web-dev-qa-db-ja.com

SwiftナビゲーションbarButtonItemおよびUIButtonにバッジを追加

AppIconに表示されるアプリで、通知ボタンにバッジを表示しようとしています。

これまでのところ、私が研究したものは何でもObjに関連しています。 C、ただし、そのソリューションをSwiftに実装する方法を具体的に説明したものは何もありません。

UiBarbuttonとUiButtonでバッジを達成するためのカスタムクラス/コードを追加するソリューションを見つけるのを手伝ってください。

これまでの研究:

https://github.com/Marxon13/M13BadgeView

mKBadgeクラスなどとともに.

14
coolagrwal

UIButtonItemの拡張機能を備えたよりエレガントなソリューションがあります

extension CAShapeLayer {
    func drawCircleAtLocation(location: CGPoint, withRadius radius: CGFloat, andColor color: UIColor, filled: Bool) {
        fillColor = filled ? color.cgColor : UIColor.white.cgColor
        strokeColor = color.cgColor
        let Origin = CGPoint(x: location.x - radius, y: location.y - radius)
        path = UIBezierPath(ovalIn: CGRect(Origin: Origin, size: CGSize(width: radius * 2, height: radius * 2))).cgPath
    }
}

private var handle: UInt8 = 0

extension UIBarButtonItem {
    private var badgeLayer: CAShapeLayer? {
        if let b: AnyObject = objc_getAssociatedObject(self, &handle) as AnyObject? {
            return b as? CAShapeLayer
        } else {
            return nil
        }
    }

    func addBadge(number: Int, withOffset offset: CGPoint = CGPoint.zero, andColor color: UIColor = UIColor.red, andFilled filled: Bool = true) {
        guard let view = self.value(forKey: "view") as? UIView else { return }

        badgeLayer?.removeFromSuperlayer()

        // Initialize Badge
        let badge = CAShapeLayer()
        let radius = CGFloat(7)
        let location = CGPoint(x: view.frame.width - (radius + offset.x), y: (radius + offset.y))
        badge.drawCircleAtLocation(location: location, withRadius: radius, andColor: color, filled: filled)
        view.layer.addSublayer(badge)

        // Initialiaze Badge's label
        let label = CATextLayer()
        label.string = "\(number)"
        label.alignmentMode = kCAAlignmentCenter
        label.fontSize = 11
        label.frame = CGRect(Origin: CGPoint(x: location.x - 4, y: offset.y), size: CGSize(width: 8, height: 16))
        label.foregroundColor = filled ? UIColor.white.cgColor : color.cgColor
        label.backgroundColor = UIColor.clear.cgColor
        label.contentsScale = UIScreen.main.scale
        badge.addSublayer(label)

        // Save Badge as UIBarButtonItem property
        objc_setAssociatedObject(self, &handle, badge, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }

    func updateBadge(number: Int) {
        if let text = badgeLayer?.sublayers?.filter({ $0 is CATextLayer }).first as? CATextLayer {
            text.string = "\(number)"
        }
    }

    func removeBadge() {
        badgeLayer?.removeFromSuperlayer()
    }
}

このすばらしいコードはStefano Vettorによって作成されたもので、すべての詳細は次の場所にあります。 https://Gist.github.com/freedom27/c709923b163e26405f62b799437243f4

13
Julio Bailon

ワーキングソリューション:

ステップ1:まず、次のように、UIButtonのサブクラスである新しいSwiftファイルを作成します:

import UIKit

class BadgeButton: UIButton {

    var badgeLabel = UILabel()

    var badge: String? {
        didSet {
            addbadgetobutton(badge: badge)
        }
    }

    public var badgeBackgroundColor = UIColor.red {
        didSet {
            badgeLabel.backgroundColor = badgeBackgroundColor
        }
    }

    public var badgeTextColor = UIColor.white {
        didSet {
            badgeLabel.textColor = badgeTextColor
        }
    }

    public var badgeFont = UIFont.systemFont(ofSize: 12.0) {
        didSet {
            badgeLabel.font = badgeFont
        }
    }

    public var badgeEdgeInsets: UIEdgeInsets? {
        didSet {
            addbadgetobutton(badge: badge)
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        addbadgetobutton(badge: nil)
    }

    func addbadgetobutton(badge: String?) {
        badgeLabel.text = badge
        badgeLabel.textColor = badgeTextColor
        badgeLabel.backgroundColor = badgeBackgroundColor
        badgeLabel.font = badgeFont
        badgeLabel.sizeToFit()
        badgeLabel.textAlignment = .center
        let badgeSize = badgeLabel.frame.size

        let height = max(18, Double(badgeSize.height) + 5.0)
        let width = max(height, Double(badgeSize.width) + 10.0)

        var vertical: Double?, horizontal: Double?
        if let badgeInset = self.badgeEdgeInsets {
            vertical = Double(badgeInset.top) - Double(badgeInset.bottom)
            horizontal = Double(badgeInset.left) - Double(badgeInset.right)

            let x = (Double(bounds.size.width) - 10 + horizontal!)
            let y = -(Double(badgeSize.height) / 2) - 10 + vertical!
            badgeLabel.frame = CGRect(x: x, y: y, width: width, height: height)
        } else {
            let x = self.frame.width - CGFloat((width / 2.0))
            let y = CGFloat(-(height / 2.0))
            badgeLabel.frame = CGRect(x: x, y: y, width: CGFloat(width), height: CGFloat(height))
        }

        badgeLabel.layer.cornerRadius = badgeLabel.frame.height/2
        badgeLabel.layer.masksToBounds = true
        addSubview(badgeLabel)
        badgeLabel.isHidden = badge != nil ? false : true
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.addbadgetobutton(badge: nil)
        fatalError("init(coder:) is not implemented")
    }
}

ステップ2:各View Controllerで使用できる関数をベースファイルに作成します:

  func addBadge(itemvalue: String) {

        let bagButton = BadgeButton()
        bagButton.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
        bagButton.tintColor = UIColor.darkGray
        bagButton.setImage(UIImage(named: "ShoppingBag")?.withRenderingMode(.alwaysTemplate), for: .normal)
        bagButton.badgeEdgeInsets = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 15)
        bagButton.badge = itemvalue
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: bagButton)
    }

ステップ3:この方法で任意のView Controllerから上記の機能を使用します:

self.addBadge(itemvalue: localStorage.string(forKey: "total_products_in_cart") ?? "0")
12
Shivam Tripathi

m13BadgeViewを使用します。このコードを使用します

(ボタンにfontawesome.Swiftを使用しているIM :: https://github.com/thii/FontAwesome.Swift

    let rightButton = UIButton(frame: CGRect(x:0,y:0,width:30,height:30))
    rightButton.titleLabel?.font = UIFont.fontAwesome(ofSize: 22)
    rightButton.setTitle(String.fontAwesomeIcon(name: .shoppingBasket), for: .normal)

    let rightButtonItem : UIBarButtonItem = UIBarButtonItem(customView: rightButton)

    let badgeView = M13BadgeView()
        badgeView.text = "1"
        badgeView.textColor = UIColor.white
        badgeView.badgeBackgroundColor = UIColor.red
        badgeView.borderWidth = 1.0
        badgeView.borderColor = UIColor.white
        badgeView.horizontalAlignment = M13BadgeViewHorizontalAlignmentLeft
        badgeView.verticalAlignment = M13BadgeViewVerticalAlignmentTop
        badgeView.hidesWhenZero = true

    rightButton.addSubview(badgeView)

    self.navigationItem.rightBarButtonItem = rightButtonItem
2
keithics

良い回答@Julio Bailon( https://stackoverflow.com/a/45948819/189897 )!

以下に著者のサイトに完全な説明があります: http://www.stefanovettor.com/2016/04/30/adding-badge-uibarbuttonitem/

IOS 11では動作していないようです。おそらく、スクリプトがUIBarButtonItemの「view」プロパティにアクセスしようとするためです。私はそれを機能させました:

  1. UIButtonを作成してから、UIBarButtonItemをcustomViewとして使用してUIButtonを作成します。

    navigationItem.rightBarButtonItem = UIBarButtonItem.init(
            customView: shoppingCartButton)
    
  2. UIBarButtonItem拡張子の行を置き換えることにより:

    guard let view = self.value(forKey: "view") as? UIView else { return }
    

    次のように:

    guard let view = self.customView else { return }
    

私にはエレガントなようで、何よりもうまくいきました!

1
Leandro

UILabelに関してUIButtonに以下の制約を設定できます

UILabelの上部と末尾をUIButtonに揃えます

そして、バッジを表示する必要がある場合は、テキストをUILabelに設定し、バッジを表示したくない場合は、空の文字列をUILabelに設定します

1
Sayali Shinde

同じ仕事をしました。サードパーティのライブラリを使用したくありませんでした。まず、 Stefanoのソリューション を試しましたが、それは素晴らしいことですが、それを解決するために独自の方法を実装することにしました。

私の謙虚な意見では、以下に簡単に説明する簡単な手順があります:

  1. .xibファイル内にUIViewインスタンスを作成し、設計要件に応じてUILabelまたはUIImageViewインスタンスなどの必要なアイテムを配置します。 enter image description here

このステップで行った最後のアクションは、非表示ボタンをビューの階層の最上部に配置することです。

enter image description here

  1. YourCustomView.Swiftを作成し、xibからすべての@IBOutletsをカスタムビュークラス実装内の現在のファイルにリンクします。

enter image description here

  1. 次に、YourCustomViewクラスにクラス関数を実装します。これは、xibからカスタムビューを読み込み、YourCustomViewインスタンスとして返します。

enter image description here

  1. 最後に、カスタムバッジをカスタムView Controllerインスタンスに追加します。

enter image description here

私の結果は..

enter image description here

P.S。@IBActionsを実装する必要がある場合は、デリゲートパターンを介してカスタムビューとカスタムビューコントローラをリンクすることをお勧めします。

1
Ivan Shokurov

これをダウンロード

ForBarButtonItem:ドラッグアンドドロップUIBarButtonItem + Badge.hおよびUIBarButtonItem + Badge.mプロジェクトのクラス。

セットバッジ用にこのコードを記述します。

self.navigationItem.rightBarButtonItem.badgeValue = "2"
self.navigationItem.rightBarButtonItem.badgeBGColor = UIColor.black

UIButtton:ドラッグアンドドロップUIButton + Badge.hおよびUIButton + Badge.mプロジェクトのクラス。

self.notificationBtn.badgeValue = "2"
self.notificationBtn.badgeBGColor = UIColor.black
0
Deep