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

时间:2018-11-29 13:46:21

标签: ios swift uitextfield core-graphics uibezierpath

enter image description here

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

到目前为止,我认为UIBezierPath是最后的选择。

1 个答案:

答案 0 :(得分:0)

一个非常有趣的问题,我真的很喜欢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
    }
}