1

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!

Nordeast
  • 1,353
  • 13
  • 21
Raoul
  • 101
  • 9

2 Answers2

0

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)
Nordeast
  • 1,353
  • 13
  • 21
  • Most important here is that the borders are always on top of the subviews. This should work; I haven't tested it myself. Another approach would be to have an image for the background and indicate the slicing. See https://stackoverflow.com/questions/12623961/stretch-background-image-for-uibutton for an example. – Raoul Nov 13 '18 at 10:05
  • You can do it with an images too, but for your case here I think that is more work than just adding another `UIView` on the button. Doing it with a `UIView` has the added benefit of scaling to all devices and will produce a more sharp looking result. In that link it would probably be just as easy to add a `CAGradientLayer` to the button instead of stretching an image. – Nordeast Nov 13 '18 at 14:49
0

Try putting your badge image after (below) the button in your xml.

Guilherme Oliveira
  • 916
  • 1
  • 11
  • 21