iOS - 设计具有透明背景的自定义 UITextField 的最佳方法

标签 ios swift uitextfield core-graphics uibezierpath

enter image description here

我必须创建上图中给出的文本字段。此文本字段将在 UITableViewCellUIView 中的整个应用程序中使用。最好的方法是什么?

到目前为止,我认为 UIBezierPath 是最后一个选项。

最佳答案

非常有趣的问题,我非常喜欢那个UITextField的设计,所以我在一个类中实现了它。我已经做到了@IBDesignable 和@IBInspectable

AMTitledTextField

这是代码:

//
//  AMTitledTextField.swift
//
//  Created with 💪 by Alessandro Manilii on 29/11/2018.
//  Copyright © 2018 Alessandro Manilii. All rights reserved.
//

import UIKit

@IBDesignable
class AMTitledTextField: UITextField {

    // MARK: - IBInspectables
    @IBInspectable var title: String = "" {
        didSet { self.updateTextViewBorder() }
    }

    @IBInspectable var titleColor: UIColor = UIColor.black {
        didSet { updateTextViewBorder() }
    }

    @IBInspectable var borderWidth: CGFloat = 0.0 {
        didSet { updateTextViewBorder() }
    }

    @IBInspectable var borderColor: UIColor = UIColor.clear {
        didSet { updateTextViewBorder() }
    }

    @IBInspectable var cornerRadius: CGFloat = 0.0 {
        didSet { updateTextViewBorder() }
    }

    @IBInspectable var placeholderColor: UIColor = .lightGray {
        didSet { setValue(placeholderColor, forKeyPath: "_placeholderLabel.textColor") }
    }

    // MARK: - Properties
    private var borderLayer: CAShapeLayer?
    private var sidePadding: CGFloat = 8.0
    private let verticalPadding: CGFloat = 12.0
    private var lblTitle: UILabel?

    var originNew: CGPoint {
        get { return CGPoint(x: cornerRadius + borderWidth/2, y: 0) }
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        updateTextViewBorder()
    }
}

extension AMTitledTextField {

    func updateTextViewBorder() {
        borderStyle = .none
        createTitle()
        borderLayer?.removeFromSuperlayer()
        borderLayer = nil
        borderLayer = CAShapeLayer()
        guard let borderLayer = borderLayer else { return }
        borderLayer.path = createPath().cgPath
        borderLayer.strokeColor = borderColor.cgColor
        borderLayer.fillColor = UIColor.clear.cgColor
        borderLayer.lineWidth = borderWidth
        self.layer.addSublayer(borderLayer)
    }
}

// MARK: - Rectangles Setup
extension AMTitledTextField {

    var fullSidePadding : CGFloat { return cornerRadius + sidePadding }
    var topPadding      : CGFloat { return verticalPadding/2 }
    var textPadding     : CGFloat {return sidePadding/2}

    override public func textRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.inset(by: UIEdgeInsets.init(top: topPadding,
                                                  left: fullSidePadding + textPadding,
                                                  bottom: 0,
                                                  right: fullSidePadding))
    }

    override public func editingRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.inset(by: UIEdgeInsets.init(top: topPadding,
                                                  left: fullSidePadding + textPadding,
                                                  bottom: 0,
                                                  right: fullSidePadding))
    }

    override public func placeholderRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.inset(by: UIEdgeInsets.init(top: topPadding,
                                                  left: fullSidePadding + textPadding,
                                                  bottom: 0,
                                                  right: fullSidePadding))
    }

    override public func borderRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.inset(by: UIEdgeInsets.init(top: 0,
                                                  left: fullSidePadding + textPadding,
                                                  bottom: 0,
                                                  right: fullSidePadding))
    }
}

private extension AMTitledTextField {

    func setPlaceholderColor(_ color: UIColor) {
        var placeholderText = ""
        if let placeholder = self.placeholder {
            placeholderText = placeholder
        }

        self.attributedPlaceholder = NSAttributedString(string: placeholderText, attributes: [NSAttributedString.Key.foregroundColor: color])
    }

    func createTitle() {
        lblTitle = nil
        lblTitle = UILabel(frame: CGRect(x: originNew.x, y: originNew.y, width: 25, height: 25))
        guard let lblTitle = lblTitle else { return }

        lblTitle.textAlignment = .center
        lblTitle.text = title
        lblTitle.textColor = titleColor
        lblTitle.font = font
        if let fontSize = font?.pointSize {
            lblTitle.font = lblTitle.font.withSize(fontSize * 0.85)
        }

        lblTitle.sizeToFit()
        lblTitle.frame = CGRect(x: lblTitle.frame.origin.x + sidePadding, y: lblTitle.frame.origin.y, width: lblTitle.frame.width + sidePadding, height: lblTitle.frame.height);
        addSubview(lblTitle)
    }

    func createPath() -> UIBezierPath  {
        let path = UIBezierPath()
        guard let lblTitle = lblTitle else { return path }

        let pointA = CGPoint(x: originNew.x + lblTitle.frame.width + sidePadding, y: lblTitle.center.y)
        let pointB = CGPoint(x: frame.width - cornerRadius - borderWidth/2, y: pointA.y)
        let centerUR = CGPoint(x: pointB.x, y: pointA.y + cornerRadius)
        let pointC = CGPoint(x: frame.width - borderWidth/2, y: frame.height - cornerRadius - borderWidth/2)
        let centerBR = CGPoint(x: centerUR.x, y: frame.height - cornerRadius - borderWidth/2)
        let pointD = CGPoint(x: cornerRadius + borderWidth/2, y: frame.height - borderWidth/2)
        let centerBL = CGPoint(x: pointD.x, y: centerBR.y)
        let pointE = CGPoint(x: borderWidth/2, y: centerUR.y)
        let centerUL = CGPoint(x: centerBL.x, y: centerUR.y)
        let pointF = CGPoint(x: pointD.x + sidePadding, y: pointA.y)

        path.move(to: pointA)
        path.addLine(to: pointB)
        path.addArc(withCenter: centerUR, radius: cornerRadius, startAngle: CGFloat(3 * Double.pi/2), endAngle: 0, clockwise: true)
        path.addLine(to: pointC)
        path.addArc(withCenter: centerBR, radius: cornerRadius, startAngle: 0, endAngle: CGFloat(Double.pi/2), clockwise: true)
        path.addLine(to: pointD)
        path.addArc(withCenter: centerBL, radius: cornerRadius, startAngle: CGFloat(Double.pi/2), endAngle: CGFloat(2 * Double.pi/2), clockwise: true)
        path.addLine(to: pointE)
        path.addArc(withCenter: centerUL, radius: cornerRadius, startAngle:  CGFloat(2 * Double.pi/2), endAngle:  CGFloat(3 * Double.pi/2), clockwise: true)
        path.addLine(to: pointF)

        return path
    }
}

关于iOS - 设计具有透明背景的自定义 UITextField 的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53540487/

相关文章:

ios - NSPredicate 按时间间隔获取日期

ios - 如何将可访问性集中在 UISegmentedControl 中的特定部分

ios - iOS 中的线程通信?

ios - 下一步按钮将焦点带到下一个 UITextField?

ios - [UITextField 保留] : message sent to deallocated instance

ios - 以编程方式确定 iPad 模态视图的大小

ios - GMSAutocompleteViewController 想要在搜索点击时获取搜索栏中的文本

ios - 在 imageview 中快速调整图像大小

ios - segue 快速获得 twise 调用

ios - 为什么文本框的边缘会被剪掉?