【问题标题】:objective C: Buttons created from subclass of UIButton class not working目标 C:从 UIButton 类的子类创建的按钮不起作用
【发布时间】:2011-06-22 16:57:26
【问题描述】:

我正在创建 UIButton 的子类,以便创建自己的自定义按钮。我的代码如下:

//interface file (subclass of uIButton
@interface UICustomButton : UIButton 
{
    Answer *answer;
    NSString *btnType;
}

@property (nonatomic, retain) Answer *answer;
@property (nonatomic, assign) NSString *btnType;

- (id)initWithAnswer:(Answer *)ans andButtonType:(NSString *)type andFrame:(CGRect)frame; 
- (void)buttonPressed;

@end


//Implementation file (.m)
@implementation UICustomButton
@synthesize answer,btnType;

- (id)initWithAnswer:(Answer *)ans andButtonType:(NSString *)type andFrame:(CGRect)frame; 
{
    self = [super initWithFrame:frame];
    if (self) 
    {
        self = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
        self.backgroundColor = [UIColor colorWithHexString:@"#E2E4E7"];

    }

    [self addTarget:self action:@selector(buttonPressed) forControlEvents:UIControlStateNormal];

    self.answer = ans;
    self.btnType = type;

    return self;
}

我在使上述代码正常工作时遇到了一些问题。我有两个问题

1) 按钮没有响应选择器方法“buttonPressed”

2) 我在 'self.answer = ans' 和 'self.btnType = type' 行中遇到运行时错误堆栈跟踪如下:

-[UIButton setAnswer:]: unrecognized selector sent to instance 0x614ebc0
2011-06-23 00:55:27.038 onethingaday[97355:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIButton setAnswer:]: unrecognized selector sent to instance 0x614ebc0'

我在这里做错了什么?

【问题讨论】:

  • 我发现只在子类中调用[super init]是行不通的,至少在iOS8中是这样。它只是简单地返回零。所以我调用[super initWithFrame:CGRectZero],然后你必须在代码中设置一些大小...
  • @albertamg,您应该考虑删除您的评论!现在是 2015 年,是错误的和过时的。
  • @IulianOnofrei 你是对的。该评论已有 4 年历史,现在已过时。

标签: objective-c ios uibutton


【解决方案1】:

发生这种情况是因为您在 init 方法中创建的是 UIButton 类型对象,而不是 UICustomButton 类型

self = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];

尝试将您的 init 方法替换为

