1、自定义UIView
// MyControl.h
#import <UIKit/UIKit.h>
@interface MyControl : UIView
@property(strong,nonatomic) UIView *aView;
@end
// MyControl.m
#import "MyControl.h"
@implementation MyControl
//重写initWiyhFrame方法
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.aView=[[UIView alloc] initWithFrame:CGRectMake(50, 50, 50, 50)];
// self.aView=[[UIView alloc] initWithFrame:frame];
self.aView.backgroundColor=[UIColor redColor];
[self addSubview:self.aView];
}
return self;
}
@end
2、在自定义控件中加入动作
// MyControl.h
#import <UIKit/UIKit.h>
@interface MyControl : UIView
@property(strong,nonatomic) id target;
@property(assign,nonatomic) SEL action;
-(void)addTarget:(id) target action:(SEL)action;
@end
// MyControl.m
#import "MyControl.h"
@implementation MyControl
-(void)addTarget:(id)target action:(SEL)action
{
self.target=target;
self.action=action;
}
//重写触摸方法
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//调用方法
[self.target performSelector:self.action];
}
@end
//测试:
- (void)viewDidLoad {
[super viewDidLoad];
self.myControl=[[MyControl alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
self.myControl.backgroundColor=[UIColor yellowColor];
[self.myControl addTarget:self action:@selector(test)];
[self.view addSubview:self.myControl];
}
-(void)test
{
NSLog(@"我的自定义控件");
}
3、数据回传(代理方式)
代理的实现过程
1、在目标控制器的头文件定义代理和代理对应的方法, 并定义代理属性
#import <UIKit/UIKit.h>
//分别为联系人控制器, 联系人信息模型, 添加联系人控制器
@class ContactViewController, Contact, AddViewController;
//设置代理
@protocol AddViewControllerDelegate <NSObject>
@optional
//声明代理的方法, 定义这个方法在源控制器(也是就代理使用者)
- (void)addViewController:(AddViewController *)addVc DidAddContact: (Contact *)contact;
@end
@interface AddViewController : UIViewController
@property (nonatomic, strong) ContactViewController *contacts;//模型
@property (nonatomic, weak) id<AddViewControllerDelegate> delegate; //定义代理属性
@end
2、当某个事件(比如点击事件后需要传递数据给代理)引发代理事件时, 通知代理, 如果代理有某个方法, 就调用这个方法通知代理
//最好将所有参数封装成模型, 直接给代理传递模型
- (IBAction)add {
//1. 关闭当前控制器(出栈)
[self.navigationController popViewControllerAnimated:YES];
//2. 传递数据给上一级控制器(contactViewController)
//2.1. 通知代理 (调用代理方法)
if ([self.delegate respondsToSelector:@selector(addViewController:DidAddContact:)]) {
//初始化模型并复制
Contact *contact = [[Contact alloc] init];
contact.name = self.nameField.text;
contact.phone = self.phoneField.text;
//给代理传入模型
[self.delegate addViewController:self DidAddContact:contact];
}
}
3、代理遵守协议, 代理接到消息后, 执行代理方法
@interface ContactViewController () <AddViewControllerDelegate>
- (IBAction)logout:(id)sender;
@property (nonatomic, strong) NSMutableArray *contacts;
@end
//add控制器的代理方法
- (void)addViewController:(AddViewController *)addVc DidAddContact:(Contact *)contact
{
//1. 添加模型数据
[self.contacts addObject:contact];
//2. 刷新tableView表格
[self.tableView reloadData];
}
- 总结:
1、联系人列表界面点击加号添加联系人(即将进行控制器的跳转), 调用- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender方法(拿到目标控制器,设置添加控制器的代理为self(也就是源控制器)
2、进行控制器跳转
3、add方法(目标控制器触发代理事件)关闭当前控制器,判断代理联系人控制器有没有实现某个方法, 调用联系人列表的代理
4、代理执行这个代理方法
4、ios事件传递
如上图,iOS中事件传递首先从App(UIApplication)开始,接着传递到Window(UIWindow),在接着往下传递到View之前,Window会将事件交给GestureRecognizer,如果在此期间,GestureRecognizer识别了传递过来的事件,则该事件将不会继续传递到View去,而是像我们之前说的那样交给Target(ViewController)进行处理。
响应者链(Responder Chain)
通常,一个iOS应用中,在一块屏幕上通常有很多的UI控件,也就是有很多的View,那么当一个事件发生时,如何来确定是哪个View响应了这个事件呢,接下来我们就一起来看看。响应者对象(Responsder Object)
响应者对象是能够响应并且处理事件的对象,UIResponder是所有响应者对象的父类,包括UIApplication、UIView和UIViewController都是UIResponder的子类。也就意味着所有的View和ViewController都是响应者对象。第一响应者(First Responder)
第一响应者是第一个接收事件的View对象,我们在Xcode的Interface Builder画视图时,可以看到视图结构中就有First Responder。
这里的First Responder就是UIApplication了。另外,我们可以控制一个View让其成为First Responder,通过实现 canBecomeFirstResponder方法并返回YES可以使当前View成为第一响应者,或者调用View的becomeFirstResponder方法也可以,例如当UITextField调用该方法时会弹出键盘进行输入,此时输入框控件就是第一响应者。事件传递机制
如上所说,,如果hit-test view不能处理当前事件,那么事件将会沿着响应者链(Responder Chain)进行传递,知道遇到能处理该事件的响应者(Responsder Object)。通过下图,我们来看看两种不同情况下得事件传递机制。
左边的情况,接收事件的initial view如果不能处理该事件并且她不是顶层的View,则事件会往它的父View进行传递。initial view的父View获取事件后如果仍不能处理,则继续往上传递,循环这个过程。如果顶层的View还是不能处理这个事件的话,则会将事件传递给它们的ViewController,如果ViewController也不能处理,则传递给Window(UIWindow),此时Window不能处理的话就将事件传递给Application(UIApplication),最后如果连Application也不能处理,则废弃该事件。
右边图的流程唯一不同就在于,如果当前的ViewController是由层级关系的,那么当子ViewController不能处理事件时,它会将事件继续往上传递,直到传递到其Root ViewController,后面的流程就跟之前分析的一样了。
这就是事件响应者链的传递机制,通过这些内容,我们可以更深入的了解事件在iOS中得传递机制,对我们在实际开发中更好的理解事件操作的原理有很大的帮助,也对我们实现复杂布局进行事件处理时增添了多一份的理解。