前面在做东西的时候都用到了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中代码如下:

    MyViewController *myViewController = [[MyViewController alloc] init];
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(, , , )]; 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中相应的位置添加如下代码去执行按钮点击时要回调的方法:

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

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

     //注册委托回调
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

 //接受block块
@property (nonatomic, strong) ButtonWillAndDidBlock willBlock;
@property (nonatomic, strong) ButtonWillAndDidBlock didBlock;
@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控制台输出的日志:

IOS开发之自定义Button(集成三种回调模式)的更多相关文章

  1. iOS开发 跳转场景的三种方式

    iOS开发 跳转场景的三种方式 2012年10月17日, 15:32 假设A跳转到B,三种方法:1.按住ctrl键,拖动A上的控件(比如说UIButton)到B上,弹出菜单,选择Modal.不需要写任 ...

  2. iOS_Swift初识之使用三种回调方式自定义Button

    最近在学习Swift ,发现青玉伏案大神早期用OC写的一篇博客--IOS开发之自定义Button(集成三种回调模式)  很适合用来熟悉Swift的回调方式,于是我就用Swift翻版了一下,具体实现原理 ...

  3. iOS开发之自定义表情键盘(组件封装与自动布局)

    下面的东西是编写自定义的表情键盘,话不多说,开门见山吧!下面主要用到的知识有MVC, iOS开发中的自动布局,自定义组件的封装与使用,Block回调,CoreData的使用.有的小伙伴可能会问写一个自 ...

  4. iOS开发UI篇—Button基础

    iOS开发UI篇—Button基础 一.简单说明 一般情况下,点击某个控件后,会做出相应反应的都是按钮 按钮的功能比较多,既能显示文字,又能显示图片,还能随时调整内部图片和文字的位置 二.按钮的三种状 ...

  5. iOS开发之动画编程的几种方法

    iOS开发之动画编程的几种方法 IOS中的动画总结来说有五种:UIView<block>,CAAnimation<CABasicAnimation,CATransition,CAKe ...

  6. 【朝花夕拾】Android自定义View篇之(四)自定义View的三种实现方式及自定义属性使用介绍

    前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10979161.html],谢谢! 尽管Android系统提供了不少控件,但是有很多酷炫效果仍然 ...

  7. IOS开发中数据持久化的几种方法--NSUserDefaults

    IOS开发中数据持久化的几种方法--NSUserDefaults IOS 开发中,经常会遇到需要把一些数据保存在本地的情况,那么这个时候我们有以下几种可以选择的方案: 一.使用NSUserDefaul ...

  8. iOS开发基础篇-Button基础

    一.简单介绍  UIButton 的功能:响应用户操作.显示文字.显示图片.调整内部图片和文字的位置. 二. UIButton 的状态  UIControlStateNormal :普通状态,为默认情 ...

  9. (OPC Client .NET 开发类库)网上很多网友都有提过,.NET开发OPC Client不外乎下面三种方法

    1. 背景 OPC Data Access 规范是基于COM/DCOM定义的,因此大多数的OPC DA Server和client都是基于C++开发的,因为C++对COM/DCOM有最好的支持.现在, ...

随机推荐

  1. 使用docker toolbox 在windows上搭建统一环境

    1.先下载docker toolbox 以下是下载地址: http://get.daocloud.io/#install-docker-for-mac-windows 2.下载安装 git windo ...

  2. Linux Shell 通配符、元字符、转义符【转帖】

    作者:程默 说到shell通配符(wildcard),大家在使用时候会经常用到.下面是一个实例: 1   1 2 3 4 [chengmo@localhost ~/shell]$ ls a.txt  ...

  3. ajax的一些笔试面试题

    1. 什么是ajax,为什么要使用Ajax(请谈一下你对Ajax的认识) 什么是ajax: AJAX是“Asynchronous JavaScript and XML”的缩写.他是指一种创建交互式网页 ...

  4. C#:获取设备电量相关信息

    更多资源:http://denghejun.github.io [DllImport("kernel32.dll",EntryPoint="GetSystemPowerS ...

  5. 解决读取iphone名称中文乱码问题

    #region 解决中文乱码 Ethan 2016-01-06 [DllImport("iTunesMobileDevice.dll", CallingConvention = C ...

  6. ENode通信层性能测试结果

    测试环境 两台笔记本网线直连,通过测速工具(jperf)测试,确定两台电脑之间的数据传输速度可以达到1Gbps,即千兆网卡的最大速度.两台电脑硬件配置如下: client服务器,CPU:Intel i ...

  7. shell日常案例(一)

      序   在linux平台下开发,我们经常会接触到一些任务性质的工作,而处理方式多样化.现积累各个案例.   清理近7天的数据   日志文件越来越大,我们需要及时的去做清理工作.配合工具:find, ...

  8. .NET陷阱之六:从枚举值持久化带来大量空间消耗谈起

    好长时间没有写博文了,今天继续. 这次跟大家分享的内容起因于对一个枚举值列表的序列化,下面简化后的代码即能重现.为了明确起见,我显式指定了枚举的基础类型. // 定义一个枚举类型. public en ...

  9. 干货!表达式树解析"框架"(3)

    最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html 这应该是年前最后一篇了,接下来的时间就要陪陪老婆孩子了 关于表达 ...

  10. Windows Azure Storage (23) 计算Azure VHD实际使用容量

    <Windows Azure Platform 系列文章目录> 对于A系列和D系列的虚拟机来说,使用的是普通存储. 普通存储的存储资源,是按照每GB每月计费的.Microsoft Azur ...