ios - iOS - 设计具有透明背景的自定义 UITextField 的最佳方法
问题描述
我必须创建上图中给出的文本字段。此文本字段将在 和 内的整个应用程序中UITableViewCell
使用UIView
。什么可能是最好的方法?
到目前为止,我认为UIBezierPath
是最后一个选择。
解决方案
非常有趣的问题,我真的很喜欢那个 UITextField 的设计,所以我在一个类中实现了它。我已经完成了所有@IBDesignable 和@IBInspectable
那是代码:
//
// 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
}
}
推荐阅读
- javascript - 如何连接具有相同ID的对象值
- codeigniter - 防止在数据库 Codeigniter 中重复输入
- javascript - 如何在 Scroll 上为 Div 设置动画
- x11 - 在 XCB 中将窗口固定到窗口堆栈的顶部
- c# - 使用 Razor Pages 向控制器或页面模型发出 AJAX 请求
- c# - 将数据从数据表显示到数据网格时出现 System.outofmemoryexception
- oracle - Oracle DBMS_LOB 到 Postgres 的转换
- python-2.7 - 如何使用机器人框架通过 Autoit lib 启动外部应用程序
- android - WebView:如何在 8.0 WebView 中加载 .php 文件
- sql - 在 SQL Server 中应用舍入后的值计算错误