iosswiftbuttonbadgezposition

Badge is displayed behind UIButton


I've created a custom class that adds a badge to a UIButton. The badge itself is a UIImageView. The button can have a different UI for each state; when the button is disabled it has a clear background, it shows a border and the title, as shown in the image below.

enter image description here

As you can see the badge is displayed behind the border, but I want to badge to be on top of it. I have tried to adjust the zPosition of the layer of the badge by setting it to e.g. 9999. I also tried to bring the badge to the front by using the bringSubviewToFront method. Both ways did not work. My code to add the badge to the button is this:

private func addBadgeImageToButton() {
    // badgeImage is a string containing the imageName
    guard badgeImage != nil else {
        return
    }

    badgeImageView = UIImageView(image: UIImage(named: badgeImage!))

    // This line merely adjusts the position of the UIImageView
    badgeImageView!.frame = adjustedRectangleForBadge(initialSize: badgeImageView!.frame.size)

    badgeImageView!.layer.zPosition = 9999
    addSubview(badgeImageView!)

    // This line does not seem to work
    //self.bringSubviewToFront(badgeImageView!)

    // Adding these two lines won't do the trick either
    self.setNeedsLayout()
    self.layoutIfNeeded()
}

Can anyone help me with this tiny problem? Any help is greatly appreciated!


Solution

  • This is expected behavior. The border is supposed to always be on top of all subviews. You can get the desired effect by instead adding a UIView with a border on to the UIButton and then adding the icon after it.

    let borderView = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
    borderView.layer.cornerRadius = self.layer.cornerRadius
    borderView.layer.borderColor = self.layer.borderColor
    
    // Remove the border color from the button its self
    self.layer.borderColor = UIColor.clear.cgColor
    
    // Add the border view to fake the border being there
    addSubview(borderView)
    
    // Then add the imageView on top of that border view
    addSubview(badgeImageView)