web-dev-qa-db-ja.com

Objective C:UIButtonクラスのサブクラスから作成されたボタンが機能しない

独自にカスタマイズしたボタンを作成するために、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;
}

上記のコードを機能させる際にいくつかの問題に直面しています。私は2つの問題があります

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'

私はここで何が間違っているのですか?

14
Zhen

これは、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;
}

これにより、selfUICustomButtonタイプのオブジェクトになります。

また、addTarget:action:forControlEvents:メソッドを使用してターゲットをボタンに追加するときに、UIControlStateパラメーターに間違ったタイプを使用しています

以下のものの中から値を使用する必要があります。

UIControlEventTouchDown
UIControlEventTouchDownRepeat
UIControlEventTouchDragInside
UIControlEventTouchDragOutside
UIControlEventTouchDragEnter
UIControlEventTouchDragExit
UIControlEventTouchUpInside
UIControlEventTouchUpOutside
UIControlEventTouchCancel


編集:UIButtonサブクラス化に関する注意

Web上の多くの参照では、UIButtonクラスをサブクラス化するべきではないと述べていますが、その理由を誰かが言っただけでなく、 IButtonクラスリファレンス がそれについて何も言っていないことも私を深く悩ませました。まったく。

IWebView Class Reference を例にとると、UIWebViewをサブクラス化してはならないことが明示的に示されています。

サブクラス化に関する注意事項UIWebViewクラスはサブクラス化しないでください。

UIButtonの大きな問題は、それがUIControlから継承することであり、適切で簡単な説明は IControlクラスリファレンス 自体にあります。

サブクラス化に関する注意事項次の2つの理由のいずれかにより、UIControlサブクラスを拡張することができます。

  • 特定のイベントのターゲットへのアクションメッセージのディスパッチを監視または変更するには
  • カスタム追跡動作を提供するため(たとえば、ハイライトの外観を変更するため)

つまり、これは、[〜#〜] can [〜#〜]UIButtonをサブクラス化できることを意味しますが、実行していることに注意する必要があります。サブクラス化するだけで、の動作notの外観が変更されます。 UIButtonの外観を変更するには、次のような、そのために提供されているインターフェイスメソッドを使用する必要があります。

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

読む価値のある参考文献

出典: 私の投稿はこちら

30
Felipe Sabino

これが以前のドキュメントにあったかどうかはわかりませんが、とにかくこれらは+ (id)buttonWithType:(UIButtonType)buttonType ..に関する現在のメモです。

私には、initの代わりにbuttonWithTypeを使用する限り、サブクラス化は問題ないように見えます。しかし、私はまだそれを自分で試していません。

説明このメソッドは、特定の構成でボタンオブジェクトを作成するための便利なコンストラクターです。 UIButtonをサブクラス化する場合、このメソッドはサブクラスのインスタンスを返しません。特定のサブクラスのインスタンスを作成する場合は、ボタンを直接割り当て/初期化する必要があります。

カスタムボタン(つまり、タイプUIButtonTypeCustomのボタン)を作成する場合、ボタンのフレームは最初は(0、0、0、0)に設定されます。ボタンをインターフェイスに追加する前に、フレームをより適切な値に更新する必要があります。

10
Jonny

ユーザーがボタンを操作しているときに通知を受け取りたい場合は、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");
}

Initメソッドは必要ありません。

0
kanstraktar
//
//  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
0
Alok SInha

編集

この答えは数年前にさかのぼり、状況は変化しました-Appleドキュメントは現在、サブクラス化について明示的に言及し、いくつかのヒントを提供しています。

したがって、次の答えは現在の開発には無関係または間違っているであり、現在の最先端技術に興味がある場合は無視される可能性があります。


UIButtonはnotサブクラス化されることを意味します。

カテゴリを作成し、必要なボタンを配信するファクトリメソッドを定義することをお勧めします(buttonWithType:を適切に呼び出します)。 initWithFrame:は、とにかくボタンを初期化する正しい方法ではありません。

0
Eiko