一、问题描述
由于项目上的银联支付接口新增了优惠码功能,需要在选择支付列表时展示配置的自定义优惠信息(例如“银联上新优惠,快来体验!”)。
参考了许多App的支付UI,最后决定模仿某团的支付UI实现,通过对左上、右上、右下角切圆角操作完成。
二、解决流程
1 cornerRadius方案(否决)
首先想到的是使用UILabel.layer.cornerRadius(Number)方法,不过刚加上后发现单独使用该方法无效,查阅相关资料后发现需搭配UILabel.layer.masksToBounds(Boolean = true)方法才能显示。该方案有在xib文件修改和代码文件修改两种实现方式,需要在调试时才能展示圆角效果。但是最终由于该方案只能对四个角同时切圆角,故否决,如有需要可选用该部分代码。
1.1 代码文件修改方式
showDiscountLabel.layer.cornerRadius = 7;
showDiscountLabel.layer.masksToBounds = true;
1.2 xib文件修改方式
⚠️注意:
在User Defined Runtime Attribute下新增这两个属性(如图)。其中layer.cornerRadius设置的类型是Number而非String,layer.masksToBounds设置的类型是Boolean并打勾。
2 贝塞尔曲线方案
通过贝塞尔曲线的方式,可以实现对部分角切圆角的样式。在方案实现之初发现存在画曲线时获取的宽度为Label根据文本自适应之前的宽度,画曲线之后Label才会根据文本长度做自适应,所以实际使用中会出现文本过长超出框范围或文本过短框展示不全的问题(前辈给的建议是自定义一个Label再重写draw方法,觉得太麻烦了就着手继续改了)。
原本想到的方法是在画曲线前先通过字体大小以及文本内容计算出宽度再赋值给width,但是方法过于繁琐,最后想到了使用sizeToFit自适应大小的方法,通过先实现宽度的自适应后再画曲线的方式成功解决。
三、代码展示
1 UI更新代码
⚠️注意:
sizeToFit自适应方法会同时自适应高度和宽度,如果项目不需要高度自适应可以先提取出height的值,在执行自适应后再重新赋值给UILabel.height即可。
private func updateUI(){
if nil != paySetting {
iconImageView.setImageURL(paySetting?.bankLogoUri);
showLabel.text = paySetting?.bankType;
showTitleLabel.text = paySetting?.title;
if paySetting?.discountStatus == 1 {
showDiscountLabel.text = " " + (paySetting?.discountDescription)! + " ";
// 使用贝塞尔曲线存在问题,画曲线时获取的宽度为自适应前的宽度,故先自适应宽度后再画曲线(保持高度不变)
let height = showDiscountLabel.height;
showDiscountLabel.sizeToFit();
showDiscountLabel.height = height;
showDiscountLabel.clipRectCorner(direction: [UIRectCorner.topLeft, UIRectCorner.topRight, UIRectCorner.bottomRight], cornerRadius: 7);
} else {
showDiscountLabel.alpha = 0;
}
}
}
2 贝塞尔曲线代码
通用代码,网上随处可见。
func clipRectCorner(direction: UIRectCorner, cornerRadius: CGFloat) {
let cornerSize = CGSize(width: cornerRadius, height: cornerRadius);
let maskPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: direction, cornerRadii: cornerSize);
let maskLayer = CAShapeLayer();
maskLayer.frame = bounds;
maskLayer.path = maskPath.cgPath;
layer.addSublayer(maskLayer);
layer.mask = maskLayer;
}