如何在 UIButton 子类中覆盖 -drawrect?

Posted

技术标签:

【中文标题】如何在 UIButton 子类中覆盖 -drawrect?【英文标题】:How to override -drawrect in UIButton subclass? 【发布时间】:2009-05-03 00:51:50 【问题描述】:

嗨。我需要在自定义按钮上写一些文本。所以我继承了 UIButton。在-drawrect中,我写我需要的文本。问题是文本最终位于按钮下方。在我写完我的文字后,UIButton 的 drawrect 会继续并在我的上方绘制。

我什至没有调用 [super drawrect: rect],尽管我在绘制之前就已经预料到会调用它。似乎 UIButton 的 drawrect 无论如何都会被调用。

有什么想法吗?谢谢。

【问题讨论】:

【参考方案1】:

正如其他人所说,您不需要继承 UIButton - 事实上最好不要,因为 UIButton 非常复杂(正如您发现的那样)。您有三个选择:

将按钮的标题留空,然后在按钮的所需位置添加一个新的文本字段。 如果您使用的是 3.0,请访问按钮的标签属性。虽然标签本身是只读的,但它的属性(包括框架)不是。 子类 UIControl。 UIControl 是一个 UIView,因此您可以添加其他视图 - 文本和图像,它是实现操作消息行为的 UIView (addTarget:action:forControlEvents:)。 UIButton 在此之上实现了状态性。

如果您不需要 UIButton 的 setTitle:forState: 和相关功能之类的东西,但您使用了很多这样的控件,我会使用第三个选项。否则使用第一个(如果您使用的是 3.0,则使用第二个)。

【讨论】:

【参考方案2】:

这对我很有效...(忽略复杂的绘图代码)。

    创建 UIButton 的子类 在 StoryBoard 中创建一个 UIButton 转到身份检查器并输入您的自定义名称 按钮类

这里是我的 UIButton 代码:

h 文件:

#import <UIKit/UIKit.h>

@interface DoneButton : UIButton

@property (assign, nonatomic) BOOL selected;

@end

