31

I am trying to create a custom UIButton which extends from UIButtonType.RoundedRect.

My added functionality is working, but there is an issue with the initial rounded border state of my button. The border of my extended button is not drawn until after it has been tapped.

Before-After Screenshot

Update (January 24th 2013): Added the result of red background test, as requested by Richard Marskell, which concludes only the label of the button is drawn. BackgroundColor = UIColor.Red;

Red Background Test, Before-After Screenshot

Below is my source code for creating my custom button.

public class TestView : UIView
{
    public TestView(IntPtr p) : base(p) { }

    public TestView(RectangleF bounds)
    {
        Frame = bounds;
        BackgroundColor = UIColor.White;

        UIButton button1 = new UIButton(UIButtonType.RoundedRect);
        button1.Frame = new RectangleF(20,20,100,50);
        button1.SetTitle("Button 1", UIControlState.Normal);
        AddSubview(button1); // Drawn Correctly

        MyButton button2 = new MyButton();
        button2.Frame = new RectangleF(20,90,100,50);
        button2.SetTitle("Button 2", UIControlState.Normal);
        AddSubview(button2); // Only drawn correctly after Tap

        // EDIT: Added to test Miguel's theory
        UIButton button3 = UIButton.FromType(UIButtonType.RoundedRect);
        button3.Frame = new RectangleF(20,160,100,50);
        button3.SetTitle("Button 3", UIControlState.Normal);
        AddSubview(button3); // Drawn Correctly
    }
}

public class MyButton : UIButton
{
    public MyButton() : base(UIButtonType.RoundedRect) { }
}
  • I'm just not sure how to force the border to be drawn correctly on loading of the view.
  • I don't need a button of type UIButtonType.Custom, as I don't want to style the button myself.
  • When I debug I the type of MyButton is correctly set to UIButtonType.RoundedRect.
  • The UIButton base properties of MyButton (button2) match the properties of the UIButton instance (button1).

Debug

How can I resolve this issue?


Update (January 31st 2013): Herman Schoenfeld provided a suitable solution for this bug.

Scott
  • 21,211
  • 8
  • 65
  • 72
  • 6
    +1 for a well formatted question. – MarioDS Dec 29 '12 at 11:59
  • Can you try UIButton.FromXXX method to create the button instead of the constructor? Just to try out a theory – miguel.de.icaza Dec 30 '12 at 16:18
  • @miguel.de.icaza Thanks for looking into this. I have tried creating a UIButton using the `UIButton.FromType` method, and it is drawn correctly. I am not sure how I am supposed to use this method of create an instance of MyButton using this method. – Scott Dec 30 '12 at 19:48
  • 1
    A factory class cannot be inherited from. That said, it is strange that a public constructor is provided for a factory class such as this. There is nothing from your code that would lead one to believe that the behavior of the factory method would differ from that of the constructor with the `UIButtonType` parameter. – ardila Jan 07 '13 at 16:04
  • @aardila Thanks for the clarification about the Factory class. Yeah it does seem odd. – Scott Jan 08 '13 at 15:16
  • Does the same thing happen if you create both buttons in the same way, either both through the base class or both through the custom one? Perhaps the custom class issue is a red herring. – Stephen Hewlett Jan 13 '13 at 00:36
  • @StephenHewlett I am not sure entirely what you mean by "create both buttons in the same way". Can you provide code for what you mean or elaborate on your approach please, then I can try it out? Thanks. – Scott Jan 13 '13 at 08:58
  • Try replacing `MyButton button2 = new MyButton();` with `UIButton button2 = new UIButton(UIButtonType.RoundedRect);` and vice versa, to see if the buttons still display properly. – Stephen Hewlett Jan 13 '13 at 10:46
  • @StephenHewlett I see what you are saying now. I tried this test before posting to SO. Changing the second button as `UIButton(UIButtonType.RoundedRect)` is drawn correctly, and setting button1 as `MyButton` is not drawn correctly. Same issue. – Scott Jan 13 '13 at 11:04
  • Out of curiosity, does changing `BackgroundColor = UIColor.White;` to something like red give any indication of, say, a white border or weird draw bounds? – Richard Marskell - Drackir Jan 23 '13 at 23:23
  • @RichardMarskell-Drackir thanks for the suggestion. Only the label is drawn. I have updated the question to include a screenshot of the outcome. – Scott Jan 24 '13 at 08:44

1 Answers1

7

This works

public class MyButton : UIButton
{
    public MyButton() : base(UIButtonType.RoundedRect) { }


    public override RectangleF Frame {
        get {
            return base.Frame;
        }
        set {
            var temp = TranslatesAutoresizingMaskIntoConstraints;
            TranslatesAutoresizingMaskIntoConstraints = false;
            var constraints = new [] {
                NSLayoutConstraint.Create(this, NSLayoutAttribute.Width, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1.0f, value.Width),
                NSLayoutConstraint.Create(this, NSLayoutAttribute.Height, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1.0f, value.Height)
            };
            AddConstraints(constraints);
            SizeToFit();
            RemoveConstraints(constraints);
            base.Frame = value;
            TranslatesAutoresizingMaskIntoConstraints = temp;
        }
    }
}

This is only a workaround, it appears to be a bug. The SizeToFit() fixes the issue, the other code maintains the frame.

Herman Schoenfeld
  • 8,464
  • 4
  • 38
  • 49