如何在UIButton子类中设置UIButton类型

问题描述 投票:0回答:9

我正在子类化 UIButton,我想要的是将按钮类型设置为 Round Rect。

按钮.h

@interface Button : UIButton {}
    - (void)initialize;
@end

按钮.m

@implementation Button

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self initialize];
    }
    return self;
}


-(id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if(self){
        [self initialize];
    }
    return self;
}

- (void)initialize
{
    self.titleLabel.font = [UIFont systemFontOfSize:20];
    self.titleLabel.textColor = [UIColor redColor];
    self.titleLabel.textAlignment = UITextAlignmentCenter;
   //[UIButton buttonWithType:UIButtonTypeRoundedRect];
}

@end

在这里我尝试了

[UIButton buttonWithType:UIButtonTypeRoundedRect]
但它不起作用。谁能建议如何让它发挥作用?

我知道在之前的许多文章中都说过不建议对 UIButton 进行子类化,但事实上,在开发人员文档中没有提及不对其进行子类化。

ios uibutton subclass
9个回答
16
投票

UIButton
Swift 中的子类

*以下代码适用于 Swift 3 及以上版本。

您无法根据设计设置

buttonType
子类的
UIButton
。它会自动设置为
custom
,这意味着您将获得简单的外观和行为作为起点。

如果您想重用设置按钮外观的代码,则无需子类化即可执行此操作。一种方法是提供创建

UIButton
并设置视觉属性的工厂方法。

避免子类化的工厂方法示例

extension UIButton {
    static func createStandardButton() -> UIButton {
        let button = UIButton(type: UIButtonType.system)
        button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
        button.setTitleColor(UIColor.black, for: .normal)
        button.setTitleColor(UIColor.gray, for: .highlighted)
        return button
    }
}

let button = UIButton.createStandardButton()

当其他定制技术足够时,我会避免子类化

UIButton
。工厂方法示例是一种选择。还有其他选项包括 UIAppearance API 等

有时存在需要子类化的定制需求。例如,我创建了

UIButton
子类来精细控制按钮响应触摸事件的动画方式,或者让按钮在点击时调用预定义的委托或闭包(而不是为每个实例分配
#selector
) ).

以下是作为起点的基本

UIButton
子类示例。

UIButton 子类示例

internal class CustomButton: UIButton {

    init() {
        // The frame can be set outside of the initializer. Default to zero.
        super.init(frame: CGRect.zero)
        initialize()
    }

    required init?(coder aDecoder: NSCoder) {
        // Called when instantiating from storyboard or nib
        super.init(coder: aDecoder)
        initialize()
    }

    func initialize() {
        print("Execute common initialization code")
    }
}

let button = CustomButton()
print(button.buttonType == .custom)  // true

关于
UIButtonType

的注释

自从 2012 年提出这个问题以来,

UIButtonType.roundedRect
已被弃用。头文件注释说使用
UIButtonType.system
代替。

以下是 Xcode 中 UIButton.h 转换为 Swift 的内容

public enum UIButtonType : Int {

    case custom // no button type

    @available(iOS 7.0, *)
    case system // standard system button

    case detailDisclosure
    case infoLight
    case infoDark
    case contactAdd

    public static var roundedRect: UIButtonType { get } // Deprecated, use UIButtonTypeSystem instead
}

这是设置故事板下拉菜单中所谓的“样式”设置的关键信息:

https://stackoverflow.com/a/72913854/294884


13
投票

您可能会发现 CocoaBuilder 线程中的讨论 How to subclass UIButton? 有帮助,特别是 Jack Nutting 建议忽略 ButtonType:

请注意,这样,buttonType 不会显式设置为任何内容, 这可能意味着它是 UIButtonTypeCustom。文档没有 似乎实际上指定了这一点,但因为这是 0 值 枚举,这可能就是发生的情况(这似乎是可观察到的 行为也是如此)


12
投票

不完全是你想要的,但请记住你的子类仍然有buttonWithType方法,并且它工作得很好。

buttonWithType 调用您的子类 initWithFrame,并适当地设置类型。

SubclassButton *myButton=[SubclassButton buttonWithType:UIButtonTypeRoundedRect];

6
投票

创建一个方便的 init 对我有用:

class CustomButton: UIButton {
    
    convenience init() {
        self.init(type: .system)
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        /*Do customization here*/
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        
        /*Do customization here*/
    }
}

1
投票

对于 iOS7,这比以前更相关,因为有时你需要使用 UIButtonTypeSystem,并且你不能简单地重写 init 并执行 [MyButton alloc] init],因为这样它是一个 UIButtonTypeCustom,它不反映tintColor也没有很好的高光淡出效果。

要子类化,请像这样创建静态构造函数:

+ (instancetype)myButtonWithTitle:(NSString *)title imageNamed:(NSString *)imageName target:(id)target action:(SEL)action {
    MyButton *button = [self buttonWithType:UIButtonTypeSystem];
    ... my custom setup for title, image, target, etc ...
    return button;
}

0
投票

你绝对可以继承 UIButton 的子类。我已经成功创建了一个 DateButton,它看起来像一个 UITextField,但是当用户触摸它时,它会在 Popover 中显示一个 DatePicker。有一个用于存储日期等的属性。如果上述方法未能解决您的问题,请告诉我,我将发布更多详细信息。


0
投票

这不是一个好的解决方案,所以我们需要“感谢”苹果使用这个拐杖。 XD

//if self.buttonType == .system && self.state.contains(.highlighted) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
        self.titleLabel?.alpha = 1.0
    }
//}

例如添加

touchesBegan(...)


0
投票

由于最初的目的是在初始化点配置按钮,因此您可以声明一个辅助初始化程序并传递如下配置:

extension UIButton {
    convenience init(type: ButtonType, configuration(UIButton) -> ()) {
        self.init(type: type)
        configuration(self)
    }
}

这将初始化具有给定类型的按钮,并在返回新的初始化按钮之前对其执行任何配置。

🛠️用法:
let myButton = UIButton(type: .contactAdd) {
    $0.tintColor = .red
}

💡为所有按钮制定一致的样式?

您可以创建一个配置函数并将其传递给所有按钮:

func consistentConfiguration(_ button: UIButton) -> () {
    button.tintColor = .red
}

let myConsistentButton1 = UIButton(type: .contactAdd, configuration: consistentConfiguration)
let myConsistentButton2 = UIButton(type: .detailDisclosure, configuration: consistentConfiguration)

⚠️ 您可以将此配置转换为另一个辅助初始化器,但不建议这样做,因为它的作用域不正确


-2
投票

这个怎么样?

- (id)initWithFrame:(CGRect)frame 
{
    self = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 
    if (self) {
        self.frame = frame;
    }

    return self;
}
© www.soinside.com 2019 - 2024. All rights reserved.