m 文件:

 #import "DoneButton.h"

    @implementation DoneButton

    @synthesize selected = _selected;

    - (id)initWithFrame:(CGRect)frame
    
        self = [super initWithFrame:frame];
        if (self) 
            // Initialization code
        
        return self;
    

    - (void)setSelected:(BOOL)selected
    
        if (_selected != selected) 
            _selected = selected;
            [self setNeedsDisplay];
        
    


    - (void)drawRect:(CGRect)rect
    
        // Drawing code

        if (_selected) 
            //// Color Declarations
            UIColor* color2 = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 1];

            //// Bezier Drawing
            UIBezierPath* bezierPath = [UIBezierPath bezierPath];
            [bezierPath moveToPoint: CGPointMake(49.39, 31.25)];
            [bezierPath addLineToPoint: CGPointMake(49.39, 31.25)];
            [bezierPath addCurveToPoint: CGPointMake(46.64, 25.19) controlPoint1: CGPointMake(49.39, 29.02) controlPoint2: CGPointMake(48.38, 26.94)];
            [bezierPath addCurveToPoint: CGPointMake(44.3, 18.95) controlPoint1: CGPointMake(46.63, 22.72) controlPoint2: CGPointMake(45.88, 20.53)];
            [bezierPath addCurveToPoint: CGPointMake(42.44, 17.59) controlPoint1: CGPointMake(43.75, 18.4) controlPoint2: CGPointMake(43.13, 17.95)];
            [bezierPath addCurveToPoint: CGPointMake(38.07, 16.61) controlPoint1: CGPointMake(41.17, 16.93) controlPoint2: CGPointMake(39.67, 16.62)];
            [bezierPath addCurveToPoint: CGPointMake(33.15, 13.95) controlPoint1: CGPointMake(36.62, 15.18) controlPoint2: CGPointMake(34.95, 14.23)];
            [bezierPath addCurveToPoint: CGPointMake(32.78, 13.92) controlPoint1: CGPointMake(33.03, 13.93) controlPoint2: CGPointMake(32.9, 13.93)];
            [bezierPath addCurveToPoint: CGPointMake(32, 13.86) controlPoint1: CGPointMake(32.52, 13.89) controlPoint2: CGPointMake(32.26, 13.86)];
            [bezierPath addLineToPoint: CGPointMake(32, 13.86)];
            [bezierPath addLineToPoint: CGPointMake(32, 13.86)];
            [bezierPath addLineToPoint: CGPointMake(32, 13.86)];
            [bezierPath addLineToPoint: CGPointMake(32, 13.86)];
            [bezierPath addCurveToPoint: CGPointMake(31.38, 13.91) controlPoint1: CGPointMake(31.79, 13.86) controlPoint2: CGPointMake(31.59, 13.89)];
            [bezierPath addCurveToPoint: CGPointMake(30.85, 13.95) controlPoint1: CGPointMake(31.2, 13.92) controlPoint2: CGPointMake(31.02, 13.92)];
            [bezierPath addCurveToPoint: CGPointMake(26.92, 15.74) controlPoint1: CGPointMake(29.44, 14.17) controlPoint2: CGPointMake(28.12, 14.8)];
            [bezierPath addCurveToPoint: CGPointMake(25.94, 16.61) controlPoint1: CGPointMake(26.58, 16.01) controlPoint2: CGPointMake(26.25, 16.29)];
            [bezierPath addCurveToPoint: CGPointMake(24.13, 16.76) controlPoint1: CGPointMake(25.31, 16.61) controlPoint2: CGPointMake(24.71, 16.66)];
            [bezierPath addCurveToPoint: CGPointMake(19.7, 18.95) controlPoint1: CGPointMake(22.41, 17.06) controlPoint2: CGPointMake(20.88, 17.77)];
            [bezierPath addCurveToPoint: CGPointMake(17.36, 25.19) controlPoint1: CGPointMake(18.12, 20.53) controlPoint2: CGPointMake(17.37, 22.72)];
            [bezierPath addCurveToPoint: CGPointMake(14.61, 31.25) controlPoint1: CGPointMake(15.62, 26.94) controlPoint2: CGPointMake(14.61, 29.02)];
            [bezierPath addLineToPoint: CGPointMake(14.61, 31.25)];
            [bezierPath addCurveToPoint: CGPointMake(14.61, 31.25) controlPoint1: CGPointMake(14.61, 31.25) controlPoint2: CGPointMake(14.61, 31.25)];
            [bezierPath addCurveToPoint: CGPointMake(14.66, 31.92) controlPoint1: CGPointMake(14.61, 31.48) controlPoint2: CGPointMake(14.64, 31.7)];
            [bezierPath addCurveToPoint: CGPointMake(14.7, 32.4) controlPoint1: CGPointMake(14.67, 32.08) controlPoint2: CGPointMake(14.67, 32.24)];
            [bezierPath addCurveToPoint: CGPointMake(15.86, 35.44) controlPoint1: CGPointMake(14.86, 33.46) controlPoint2: CGPointMake(15.27, 34.48)];
            [bezierPath addCurveToPoint: CGPointMake(15.97, 35.64) controlPoint1: CGPointMake(15.9, 35.5) controlPoint2: CGPointMake(15.93, 35.57)];
            [bezierPath addCurveToPoint: CGPointMake(17.36, 37.32) controlPoint1: CGPointMake(16.36, 36.23) controlPoint2: CGPointMake(16.83, 36.78)];
            [bezierPath addCurveToPoint: CGPointMake(17.49, 38.98) controlPoint1: CGPointMake(17.36, 37.89) controlPoint2: CGPointMake(17.41, 38.44)];
            [bezierPath addCurveToPoint: CGPointMake(18.35, 41.7) controlPoint1: CGPointMake(17.65, 39.95) controlPoint2: CGPointMake(17.92, 40.87)];
            [bezierPath addCurveToPoint: CGPointMake(19.7, 43.55) controlPoint1: CGPointMake(18.7, 42.38) controlPoint2: CGPointMake(19.15, 43)];
            [bezierPath addCurveToPoint: CGPointMake(25.93, 45.89) controlPoint1: CGPointMake(21.28, 45.13) controlPoint2: CGPointMake(23.47, 45.88)];
            [bezierPath addCurveToPoint: CGPointMake(27.61, 47.28) controlPoint1: CGPointMake(26.47, 46.42) controlPoint2: CGPointMake(27.02, 46.89)];
            [bezierPath addCurveToPoint: CGPointMake(32, 48.64) controlPoint1: CGPointMake(28.96, 48.16) controlPoint2: CGPointMake(30.44, 48.64)];
            [bezierPath addLineToPoint: CGPointMake(32, 48.64)];
            [bezierPath addLineToPoint: CGPointMake(32, 48.64)];
            [bezierPath addLineToPoint: CGPointMake(32, 48.64)];
            [bezierPath addLineToPoint: CGPointMake(32, 48.64)];
            [bezierPath addCurveToPoint: CGPointMake(38.06, 45.89) controlPoint1: CGPointMake(34.23, 48.64) controlPoint2: CGPointMake(36.31, 47.63)];
            [bezierPath addCurveToPoint: CGPointMake(44.3, 43.55) controlPoint1: CGPointMake(40.53, 45.88) controlPoint2: CGPointMake(42.72, 45.13)];
            [bezierPath addLineToPoint: CGPointMake(44.3, 43.55)];
            [bezierPath addLineToPoint: CGPointMake(44.3, 43.55)];
            [bezierPath addCurveToPoint: CGPointMake(46.64, 37.31) controlPoint1: CGPointMake(45.88, 41.97) controlPoint2: CGPointMake(46.63, 39.78)];
            [bezierPath addCurveToPoint: CGPointMake(49.39, 31.25) controlPoint1: CGPointMake(48.38, 35.56) controlPoint2: CGPointMake(49.39, 33.48)];
            [bezierPath addLineToPoint: CGPointMake(49.39, 31.25)];
            [bezierPath closePath];
            [color2 setStroke];
            bezierPath.lineWidth = 1;
            [bezierPath stroke];


            //// Bezier 2 Drawing
            UIBezierPath* bezier2Path = [UIBezierPath bezierPath];
            [bezier2Path moveToPoint: CGPointMake(22.42, 29.85)];
            [bezier2Path addLineToPoint: CGPointMake(29.74, 37.17)];
            [bezier2Path addLineToPoint: CGPointMake(41.58, 25.33)];
            bezier2Path.usesEvenOddFillRule = YES;

            [color2 setStroke];
            bezier2Path.lineWidth = 1;
            [bezier2Path stroke];

         else 

            //// Color Declarations
            UIColor* color3 = [UIColor colorWithRed: 0.5 green: 0.5 blue: 0.5 alpha: 1];

            //// Bezier 2 Drawing
            UIBezierPath* bezier2Path = [UIBezierPath bezierPath];
            [bezier2Path moveToPoint: CGPointMake(22.42, 29.85)];
            [bezier2Path addLineToPoint: CGPointMake(29.74, 37.17)];
            [bezier2Path addLineToPoint: CGPointMake(41.58, 25.33)];
            bezier2Path.usesEvenOddFillRule = YES;

            [color3 setStroke];
            bezier2Path.lineWidth = 1;
            [bezier2Path stroke];
        
    

