自定义 BarButtonItem 项:在右上角添加红点,Swift 4 IOS

Posted

技术标签:

【中文标题】自定义 BarButtonItem 项:在右上角添加红点,Swift 4 IOS【英文标题】:Custom BarButtonItem Item: Add red dot on top right corner, Swift 4 IOS 【发布时间】:2018-12-19 07:16:29 【问题描述】:

我想在UIbarButtonItem 的右上角添加/设置未读标志为红点,请参阅附图

我应该怎么做才能在条形按钮项目上添加/设置红点? 一旦用户点击项目然后我想删除红点。

【问题讨论】:

想法是创建一个徽章。试试这样的:gist.github.com/moflo/3939e6801dc9575903b05baa72365695 或者这个库正是你想要的:github.com/mikeMTOL/UIBarButtonItem-Badge 它是用 ObjC 编写的,但只需使用一个头文件,你就可以在你的 swift 项目中使用它 github.com/jkpang/PPBadgeView 【参考方案1】:

UIButton 子类

好的,让我们开始创建自定义UIButton 子类

class ButtonWithBadge: UIButton 

现在让我们创建UIView 来代表红点

let badgeView: UIView = 
    let view = UIView()
    view.layer.cornerRadius = 3
    view.backgroundColor = .red
    return view
()

然后为这个子类覆盖init并在里面添加这个badgeView到你的按钮的右上角:设置它的约束(右和上等于按钮的锚点,宽度和高度是badgeView的cornerRadius的两倍值)

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

    addSubview(badgeView)
    badgeView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        badgeView.rightAnchor.constraint(equalTo: rightAnchor, constant: 3),
        badgeView.topAnchor.constraint(equalTo: topAnchor, constant: 3),
        badgeView.heightAnchor.constraint(equalToConstant: badgeView.layer.cornerRadius*2),
        badgeView.widthAnchor.constraint(equalToConstant: badgeView.layer.cornerRadius*2)
    ])


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

接下来创建代表按钮当前状态的变量:

var isRead: Bool = false

现在让我们创建一些方法,根据isRead 的值隐藏或取消隐藏badgeView

func setBadge() 
    badgeView.isHidden = isRead

现在我们有了函数,对吧?所以让我们在init 的末尾和isRead 变量的didSet 中调用这个函数

class ButtonWithProperty: UIButton 

var isRead: Bool = false 
    didSet 
        setBadge()
    


override init(frame: CGRect) 
    ...
    setBadge()

添加到 ViewController

首先为按钮和视图创建变量

lazy var barButton: ButtonWithProperty = 
    let button = ButtonWithProperty()
    ... // set color, title, target, etc.
    return button
()

现在例如在viewDidLoad 中添加这个barButtonUINavigationBar 并按照你想要的方式放置它:

override func viewDidLoad() 
    super.viewDidLoad()
    ...
    guard let navigationBar = self.navigationController?.navigationBar else  return 

    navigationBar.addSubview(barButton)
    barButton.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        barButton.rightAnchor.constraint(equalTo: navigationBar.rightAnchor, constant: -20),
        barButton.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor, constant: -6)
    ])


现在,当您需要时,您可以轻松更改barButtonisRead 变量,红点消失或出现

barButton.isRead = true


class ButtonWithProperty: UIButton 

    var isRead: Bool = false 
        didSet 
            setBadge()
        
    

    lazy var badgeView: UIView = 
        let view = UIView()
        view.layer.cornerRadius = 3
        view.backgroundColor = .red
        return view
    ()

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

        addSubview(badgeView)
        badgeView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            badgeView.rightAnchor.constraint(equalTo: rightAnchor, constant: 3),
            badgeView.topAnchor.constraint(equalTo: topAnchor, constant: 3),
            badgeView.heightAnchor.constraint(equalToConstant: badgeView.layer.cornerRadius*2),
            badgeView.widthAnchor.constraint(equalToConstant: badgeView.layer.cornerRadius*2)
        ])

        setBadge()
    

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

    func setBadge() 
        badgeView.isHidden = isRead
    


ViewController 内部:

class ViewController: UIViewController 

    lazy var barButton: ButtonWithProperty = 
        let button = ButtonWithProperty()
        ... // color, title, target, etc.
        return button
    ()

    ...

    override func viewDidLoad() 
        super.viewDidLoad()
        ...
        guard let navigationBar = self.navigationController?.navigationBar else  return 

        navigationBar.addSubview(barButton)
        barButton.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            barButton.rightAnchor.constraint(equalTo: navigationBar.rightAnchor, constant: -20),
            barButton.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor, constant: -6)
        ])

    
    ...

【讨论】:

【参考方案2】:

我已经编写了一个自定义栏按钮类来处理这个问题,我使用CAShapeLayerUIBarButtonItem 上绘制一个点。

// Custom Bar button
class CustomBarButton: UIBarButtonItem

    // Unread Mark
    private var unreadMark: CAShapeLayer?

    // Keep track of unread status
    var hasUnread: Bool = false
    
        didSet
        
            setUnread(hasUnread: hasUnread)
        
    

    // Toggles unread status
    private func setUnread(hasUnread: Bool)
    
        if hasUnread
        
            unreadMark            = CAShapeLayer();
            unreadMark?.path      = UIBezierPath(ovalIn: CGRect(x: (self.customView?.frame.width ?? 0) - 10, y: 5, width: 5, height: 5)).cgPath;
            unreadMark?.fillColor = UIColor.red.cgColor
            self.customView?.layer.addSublayer(unreadMark!)
        
        else
        
            unreadMark?.removeFromSuperlayer()
        

    

栏按钮项没有可用的图层属性,因此您需要使用自定义视图创建UIBarButtonItem

// Bar button property
var barButton:CustomBarButton!

// Initialisation
button       = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: 70, height: 40)
button.setTitle("Right", for: .normal)
button.setTitleColor(UIColor.green, for: .normal)

// Bar button
barButton = CustomBarButton(customView: button)
button.addTarget(self, action: #selector(toggleStatus(sender:)), for: UIControl.Event.touchUpInside)

// Flexible space (Optional)
let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
toolBar.items     = [flexibleSpace, barButton]

IBAction 中,您可以使用hasUnread 属性切换状态:

@objc func toggleStatus(sender: AnyObject)

    barButton.hasUnread = !barButton.hasUnread

它看起来像:

【讨论】:

以上是关于自定义 BarButtonItem 项:在右上角添加红点,Swift 4 IOS的主要内容,如果未能解决你的问题,请参考以下文章

为啥我必须在实现自定义左 barButtonItem 之前隐藏后退按钮项?

自定义 barbuttonItem 不显示

iOS开发小技巧--获取自定义的BarButtonItem中的自定义View的方法(customView)

“导航项中不支持普通样式”警告我的自定义条形按钮项

将 BarButtonItem 旋转 45 度(动画)

IOS - Swift - 向 BarButtonItem 的 customView 添加目标和操作