iOS 自定义View
2017-04-20 本文已影响1595人
smalldu
在日常开发中,一个App会有很多模块中的小模块相差不多。这时候我们就需要考虑公用 -- 自定义View , 这样就可以避免很多重复的代码。
有哪些需要考虑的
- 首先要考虑不同的调用,纯代码的方式或者Xib 、Storyboard的方式都要可以使用
- 要有一定的可定制化 ,也就是暴露出来的属性
- 使用起来简单
实例
例如有这样的 View
在不同的地方有用到。
很简单的一个视图,图片加文字加边框。
首先,新建一个UIView
的子类ImageTextView
, 在class前面添加open
关键字 (我们要做成公用的)
删除drawRect相关方法,将下面代码复制进去
public override init(frame: CGRect) {
super.init(frame: frame)
#if !TARGET_INTERFACE_BUILDER // 非interfabuilder环境下
// 如果是从代码层面开始使用Autolayout,需要对使用的View的translatesAutoresizingMaskIntoConstraints的属性设置为false
translatesAutoresizingMaskIntoConstraints = false
#endif
prepareView()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
prepareView()
}
// 布局
func prepareView(){
}
init?(coder:)
是从Xib或者Storyboard创建的时候会调用。 其他看注释咯 - _ -
为UIImageView
添加一个扩展,方便创建UIImageView
对象
extension UIImageView {
class func configuredImageView() -> UIImageView {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFill
return imageView
}
}
回到ImageTextView
中声明图片和文本的变量
fileprivate let imageView = UIImageView.configuredImageView()
fileprivate lazy var textLabel = UILabel()
在prepareView
中对图片和文本进行布局
// 布局
func prepareView(){
textLabel.translatesAutoresizingMaskIntoConstraints = false
textLabel.font = UIFont.systemFont(ofSize: CGFloat(textSize))
addSubview(imageView)
addSubview(textLabel)
imageView.setContentCompressionResistancePriority(1000, for: .horizontal )
NSLayoutConstraint.activate([
imageView.leftAnchor.constraint(equalTo: leftAnchor, constant:10 ) ,
imageView.centerYAnchor.constraint(equalTo: centerYAnchor) ,
textLabel.leftAnchor.constraint(equalTo: imageView.rightAnchor , constant:2 ) ,
textLabel.centerYAnchor.constraint(equalTo: centerYAnchor) ,
textLabel.rightAnchor.constraint(equalTo: rightAnchor, constant:-10)
])
layer.borderColor = UIColor.lightGray.cgColor
layer.borderWidth = 0.5
layer.cornerRadius = 3
}
这里的布局方法是iOS 9 开始支持的API , 当然你也可以使用SnapKit
为了使我们的View
可以在 InterfaceBuilder
中使用,在类前面使用注解 @IBDesignable
并暴露出可以自定义的属性
extension ImageTextView{
@IBInspectable
open var image:UIImage?{
get{
return imageView.image
}
set{
imageView.image = newValue
}
}
@IBInspectable
open var text:String?{
get{
return textLabel.text
}
set{
textLabel.text = newValue ?? ""
}
}
@IBInspectable
open var textColor:UIColor? {
get{
return textLabel.textColor
}
set{
textLabel.textColor = newValue
}
}
}
在变量声明下面在加上字体大小
// 这里使用 textSize 是因为 IBInspectable 暂时还不支持 UIFont
@IBInspectable
open var textSize:UInt = 17 {
didSet{
textLabel.font = UIFont.systemFont(ofSize: CGFloat(textSize))
}
}
这块由于暂时不支持UIFont
所以使用了UInt
我们还可以在InterfaceBuilder
渲染前做一些事情
override open func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
// interface builder 渲染前执行 不会影响真正运行效果
layer.borderColor = UIColor.lightGray.cgColor
layer.borderWidth = 0.5
layer.cornerRadius = 3
}
到这里,这个自定义View
就算完成了,看下载Storyboard中的使用吧
随便拖一个UIView
修改Class属性
保存后就可以看到这些属性了
截图设置完成后 InterfaceBuilder
立刻会渲染出来
这里是我随便设了几个属性
截图有了这个自定义的View
,那么在任何地方有相似效果,我们只需要像拖UILabel
一样把他拖出来简单的设置下属性就好了(也可以通过手写代码创建)。当然,这只是一个简单的demo,并没有涉及到事件Layer以及动画等,如果有兴趣下次再讲。