在一个页面里有时会突出显示一个功能的项,比如充值卡打折、购物优惠等。有一种方式就是在按钮的右上角加一个“红色飘带”,然后在飘带上加提示文字,如下图:
![](https://img.haomeiwen.com/i13180946/b48aae5fda95d28b.png)
1. 思路
为了让这个角标控件除了在按钮之外,也可以在其他视图上使用,我们把它封装到一个单独的view上。有同学可能想在这个view的drawRect方法中直接画出这个“红色飘带”及白色文字,但是这样在绘制规则图形时比较容易,在绘制文字时需要调整角度,有些难度。这里我们采用普通方式,“红色飘带”作为一个contentView,调整其transform旋转角度,在将一个label放在contentView剧中位置。
2. 实现代码
ScriptLabelView 是这个单独的角标控件,具体代码如下:
import UIKit
class ScriptLabelView: UIView {
var scriptHeight: CGFloat = 30.0
var contentView: UIView = UIView.init()
private var scriptLabel: UILabel = UILabel.init()
var roateMatrix: CGAffineTransform = CGAffineTransform.identity
override init(frame: CGRect) {
super.init(frame: frame)
self.isUserInteractionEnabled = false
self.backgroundColor = UIColor.clear
self.clipsToBounds = true
contentView = UIView.init()
contentView.backgroundColor = UIColor.red
self.addSubview(contentView)
contentView.layer.borderColor = UIColor.green.cgColor
contentView.layer.borderWidth = 1.0
scriptLabel = UILabel.init()
scriptLabel.backgroundColor = UIColor.clear
scriptLabel.font = UIFont.systemFont(ofSize: 12)
scriptLabel.adjustsFontSizeToFitWidth = true
scriptLabel.textColor = UIColor.white
scriptLabel.textAlignment = .center
contentView.addSubview(scriptLabel)
scriptLabel.layer.borderColor = UIColor.yellow.cgColor
scriptLabel.layer.borderWidth = 1.0
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
let size = self.frame.size
let offset = sin(.pi / 4.0) * scriptHeight / 2.0
let contentViewWidth = sqrt(2.0 * size.width * size.height)
contentView.bounds = CGRect.init(x: 0, y: 0, width: contentViewWidth, height: scriptHeight)
print("---->> \(contentView.frame)")
contentView.center = CGPoint.init(x: size.width / 2.0 + offset, y: size.height / 2.0 - offset)
contentView.transform = CGAffineTransform.init(rotationAngle: .pi / 4.0)
scriptLabel.frame = CGRect.init(x: scriptHeight, y: 0, width: contentViewWidth - scriptHeight * 2.0, height: scriptHeight)
}
func setScriptText(text: String) {
if text.lengthOfBytes(using: .utf8) > 0 {
self.isHidden = false
scriptLabel.text = text
}
else {
self.isHidden = true
}
}
func setScriptBackColor(backColor: UIColor, textColor: UIColor) {
contentView.backgroundColor = backColor
scriptLabel.textColor = textColor
}
}
SuperscriptButton 继承余UIButton,其右上角使用了上面的角标控件,具体代码如下:
import UIKit
class SuperscriptButton: UIButton {
var scriptView = ScriptLabelView.init()
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(scriptView)
scriptView.layer.borderColor = UIColor.blue.cgColor
scriptView.layer.borderWidth = 2.0
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
let size = self.frame.size
let scriptWidth:CGFloat = 100.0 // 要求是一个正方形
scriptView.frame = CGRect.init(x: size.width - scriptWidth, y: 0, width: scriptWidth, height: scriptWidth)
}
func setScriptText(text: String) {
scriptView.setScriptText(text: text)
}
}
3. 关于 view 的 frame 与 bounds
-
frame
frame为该view在父view坐标系中的位置和大小,参考其父view的坐标系。 -
bounds
该view在本地坐标系统中的位置和大小,它的参考坐标系是自身的坐标系,原点始终为(0,0)。
详细区别请参考文章:https://www.jianshu.com/p/964313cfbdaa。
本例中子视图的尺寸都在layoutSubviews这个方法中来调整,需要引起注意的是在ScriptLabelView中一开始代码是下面这样的:
contentView.frame = CGRect.init(x: 0, y: 0, width: contentViewWidth, height: scriptHeight)
contentView.center = CGPoint.init(x: size.width / 2.0 + offset, y: size.height / 2.0 - offset)
contentView.transform = CGAffineTransform.init(rotationAngle: .pi / 4.0)
第一行中用的是contentView.frame,但是在显示的时候,contentView的形状发生了变化,并不是我们想设置的效果。原因是在设置这个视图transform属性时,这个视图的frame会发生变化,而且layoutSubviews 会被多次调用,影响了contentView的显示。官方文档有介绍:
![](https://img.haomeiwen.com/i13180946/8dc693f391123600.png)
因此,我们把contentView.frame改为contentView.bounds。
本文中角标控件强制为一个正方形,你也可以花点时间把它改造成矩形。
网友评论