需求描述
HelloSlide是把文本自动转化成幻灯片的软件,在幻灯片中我们有SmartArt:各种各样的几何形状,并且可以自定义大小和颜色,放在幻灯片不同的位置。
为了在我们的软件中实现类似的效果,我封装了一些自定义的组件,因为暂时只需要几何形状,我通过直接继承UIView来实现
代码
class ArcView:UIView{ var mystrokecolor:UIColor //设置笔触颜色 var color : UIColor //设置填充颜色 init(frame:CGRect,color:UIColor,strokecolor:UIColor){ self.mystrokecolor = strokecolor self.color = color super.init(frame:frame) self.backgroundColor = UIColor.clear //要将背景色设置为透明 } required init(coder acoder:NSCoder) { fatalError("some error in Xcode") } override func draw(_ rect: CGRect){ super.draw(rect) guard let context = UIGraphicsGetCurrentContext() else{ return } let path = CGMutablePath() path.move(to: CGPoint(x:self.bounds.minX,y:self.bounds.minY)) //设置起点 path.addLine(to: CGPoint(x:self.bounds.maxX,y:self.bounds.minY)) path.addLine(to: CGPoint(x:self.bounds.maxX,y:self.bounds.maxY)) path.addLine(to: CGPoint(x:self.bounds.minX,y:self.bounds.maxY)) path.addLine(to: CGPoint(x:self.bounds.minX,y:self.bounds.minY))
//完成path的绘制 //path.addRect(T##rect: CGRect##CGRect) context.addPath(path)
// 设置笔触样式 context.setStrokeColor(mystrokecolor.cgColor) context.setLineWidth(6) context.setFillColor(color.cgColor) context.strokePath() } }
解释
1 用的Core Graphics框架。Core Graphics提供CGMutablePath的底层API,而UIBezierPath事实上是对CGMutablePath的封装
2 我们使用的 UIKit 库中所有 UI 组件其实都是由 CoreGraphics 绘制实现的。所以使用 Core Graphics 可以实现比 UIKit 更底层的功能。
3 我们开放了两个属性:笔触颜色和填充颜色,用来自定义颜色;其他的如空间大小等可以直接继承自UIView中的属性
深度需求探索
如果我们希望把这个组件放到Storyboard上面,需要做一点调整
@IBDesignable:用来标识自定义组件类,这样在StoryBoard中就能能实时更新视图。
@IBInspectable:用来标识属性,这样在Attribute Inspector(属性检查器)中查看设置该属性。
代码
class ArcView:UIView{ var mystrokecolor:UIColor
//设置笔触颜色 var color : UIColor //设置填充颜色 init(frame:CGRect,color:UIColor,strokecolor:UIColor){ self.mystrokecolor = strokecolor self.color = color super.init(frame:frame) self.backgroundColor = UIColor.clear //要将背景色设置为透明 } required init(coder acoder:NSCoder) { fatalError("some error in Xcode") } override func draw(_ rect: CGRect){ super.draw(rect) guard let context = UIGraphicsGetCurrentContext() else{ return } let path = CGMutablePath() path.move(to: CGPoint(x:self.bounds.minX,y:self.bounds.minY)) //设置起点 path.addLine(to: CGPoint(x:self.bounds.maxX,y:self.bounds.minY)) path.addLine(to: CGPoint(x:self.bounds.maxX,y:self.bounds.maxY)) path.addLine(to: CGPoint(x:self.bounds.minX,y:self.bounds.maxY)) path.addLine(to: CGPoint(x:self.bounds.minX,y:self.bounds.minY)) //完成path的绘制 //path.addRect(T##rect: CGRect##CGRect) context.addPath(path) // 设置笔触样式 context.setStrokeColor(mystrokecolor.cgColor) context.setLineWidth(6) context.setFillColor(color.cgColor) context.strokePath() } }
// 把上述这个view放到一个IBDesignable类型的class中去
@IBDesignable class myview : UIView{
private var thisview : ArcView()
@IBInspectable var strokecolor : UIColor = .white{
didSet{
self.thisview.strokeColor = strokecolor;
}
}
另外
但是如果组件里的元素比较多,布局比较复杂。那用纯代码写就比较麻烦了。对于这种复杂的自定义组件,我们可以结合 XIB 文件来实现。
使用XIB的方式可以省去
initWithFrame:
和
layoutSubviews
中添加子控件和设置子控件尺寸的步骤,还有在view controller里面设置view的frame,因为添加子控件和设置子控件的尺寸以及整个view的尺寸在xib中就已经完成。(注意整个view的位置还没有设置,需要在controller里面设置。)
参考:https://www.hangge.com/blog/cache/detail_1394.html
https://www.jianshu.com/p/7e47da62899c