不规则Button点击(二)

前言

在上一篇文章中,讲述了按钮在设置了不规则图片情况下的响应处理。

这篇文章讲述按钮不规则的另一种情况:当按钮的形状是由我们自己绘制出来的时候。

这里我们直接开始代码的编写了,关于事件传递机制可以在上一篇文章回顾一下。

关于不规则按钮的源码你们可以去JTShapedButton中查看。

按钮定义

这里创建了一个继承自UIButton的子类 IrregularButton。 并提供了三个方法供外界设置:

1
2
3
4
// 方法都返回了自身,使外界可以链式调用
func path(type: BtnType) -> IrregularButton // 设置要绘制的path
func backgroundColor(color: UIColor) -> IrregularButton // 设置背景颜色
func text(text: String) -> IrregularBtn // 设置文字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// 这里定义了一个枚举,定义了我们这个例子中按钮绘制的类型
enum BtnType {
case leftUp
case leftDown
case rightUp
case rightDown
case center
}

class IrregularButton: UIButton {

// 绘制出图形的path
private var path = UIBezierPath()

// 最终要呈现的图形
private var drawLayer = CAShapeLayer()

// 显示我们需要显示的文字
private var textLayer = CATextLayer()

override init(frame: CGRect) {
super.init(frame: frame)

// 将要显示的layer添加到自身的layer中
self.layer.addSublayer(self.drawLayer)
self.layer.addSublayer(self.textLayer)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// 外部传入的path,供我们绘制
func path(type: BtnType) -> IrregularButton {

let path = UIBezierPath()

switch type {
case .leftUp:

path.move(to: CGPoint(x: 60, y: 100))
path.addLine(to: CGPoint(x: 0, y: 100))
path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 100, startAngle: .pi, endAngle: .pi*1.5, clockwise: true)
path.addLine(to: CGPoint(x: 100, y: 60))
path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 40, startAngle: .pi*1.5, endAngle: .pi, clockwise: false)
path.close()

self.path = path

case .leftDown:
path.move(to: CGPoint(x: 60, y: 100))
path.addLine(to: CGPoint(x: 0, y: 100))
path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 100, startAngle: .pi, endAngle: .pi*0.5, clockwise: false)
path.addLine(to: CGPoint(x: 100, y: 140))
path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 40, startAngle: .pi*0.5, endAngle: .pi, clockwise: true)
path.close()

self.path = path
case .rightUp:
path.move(to: CGPoint(x: 100, y: 60))
path.addLine(to: CGPoint(x: 100, y: 0))
path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 100, startAngle: .pi*1.5, endAngle: 0, clockwise: true)
path.addLine(to: CGPoint(x: 140, y: 100))
path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 40, startAngle: 0, endAngle: .pi*1.5, clockwise: false)
path.close()

self.path = path
case .rightDown:
path.move(to: CGPoint(x: 140, y: 100))
path.addLine(to: CGPoint(x: 200, y: 100))
path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 100, startAngle: 0, endAngle: .pi*0.5, clockwise: true)
path.addLine(to: CGPoint(x: 100, y: 140))
path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 40, startAngle: .pi*0.5, endAngle: 0, clockwise: false)
path.close()

self.path = path
case .center:
path.move(to: CGPoint(x: 140, y: 100))
path.addArc(withCenter: CGPoint(x: 100, y: 100), radius: 40, startAngle: 0, endAngle: .pi*2, clockwise: true)
path.close()

self.path = path
}

self.drawLayer.path = self.path.cgPath

// 绘制完成,通知layer去刷新界面
setNeedsDisplay()

return self
}

// 设置需要显示的文字
func text(text: String) {

// 获取显示文字的size
let stringSize = text.boundingRect(with: CGSize(width:100,height:CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font:UIFont.systemFont(ofSize: 14)], context: nil).size

// 设置textLayer的位置
textLayer.frame = CGRect(x: self.path.bounds.origin.x+(self.path.bounds.size.width/2)-(stringSize.width/2), y: self.path.bounds.origin.y+(self.path.bounds.size.height/2)-(stringSize.height/2), width: stringSize.width, height: stringSize.height)

textLayer.string = NSAttributedString(string: text, attributes: [NSAttributedString.Key.foregroundColor:UIColor.black,
NSAttributedString.Key.font:UIFont.systemFont(ofSize: 14)])
textLayer.backgroundColor = UIColor.clear.cgColor

textLayer.isWrapped = false//设置是否自动换行
textLayer.contentsScale = UIScreen.main.scale//寄宿图的像素尺寸和视图大小的比例,不设置为屏幕比例文字就会像素化

setNeedsDisplay()
}

// 设置按钮的背景颜色
func backgroundColor(color: UIColor) -> IrregularButton {

self.drawLayer.fillColor = color.cgColor

setNeedsDisplay()

return self
}

// 重写此方法。判断点是否在自身path所包含的区域内。包含则返回true,代表自身处理;否则返回false。
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if self.path.contains(point) {
return true
}
return false
}
}

按钮添加

在controller界面中,创建按钮组并添加到界面上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class ViewController: UIViewController {

private let BTN_TAG = 1001

override func viewDidLoad() {
super.viewDidLoad()

let colorArr = [UIColor(red: 231/255, green: 15/255, blue: 0, alpha: 1),
UIColor(red: 237/255, green: 218/255, blue: 0, alpha: 1),
UIColor(red: 248/255, green: 160/255, blue: 0, alpha: 1),
UIColor(red: 103/255, green: 226/255, blue: 103/255, alpha: 1),
UIColor(red: 67/255, green: 196/255, blue: 242/255, alpha: 1)]

let typeArr: [BtnType] = [.leftUp, .rightUp, .leftDown, .rightDown, .center]

for index in 0..<colorArr.count {
let color = colorArr[index]
let type = typeArr[index]

let btn = IrregularBtn(frame: CGRect(x: 80, y: 100, width: 200, height: 200))

btn.path(type: type)
.backgroundColor(color: color)
.text(text: "功能\(index+1)")
.addTarget(self, action: #selector(btnClick(_:)), for: .touchUpInside)
btn.tag = BTN_TAG + index

self.view.addSubview(btn)
}
}

@objc func btnClick(_ sender: UIButton) {
var str: String
switch sender.tag {
case 1001:
str = "LeftUp Button"
case 1002:
str = "RightUp Button"
case 1003:
str = "LeftDown Button"
case 1004:
str = "RightDown Button"
default:
str = "Center Button"
}

print("current click event is \(str)")
}
}

实现效果