简体   繁体   中英

Incorrect drawRect frame relative to UIButton frame

I am attempting to add status indicators to some UIButtons, nuzzling it right into the spot the blue indicator is in the following screenshot. I first calibrated by creating the first indicator line of code from scratch using minY and minX to use the UIButton origin as a reference point, then copied it for the other two indicators thinking it should translate but it seems it has not.

//In header/property declaration
    @IBOutlet weak var thirdButton: UIButton!
    @IBOutlet weak var secondButton: UIButton!
    @IBOutlet weak var firstButton: UIButton!

    var capicheIndicator: UIView!
    var secondIndicator: UIView!
    var thirdIndicator: UIView!

// In viewDidLoad
        let firstButtonFrame = firstButton.frame
        self.capicheIndicator = DrawBlueCircle(frame: CGRect(x: firstButtonFrame.minX + 15, y: firstButtonFrame.minY + 4, width: 11, height: 11))
        self.view.addSubview(capicheIndicator)

        let secondButtonFrame = secondButton.frame
        self.secondIndicator = DrawYellowCircle(frame: CGRect(x: secondButtonFrame.minX + 15, y: secondButtonFrame.minY + 4, width: 11, height: 11))
        self.view.addSubview(secondIndicator)

        let thirdButtonFrame = thirdButton.frame
        self.thirdIndicator = DrawRedCircle(frame: CGRect(x: thirdButtonFrame.minX + 15, y: thirdButtonFrame.minY + 4, width: 11, height: 11))
        self.view.addSubview(thirdIndicator).

This is how I draw each indicator, with the circle color fill line of code being the only change between DrawBlueCircle, DrawYellowCircle, and DrawRedCircle.

class DrawBlueCircle: UIView {

    override func drawRect(rect: CGRect)
    {
        let contextRef = UIGraphicsGetCurrentContext()

        CGContextClearRect(contextRef, rect)

        //Set the border width
        CGContextSetLineWidth(contextRef, 1.5)

        //Set the circle fil
        CGContextSetRGBFillColor(contextRef, 0/255, 122/255, 1, 1)

        CGContextFillEllipseInRect(contextRef, rect)
    }
}

However unfortunately, only the blue indicator is getting drawn correctly. 在此处输入图片说明

In my attempts to debug I printed to the console every step of the way as shown by the following code, but the code and the screen somehow do not match.

 let firstButtonFrame = firstButton.frame
    print(firstButtonFrame)
    print(firstButtonFrame.minY)
    self.capicheIndicator = DrawBlueCircle(frame: CGRect(x: firstButtonFrame.minX + 15, y: firstButtonFrame.minY + 4, width: 11, height: 11))
    print(capicheIndicator.frame)
    self.view.addSubview(capicheIndicator)

    let secondButtonFrame = secondButton.frame
    print(secondButtonFrame)
    print(secondButtonFrame.minY)
    self.secondIndicator = DrawYellowCircle(frame: CGRect(x: secondButtonFrame.minX + 15, y: secondButtonFrame.minY + 4, width: 11, height: 11))
    print(secondIndicator.frame)
    self.view.addSubview(secondIndicator)

    let thirdButtonFrame = thirdButton.frame
    print(thirdButtonFrame)
    print(thirdButtonFrame.minY)
    self.thirdIndicator = DrawRedCircle(frame: CGRect(x: thirdButtonFrame.minX + 15, y: thirdButtonFrame.minY + 4, width: 11, height: 11))
    print(thirdIndicator.frame)
    self.view.addSubview(thirdIndicator)

And the console output:

(36.0, 381.0, 528.0, 40.0)
381.0
(51.0, 385.0, 11.0, 11.0)
(36.0, 431.0, 528.0, 40.0)
431.0
(51.0, 435.0, 11.0, 11.0)
(36.0, 481.0, 528.0, 40.0)
481.0
(51.0, 485.0, 11.0, 11.0)

This is done so much more easily by subclassing UIView and adding a button. Just add the indicator as a subview. Try this in Playground:

class IndicatorButton: UIView {

    let indicatorView: UIView = {
        let indicator = UIView(frame: CGRectMake(0,0,10,10))
        indicator.layer.cornerRadius = 5.0
        indicator.clipsToBounds = true
        indicator.backgroundColor = UIColor.clearColor()
        return indicator
    }()

    var indicatorColor: UIColor = UIColor.clearColor() {
        didSet {
            indicatorView.backgroundColor = indicatorColor
            self.layer.borderColor = indicatorColor.CGColor
            self.button.setTitleColor(indicatorColor, forState: .Normal)
        }
    }

    let button: UIButton = {
        let button = UIButton(type: .Custom)
        return button
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.layer.borderWidth = 2.0
        self.layer.borderColor = indicatorColor.CGColor
        self.layer.cornerRadius = 8.0
        self.clipsToBounds = true
        button.frame = CGRectMake(0, 0, frame.size.width, frame.size.height)
        button.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
        button.titleEdgeInsets = UIEdgeInsetsMake(0,15,0,0)
        self.addSubview(button)
        self.addSubview(indicatorView)
    }

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


    override func layoutSubviews() {
        super.layoutSubviews()
        indicatorView.frame = CGRectMake(10, (self.bounds.size.height-10) / 2.0, 10,10)
    }

}

Use it like this:

let b = IndicatorButton(frame: CGRectMake(0,0,100,30))
b.indicatorColor = UIColor.redColor()
b.button.setTitle("Start", forState: .Normal)
b

Result:

按钮

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM