IOS开发之自定义Button(集成三种回调模式)

简介:

  前面在做东西的时候都用到了storyboard,在今天的代码中就纯手写代码自己用封装个Button。这个Button继承于UIView类,在封装的时候用上啦OC中的三种回调模式:目标动作回调,委托回调,Block回调。具体的内容请参考之前的博客:“Objective-C中的Block回调模式”,“Target-Action回调模式”,“Objective-C中的委托(代理)模式”。在接下来要封装的button中将要用到上面的知识点。之前在做新浪微博中的Cell的时候用到了Block回调来确定是那个Cell上的那个Button。

  在封装Button之前呢,简单的了解一下UIView中的触摸事件:

    1.当触摸开始时会调用下面的事件

      -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

     2.当触摸取消时会调用下面的事件

      -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

       3.当触摸结束时会调用下面的事件

      -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

    4.当触摸移动时会调用下面的事件

      -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

  所以在封装自己的button是我们会用上上面的方法,首先新建一个ViewController, 然后把我们新建的ViewController在AppDelegate.m中设置成我们的根视图,我们关于Button的初始化和配置都写在ViewController中的ViewDidLoad中代码如下:

1    MyViewController *myViewController = [[MyViewController alloc] init];
2    self.window.rootViewController = myViewController;

 

  一、目标动作回调:

    首先新建一个MyButton类,MyButton类继承于UIView, 我们就在MyButton类中自定义我们的button.下面要为自定义Button添加目标动作回调接口,步骤如下:

      1.在MyButton.h中声明目标动作注册方法:

//TargetAction回调
-(void)addTarget:target action:(SEL)action;

 

    2.在MyButton.m中进行实现:

//延展
@interface MyButton()

@property (nonatomic,weak) id target;
@property (nonatomic, assign) SEL action;

@end


//实现
@implementation MyButton
//目标动作回调
-(void)addTarget:(id)target action:(SEL)action
{
    self.target = target;
    self.action = action;
}

  

    3.通过target来执行action方法,触摸完成的事件中让target执行action方法,执行之前要判断一下触摸的释放点是否在按钮的区域内,代码如下:

//当button点击结束时,如果结束点在button区域中执行action方法
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    //获取触摸对象
    UITouch *touche = [touches anyObject];
    //获取touche的位置
    CGPoint point = [touche locationInView:self];
    
    //判断点是否在button中
    if (CGRectContainsPoint(self.bounds, point))
    {
        //执行action
        [self.target performSelector:self.action withObject:self];  
    }

}

 

    4.在MyViewController中进行button的初始化,并注册目标方法回调,当点击button时,我们MyViewController中的tapButton方法就会被执行:

//在v2中添加一个button
    MyButton *button = [[MyButton alloc] initWithFrame:CGRectMake(10, 10, 44, 44)];
    
    button.backgroundColor = [UIColor blackColor];
    
    //注册回调
    [button addTarget:self action:@selector(tapButton)];

 

  二、委托回调 

   1.在上面的基础上添加上委托回调,通过委托回调添加按钮是否可用,按钮将要点击和按钮点击后的事件,首先我们得有协议来声明这三个方法。协议我们就不新建文件了,下面的协议是添加在MyButton.h中的,协议定义如下:

//定义MyButton要实现的协议, 用于委托回调
@protocol MyButtonDelegete <NSObject>

//可选择的实现
@optional

//当button将要点击时调用
-(void) myButtonWillTap:(MyButton *) sender;

//当button点击后做的事情
-(void) myButtonDidTap: (MyButton *) sender;

//判断button是否可以被点击
-(BOOL) myButtonShouldTap: (MyButton *) sender;

@end

 

    2.在MyButton.h中添加delegate属性,为了避免强引用循环,定义为weak类型,用于回调的注册:

//委托回调接口
@property (nonatomic, weak) id <MyButtonDelegete> delegate;

 

    3.在MyButton.m中当开始点击按钮时做一下处理,首先得判断delegate对象是否实现了协议中的方法如果实现了就通过delegate回调,如果没实现就不调用

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    
    //判断myButtonShouldTap是否在degate中实现啦:委托回调
    if ([self.delegate respondsToSelector:@selector(myButtonShouldTap:)])
    {
        //如果实现了,就获取button的状态
        myButtonState = [self.delegate myButtonShouldTap:self];

    } 
    
    //根据按钮的状态来做处理
    if (myButtonState)
    {
        //如果myButtonWillTap被实现啦,此时我们就实现myButtonWillTapf方法
        if ([self.delegate respondsToSelector:@selector(myButtonWillTap:)])
        {
            [self.delegate myButtonWillTap:self];
        }
    }
}

 

    4.在touchesEnded中相应的位置添加如下代码去执行按钮点击时要回调的方法:

1         //点击结束要调用myButtonDidTap  委托回调
2         if ([self.delegate respondsToSelector:@selector(myButtonDidTap:)])
3         {
4             [self.delegate myButtonDidTap:self];
5         }

 

 

    5、在MyViewController.m中注册委托回调

1     //注册委托回调
2     button.delegate = self;

 

    6、MyViewController要实现MyButtonDelegate,并实现相应的方法

//实现button委托回调的方法myButtonShouldTap:设置button是否好用
-(BOOL) myButtonShouldTap:(MyButton *)sender
{
    NSLog(@"我是Delegate:should方法");
    return YES;
}

//实现按钮将要点击的方法
-(void)myButtonWillTap:(MyButton *)sender
{
    NSLog(@"我是Delegate: will方法");
}

//实现按钮点击完要回调的方法
-(void) myButtonDidTap:(MyButton *)sender
{
    NSLog(@"我是Delegate: Did");
}

 

  三.Block回调

    1、为我们的按钮添加Block回调(把上面的委托回调改成Block回调),和之前微博中的Cell的Block回调类似,首先在MyButton.h中声明我们要用的Block类型,然后提供Block的set方法:

//button中使用Block回调,定义Block类型
@class MyButton;
typedef void (^ButtonWillAndDidBlock) (MyButton *sender);
typedef BOOL (^ButtonShouldBlock) (MyButton *sender);


//接受block的方法
-(void)setButtonShouldBlock: (ButtonShouldBlock) block;
-(void)setButtonWillBlock: (ButtonWillAndDidBlock) block;
-(void)setButtonDidBlock:(ButtonWillAndDidBlock) block;

 

 

    2.在MyButton.m中的延展中添加相应的属性来接受Controller中传过来的Block

1 //接受block块
2 @property (nonatomic, strong) ButtonWillAndDidBlock willBlock;
3 @property (nonatomic, strong) ButtonWillAndDidBlock didBlock;
4 @property (nonatomic, strong) ButtonShouldBlock shouldBlock;

  

    3.实现setter方法

//实现block回调的方法
-(void)setButtonWillBlock:(ButtonWillAndDidBlock)block
{
    self.willBlock = block;
}

-(void)setButtonDidBlock:(ButtonWillAndDidBlock)block
{
    self.didBlock = block;
}

-(void) setButtonShouldBlock:(ButtonShouldBlock)block
{
    self.shouldBlock = block;
}

 

    4.在MyButton.m中有委托调用的地方加入相应的Block回调,添加的代码如下:

//block回调
    if (self.shouldBlock) {
        //block回调获取按钮状态
        myButtonState = self.shouldBlock(self);
    }


        //block回调实现willTap
        if (self.willBlock)
        {
            self.willBlock(self);
        }


        //block回调
        if (self.didBlock) {
            self.didBlock(self);
        }

 

   5、在MyViewController中调用Button中的setter方法传入相应的block:

//实现button的block回调
    [button setButtonShouldBlock:^BOOL(MyButton *sender) {
        NSLog(@"我是Block: should方法\n\n");
        return YES;
    }];
    
    [button setButtonWillBlock:^(MyButton *sender) {
        NSLog(@"我是Block: Will方法\n\n");
    }];
    
    [button setButtonDidBlock:^(MyButton *sender) {
        NSLog(@"我是Blcok: Did方法\n\n");
    }];
    

    [self.view addSubview:button];


经过上面的代码我们的button就拥有三种回调模式了,下面是点击button控制台输出的日志:

相关文章
|
7天前
|
前端开发 Android开发 iOS开发
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
【4月更文挑战第30天】Flutter 框架实现跨平台移动应用,通过一致的 UI 渲染(Skia 引擎)、热重载功能和响应式框架提高开发效率和用户体验。然而,Android 和 iOS 的系统差异、渲染机制及编译过程影响性能。性能对比显示,iOS 可能因硬件优化提供更流畅体验,而 Android 更具灵活性和广泛硬件支持。开发者可采用代码、资源优化和特定平台优化策略,利用性能分析工具提升应用性能。
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
|
7天前
|
JSON API 数据处理
【Swift开发专栏】Swift中的RESTful API集成实战
【4月更文挑战第30天】本文探讨了在Swift中集成RESTful API的方法,涉及RESTful API的基础概念,如HTTP方法和设计原则,以及Swift的网络请求技术,如`URLSession`、`Alamofire`和`SwiftyJSON`。此外,还强调了数据处理、错误管理和异步操作的重要性。通过合理利用这些工具和策略,开发者能实现高效、稳定的API集成,提升应用性能和用户体验。
|
7天前
|
前端开发 定位技术 API
【Flutter前端技术开发专栏】Flutter中的第三方服务集成(如支付、地图等)
【4月更文挑战第30天】本文介绍了在Flutter中集成第三方服务,如支付和地图,以增强应用功能和用户体验。开发者可通过官方或社区插件集成服务,关注服务选择、API调用、错误处理和用户体验。支付集成涉及选择服务、获取API密钥、引入插件、调用API及处理结果。地图集成则需选择地图服务、获取API密钥、初始化地图并添加交互功能。集成时注意选择稳定插件、阅读文档、处理异常、优化性能和遵循安全规范。随着Flutter生态发展,更多第三方服务将可供选择。
【Flutter前端技术开发专栏】Flutter中的第三方服务集成(如支付、地图等)
|
7天前
|
Dart 前端开发 Android开发
【Flutter前端技术开发专栏】Flutter与原生代码的集成与交互
【4月更文挑战第30天】本文探讨了如何在Flutter中集成和交互原生代码,以利用特定平台的API和库。当需要访问如蓝牙、特定支付SDK或复杂动画时,集成原生代码能提升效率和性能。集成方法包括:使用Platform Channel进行通信,借助现有Flutter插件,以及Android和iOS的Embedding。文中通过一个电池信息获取的例子展示了如何使用`MethodChannel`在Dart和原生代码间传递调用。这些技术使开发者能充分利用原生功能,加速开发进程。
【Flutter前端技术开发专栏】Flutter与原生代码的集成与交互
|
7天前
|
传感器 前端开发 Android开发
【Flutter 前端技术开发专栏】Flutter 中的插件开发与集成
【4月更文挑战第30天】本文探讨了Flutter插件开发的关键技术和实践,包括插件作为连接Flutter与原生功能桥梁的角色,开发流程(定义接口、实现原生代码、打包发布),以及集成方法(添加依赖、初始化)。文中提到了多媒体、传感器和文件系统等常见插件类型,并以相机插件为例说明开发步骤。此外,还强调了版本兼容性、性能优化和错误处理的注意事项,推荐了开发工具和资源。随着Flutter的发展,插件开发将更加重要,未来有望形成更丰富的生态系统。
【Flutter 前端技术开发专栏】Flutter 中的插件开发与集成
|
7天前
|
存储 Swift iOS开发
使用Swift开发一个简单的iOS应用的详细步骤。
使用Swift开发iOS应用的步骤包括:创建Xcode项目,设计界面(Storyboard或代码),定义数据模型,实现业务逻辑,连接界面和逻辑,处理数据存储(如Core Data),添加网络请求(必要时),调试与测试,根据测试结果优化改进,最后提交至App Store或其它平台发布。
20 0
|
7天前
|
持续交付 开发工具 Swift
【Swift开发专栏】Swift与第三方库和框架的集成
【4月更文挑战第30天】本文探讨了Swift中集成第三方库和框架的策略,包括选择有功能需求、社区支持、丰富文档和合适许可证的库。集成步骤涉及使用CocoaPods等工具安装,`import`导入库,遵循错误处理和性能优化。建议遵循代码组织、单一职责原则,做好错误处理和日志记录,使用版本控制和CI/CD,以提升项目稳定性和用户体验。
|
7天前
|
安全 Swift iOS开发
【Swift 开发专栏】Swift 与 UIKit:构建 iOS 应用界面
【4月更文挑战第30天】本文探讨了Swift和UIKit在构建iOS应用界面的关键技术和实践方法。Swift的简洁语法、类型安全和高效编程模型,加上与UIKit的紧密集成,使开发者能便捷地创建用户界面。UIKit提供视图、控制器、布局、动画和事件处理等功能,支持灵活的界面设计。实践中,遵循设计原则,合理组织视图层次,运用布局和动画,以及实现响应式设计,能提升界面质量和用户体验。文章通过登录、列表和详情界面的实际案例展示了Swift与UIKit的结合应用。
|
7天前
|
存储 安全 Swift
【Swift 开发专栏】使用 Swift 开发一个简单的 iOS 应用
【4月更文挑战第30天】本文介绍了使用 Swift 开发简单 iOS 待办事项应用的步骤。首先,阐述了 iOS 开发的吸引力及 Swift 语言的优势。接着,详细说明了应用的需求和设计,包括添加、查看和删除待办事项的功能。开发步骤包括创建项目、界面搭建、数据存储、功能实现,并提供了相关代码示例。最后,强调了实际开发中需注意的细节和优化,旨在帮助初学者掌握 Swift 和 iOS 开发基础。
|
8天前
|
编解码 Linux Windows
FFmpeg开发笔记(十三)Windows环境给FFmpeg集成libopus和libvpx
本文档介绍了在Windows环境下如何为FFmpeg集成libopus和libvpx库。首先,详细阐述了安装libopus的步骤,包括下载源码、配置、编译和安装,并更新环境变量。接着,同样详细说明了libvpx的安装过程,注意需启用--enable-pic选项以避免编译错误。最后,介绍了重新配置并编译FFmpeg以启用这两个库,通过`ffmpeg -version`检查是否成功集成。整个过程参照了《FFmpeg开发实战:从零基础到短视频上线》一书的相关章节。
FFmpeg开发笔记(十三)Windows环境给FFmpeg集成libopus和libvpx