- (id)initWithAnswer:(Answer *)ans andButtonType:(NSString *)type andFrame:(CGRect)frame; 
{
    self = [self initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
    if (self) 
    {
        self.backgroundColor = [UIColor colorWithHexString:@"#E2E4E7"];

        [self addTarget:self action:@selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside];

        self.answer = ans;
        self.btnType = type;
    }

    return self;
}

这将导致self 成为UICustomButton 类型的对象。

此外,当您使用 addTarget:action:forControlEvents: 方法将目标添加到按钮时,您使用的 UIControlState 参数类型错误

你应该使用下面的值:

UIControlEventTouchDown
UIControlEventTouchDownRepeat
UIControlEventTouchDragInside
UIControlEventTouchDragOutside
UIControlEventTouchDragEnter
UIControlEventTouchDragExit
UIControlEventTouchUpInside
UIControlEventTouchUpOutside
UIControlEventTouchCancel


编辑: UIButton 子类化注意事项

网络上的许多参考资料都说您不应该继承 UIButton 类,但不仅有人说为什么,而且让我深感恼火的是 UIButton Class Reference 根本没有说明它。

如果你以UIWebView Class Reference 为例,它明确指出你不应该继承UIWebView

子类化注释 UIWebView 类 不应该被子类化。

UIButton 的重要之处在于它继承自 UIControlUIControl Class Reference 本身提供了一个简单明了的解释

子类化注释你可能想要 为任一扩展 UIControl 子类 有两个原因:

  • 观察或修改调度 给目标的行动信息 特殊事件
  • 提供定制 跟踪行为(例如, 更改突出显示的外观)

因此,这意味着您可以子类化 UIButton,但您应该小心您正在做的事情。只需将其子类化以更改其行为而不是外观。要修改UIButton 的外观,您应该使用为此提供的接口方法,例如:

setTitle:forState:
setBackgroundImage:forState:
setImage:forState:

值得一读的参考资料

来源:my post here

【讨论】:

  • -1。如果这行得通,那充其量只是一个hack。制作按钮只有一种正确的方法,那就是工厂方法+buttonWithType:
  • 如果它不打算被子类化,它会在文档上(就像他们明确声明的 UIWebView 一样)。而且苹果也有几个项目,他们使用UIButtoninitWithFrame:方法来创建一个按钮,比如UICatalog,例如:developer.apple.com/library/ios/#samplecode/UICatalog/Listings/…。我只是觉得你反应过度了;)
  • 没有。文档显然只提供了一种创建方法:buttonWithType:。 buttonType 属性在子类化时只是未定义,没有办法设置它。随意使用它。但是在提倡这样做时,您还应该提到即使是较小的 iOS 更新也可能会破坏您的应用程序。并不是说它极有可能发生,但它可能不像你想象的那么不可能。只需考虑在未来的 iOS 版本中添加的一个重要属性,即 buttonWithType: 设置但您没有这样做(因为您根本不知道它)。或不同的默认按钮类型。
  • 如果我遵循这种思维方式,我将无法创建UIView,因为文档也没有显示init 方法。您只是忘记了继承部分。 UIButton 文档不需要显示 init 方法,因为它继承自 NSObject。以UIImageView 为例,该文档有一个initWithImage 方法但没有init,尽管没有什么能阻止我只用init 创建它并在之后设置image 属性。
  • 我在此讨论的基础上添加了一些关于 UIButton 子类化问题的注意事项。希望它能让我的观点清楚......
【解决方案2】:

不确定这是否在之前的文档中,但无论如何这些是+ (id)buttonWithType:(UIButtonType)buttonType 上的当前注释...

在我看来,只要您使用init 而不是buttonWithType,子类化就可以了。不过,我还没有亲自尝试过。

讨论这个方法是一个方便的构造函数,用于创建 具有特定配置的按钮对象。它是 UIButton 的子类, 此方法不会返回您的子类的实例。如果你想 要创建特定子类的实例,您必须分配/初始化 直接按钮。

当创建一个自定义按钮时——该按钮的类型为 UIButtonTypeCustom——按钮的框架设置为 (0, 0, 0, 0) 最初。在将按钮添加到界面之前,您应该 将框架更新为更合适的值。

【讨论】:

    【解决方案3】:

    如果您想在用户与您的按钮交互时获得通知,只需子类化 UIButton 并实现这些方法:

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"touchesBegan");
    }
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"touchesEnded");
    }
    
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"touchesCancelled");
    }
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
        NSLog(@"touchesMoved");
    }
    

    不需要初始化方法。

    【讨论】:

      【解决方案4】:

      编辑

      这个答案可以追溯到几年前,而且情况已经发生了变化——Apple 文档现在明确提到了子类化并给出了一些提示。

      因此,以下答案可能与当前的发展无关或错误,如果您对当前的技术水平感兴趣,可能会被忽略。


      UIButton 应该被子类化。

      您最好创建一个类别并定义一个提供所需按钮的工厂方法(正确调用buttonWithType:)。 initWithFrame: 无论如何都不是初始化按钮的正确方法。

      【讨论】:

      • 我很想知道投反对票的原因。几乎网络上的每一个资源都告诉你不要继承 UIButton。
      • 你能提供一个像样的资源吗?我发现 Apple 文档很混乱。
      • 实际上,UIButton 文档明确提到了子类化,至少在 iOS 6.1 中是这样。请参阅 Jonny 的回答。
      【解决方案5】:
      //
      //  BtnClass.m
      
      #import "BtnClass.h"
      
      @implementation BtnClass
      
      - (id)initWithFrame:(CGRect)frame
      {
          self = [super initWithFrame:frame];
          if (self) {
              // Initialization code
      
      
          }
          return self;
      }
      
      //added custum properities to button
      -(id)initWithCoder:(NSCoder *)aDecoder
      {
          NSLog(@"initWithCoder");
          self = [super initWithCoder: aDecoder];
          if (self) {
              // Initialization code
      
              _numberOfItems=[[UILabel alloc]initWithFrame:CGRectMake(40, 8, 160, 30)];
              _numberOfItems.textAlignment=NSTextAlignmentLeft;
              _numberOfItems.font = [UIFont boldSystemFontOfSize:18.0];
              _numberOfItems.textColor = [UIColor darkGrayColor];
              [self addSubview:_numberOfItems];
              _leftImage=[[UIImageView alloc]initWithFrame:CGRectMake(10, 10, 25, 25)];
              [self addSubview:_leftImage];
              _rightImage=[[UIImageView alloc]initWithFrame:CGRectMake(280, 10, 15, 15)];
              [self addSubview:_rightImage];
              [self setImage:[UIImage imageNamed:@"list-bg2-1.png"] forState:UIControlStateNormal];
              [_rightImage setImage:[UIImage imageNamed:@"carat.png"]];
              self.backgroundColor=[UIColor blackColor];
      
      
              if(self.tag==1)
              {
                  [_leftImage setImage:[UIImage imageNamed:@"notes-icon.png"]];
      
              }
              if(self.tag==2)
              {
                  [_leftImage setImage:[UIImage imageNamed:@"photos-icon.png"]];
      
              }
              if(self.tag==3)
              {
                  [_leftImage setImage:[UIImage imageNamed:@"videos-icon.png"]];
      
              }
      
      
          }
          return self;
      }
      
      //selected method of uibutton
      -(void)setSelected:(BOOL)selected
      {
      
          [super setSelected:selected];
      
      
          if(selected)
          {
              [self setImage:nil forState:UIControlStateNormal];
              _numberOfItems.textColor = [UIColor whiteColor];
      
              [_rightImage setImage:[UIImage imageNamed:@"carat-open.png"]];
      
              if(self.tag==1)
              {
                  [_leftImage setImage:[UIImage imageNamed:@"white-notes-icon.png"]];
              }
              else if(self.tag==2)
              {
      
                  [_leftImage setImage:[UIImage imageNamed:@"white-photo-icon.png"]];
      
              }
              else
              {
                  [_leftImage setImage:[UIImage imageNamed:@"white-video-icon.png"]];
      
              }
      
          }
          else{
      
              _numberOfItems.textColor = [UIColor darkGrayColor];
      
              if(self.tag==1)
              {
                  [_leftImage setImage:[UIImage imageNamed:@"notes-icon.png"]];
      
              }
              if(self.tag==2)
              {
                  [_leftImage setImage:[UIImage imageNamed:@"photos-icon.png"]];
      
              }
              if(self.tag==3)
              {
                  [_leftImage setImage:[UIImage imageNamed:@"videos-icon.png"]];
      
              }
      
              [self setImage:[UIImage imageNamed:@"list-bg2-1.png"] forState:UIControlStateNormal];
      
              [_rightImage setImage:[UIImage imageNamed:@"carat.png"]];
      
          }
      }
      /*
      // Only override drawRect: if you perform custom drawing.
      // An empty implementation adversely affects performance during animation.
      - (void)drawRect:(CGRect)rect
      {
          // Drawing code
      }
      */
      
      @end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-19
        • 1970-01-01
        • 2011-06-30
        • 2018-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多