自定義視圖按鈕點(diǎn)擊事件處理的幾種方法

一, 關(guān)聯(lián)對象 (runtime)

其實(shí)也是通過block實(shí)現(xiàn), 可以看成一種全局實(shí)現(xiàn)
用類目創(chuàng)建一個(gè)UIButton的點(diǎn)擊擴(kuò)展方法, 這種方法的好處就是直接在自定義視圖中創(chuàng)建一個(gè)button加在視圖上即可, 在需要調(diào)用的地方調(diào)用這個(gè)方法, 即可實(shí)現(xiàn)button點(diǎn)擊事件, 不用每個(gè)自定義視圖都去寫相關(guān)方法, 減少代碼量. 可能不太好的地方是, 需要?jiǎng)?chuàng)建一個(gè)開放的 button 屬性, 可能被修改.

關(guān)聯(lián)對象

摘自網(wǎng)絡(luò):

關(guān)聯(lián)對象通過來區(qū)分, 我們可以把關(guān)聯(lián)對象想成NSDictionary, 把關(guān)聯(lián)對象的值理解為字典中的對象, 存取關(guān)聯(lián)對象上的值就類似于字典中setObject:forKey:方法和objectForKey:方法
兩者的差別是, 關(guān)聯(lián)對象的鍵是個(gè)不透明指針, 所謂不透明指針是其所指向的數(shù)據(jù)結(jié)構(gòu)不局限于某種特定類型的指針. 在設(shè)置關(guān)聯(lián)對象時(shí), 若想讓兩個(gè)鍵匹配到同一個(gè)值, 則二者必須是完全相同的指針, 因此, 使用靜態(tài)全局變量做 Key 即可

處理方法:

以給定的鍵設(shè)置關(guān)聯(lián)對象的值objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)
根據(jù)鍵獲取值objc_getAssociatedObject(id object, void *key)
移除全部關(guān)聯(lián)對象`objc_removeAssociatedObject(id object)

button類目封裝

首先創(chuàng)建一個(gè)類目UIButton + XXX(XXX隨你便)
在XXX.h中:

#import <UIKit/UIKit.h>

typedef void(^ClickActionBlock)(UIButton *button);

@interface UIButton (ZYNBlock)

- (void)setClickBlock:(ClickActionBlock)block andEvent:(UIControlEvents)event;

@end

在XXX.M中

#import "UIButton+ZYNBlock.h"
//別忘記引用
#import <objc/runtime.h>

static void *buttonClickKey = "buttonClickKey";

@implementation UIButton (ZYNBlock)

- (void)setClickBlock:(ClickActionBlock)block andEvent:(UIControlEvents)event {
    
    // 設(shè)置關(guān)聯(lián)對象
    objc_setAssociatedObject(self, buttonClickKey, block, OBJC_ASSOCIATION_COPY_NONATOMIC);
    
    [self addTarget:self action:@selector(buttonClick:) forControlEvents:event];
}

- (void)buttonClick:(UIButton *)button {
    
    // 獲取關(guān)聯(lián)對象
    ClickActionBlock block = objc_getAssociatedObject(self, buttonClickKey);
    
    if (block) {
        block(button);
    }
}

@end

使用方法

自定義視圖的.h文件中開放相關(guān)button屬性:

#import <UIKit/UIKit.h>

@interface JPSUserHeaderView : UIView

@property (nonatomic, weak) UIButton *closeArrow;

@end

自定義視圖.m中

/** close button */
// 不需要寫任何button點(diǎn)擊相關(guān)方法, 直接添加視圖上即可
    UIButton *closeArrow = [UIButton buttonWithType:UIButtonTypeCustom];
    [closeArrow setImage:[UIImage imageNamed:@"user_close"] forState:UIControlStateNormal];
    closeArrow.contentMode = UIViewContentModeScaleAspectFit;
    [self addSubview:closeArrow];
    
    self.closeArrow = closeArrow;

在添加自定義視圖的控制器中:

- (void)setupSubViews {
    
    JPSUserHeaderView *headerView = [[JPSUserHeaderView alloc] initWithFrame:HeaderViewF];
    
    // 直接用自定義視圖里面的 button 調(diào)用剛才封裝的方法
    [headerView.closeArrow setClickBlock:^(UIButton *button) {
    // 需要執(zhí)行的操作
        [self dismissViewControllerAnimated:YES completion:nil];
    } andEvent:UIControlEventTouchUpInside];
    
    self.tableView.tableHeaderView = headerView;
    self.tableView.contentInset = UIEdgeInsetsMake(-20, 0, 0, 0);
    self.tableView.showsVerticalScrollIndicator = NO;
    self.tableView.showsHorizontalScrollIndicator = NO;
    self.tableView.alwaysBounceVertical = NO;
    self.tableView.backgroundColor = [UIColor colorWithRed:0.908 green:0.926 blue:0.932 alpha:1.000];
    
    [self.tableView registerClass:[JPSTableViewCell class] forCellReuseIdentifier:cellIdentifier];
}


二, 在自定義視圖中單獨(dú)綁定block

這種方法僅適用于當(dāng)前自定義視圖, 如果項(xiàng)目中用的全是這個(gè)自定義視圖, 那么可以直接這樣寫, 不用開放相關(guān)屬性給外界, 更安全

寫法

自定義視圖.h中:

#import <UIKit/UIKit.h>

// typedef block塊直接創(chuàng)建一個(gè)block, 不定義屬性是嫌麻煩, 太懶= =
typedef void(^AvatarButtonBlock)(UIButton *button);

@interface JPSLearnHomeHeaderView : UIView

// 第二種調(diào)用形式, 可以寫在私有屬性或者公有
//@property (nonatomic, copy) AvatarButtonBlock block;

// 設(shè)置回調(diào)
- (void)setAvatarClick:(AvatarButtonBlock)block;

@end

自定義視圖.m中

/** avatar */
    UIButton *avatar = [UIButton buttonWithType:UIButtonTypeCustom];
    [avatar setBackgroundImage:[UIImage imageNamed:@"user_avatar"] forState:UIControlStateNormal];
    avatar.layer.masksToBounds = YES;
    avatar.layer.cornerRadius = 12;
    
    // 不用于關(guān)聯(lián)對象, 單獨(dú)綁定需要給按鈕添加target/action來綁定block
    [avatar addTarget:self action:@selector(modalToUserPage:) forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:avatar];
// 按鈕點(diǎn)擊事件
- (void)modalToUserPage:(UIButton *)button {
    if (self.clickEvent) {
        self.clickEvent(button);
    }
}

// block回調(diào)實(shí)現(xiàn)
- (void)setAvatarClick:(AvatarButtonBlock)block {
    if (_clickEvent != block) {
        self.clickEvent = block;
    }
}

使用

添加自定義視圖的控制器中:

/** header view */
    JPSLearnHomeHeaderView *headerView = [[JPSLearnHomeHeaderView alloc] initWithFrame:HeaderViewF];
    
    // 調(diào)用方法一:
    // 用自定義視圖調(diào)用 block 回調(diào)
    [headerView setAvatarClick:^(UIButton *button) {
        
        JPSUserTableController *userController = [[JPSUserTableController alloc] init];
        
        JPSNavController *nav = [[JPSNavController alloc] initWithRootViewController:userController];
        
        [self presentViewController:nav animated:YES completion:nil];
    }];
   
#if 0
    // 如果自定義view里面的block屬性是開放的, 可以直接調(diào)用
    headerView.block = ^(UIButton *button) {
       // 需要實(shí)現(xiàn)的代碼   
       JPSUserTableController *userController = [[JPSUserTableController alloc] init];
        
       JPSNavController *nav = [[JPSNavController alloc] initWithRootViewController:userController];
        
       [self presentViewController:nav animated:YES completion:nil];
    };
#endif
    
    [self.view addSubview:headerView];

其他實(shí)現(xiàn)方法

  • tableview data source代理方法中:(不推薦, 這樣寫太丑)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
    
    [cell.button addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];
    
    return cell;
}
  • 代理
    代理步驟太多了, 感覺僅處理簡單事件感覺完全沒必要...
    不過代理處理業(yè)務(wù)邏輯比較復(fù)雜的時(shí)候很好用.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容