美文网首页
Swift 实现一个角标按钮

Swift 实现一个角标按钮

作者: 大成小栈 | 来源:发表于2020-03-18 17:15 被阅读0次

在一个页面里有时会突出显示一个功能的项,比如充值卡打折、购物优惠等。有一种方式就是在按钮的右上角加一个“红色飘带”,然后在飘带上加提示文字,如下图:

角标按钮

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的显示。官方文档有介绍:

因此,我们把contentView.frame改为contentView.bounds。
本文中角标控件强制为一个正方形,你也可以花点时间把它改造成矩形。

相关文章

网友评论

      本文标题:Swift 实现一个角标按钮

      本文链接:https://www.haomeiwen.com/subject/xbtcyhtx.html