如果按钮被选中,则绘制第一个代码,否则绘制另一个代码。 我更喜欢这种方法,因为我使用 Paint Code。这样可以节省大量时间,而且您无需创建数千个 png 或 jpeg。

【讨论】:

【参考方案3】:

根据您对其他答案之一的评论,这是一个询问“我如何用 Y 做 X 以实现 Z?”的情况。当你真的应该问“我如何实现 Z?”时

如果您希望按钮在图像顶部而不是旁边绘制文本,只需将图像设置为按钮的背景图像即可。使用setBackgroundImage:forState:,而不是setImage:forState:,然后正常设置标题。

无论如何,您要么必须在drawRect: 中绘制图像,要么将文本移动到子视图中,以便在图像上方绘制。我提到的解决方案是第二个选项的一个版本。

【讨论】:

奇怪的是,当我这样做时,我仍然在图像下结束,现在是背景图像 - 现在没有前景图像。我相信发生的事情是我的 drawRect 被调用,然后超级的 drawRect 被调用,覆盖了我绘制的文本。 如果您使用背景图片,请不要使用 drawRect:。背景图片会在drawRect:上方绘制,但你并不需要自定义绘制,因为标题会在背景图片上方绘制。 @mahboudz:正如 Brent 已经说过的,如果您需要的只是图像上的文本,则不应覆盖 -drawRect:。使用 setTitle:forState: 设置文本。您的情况听起来正是 UIButton 的用途 - 为什么要重新发明***?【参考方案4】:

您不需要子类化 UIButton 只是为了向它添加一些文本。下面是在 UIViewController 子类的 -viewDidLoad 方法中为自定义按钮设置按钮标题的示例:

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 0, 44, 44);
[button setTitle:@"x" forState:UIControlStateNormal];
[self.view addSubview:button];

您还可以设置按钮的字体属性或使用 -setTitleColor:forState: 更改颜色。

【讨论】:

让我补充一些细节。该按钮是一个小圆形对象的图像。如果我让默认标题发生,标题会出现在按钮的右侧,而不是在它的顶部。所以我把标题留空,我想把标题画在上面。我需要的字体大小有大约三个字符的空间。但如果我以上述为例,“x”将显示在按钮的一侧,而不是顶部。 这是使用 setTitle flickr.com/photos/glasscyclops/3495881450 的样子【参考方案5】:

在按钮的视图上添加一个子视图怎么样?然后你就可以完全控制它,而不用关心按钮做了什么。您甚至可以将其设为 Label 并为自己保存 drawRect。

【讨论】:

以上是关于如何在 UIButton 子类中覆盖 -drawrect?的主要内容,如果未能解决你的问题,请参考以下文章

子类化 UIButton 并覆盖触摸事件 - 不起作用

如何通过子类化 UIButton 来获取按钮的背景图像名称?

如何覆盖 Xamarin.IOS UIButton 的 LayoutSublayersOfLayer 行为?

Swift - UIButton 覆盖 setSelected

如何使自定义 UIButton 变暗

在UIButton上覆盖'isSelected'或'isEnabled'不起作用