2019独角兽企业重金招聘Python工程师标准>>>

触摸响应链UIResponder

UIView继承自UIResponder(响应链类),继承了相应的响应链方法:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(nullable NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEstimatedPropertiesUpdated:(NSSet * _Nonnull)touches NS_AVAILABLE_IOS(9_1);// Generally, all responders which do custom press handling should override all four of these methods.// Your responder will receive either pressesEnded:withEvent or pressesCancelled:withEvent: for each// press it is handling (those presses it received in pressesBegan:withEvent:).// pressesChanged:withEvent: will be invoked for presses that provide an analog value// (like thumbsticks or analog push buttons)// *** You must handle cancelled presses to ensure correct behavior in your application.  Failure to// do so is very likely to lead to incorrect behavior or crashes.- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);- (void)motionBegan:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
- (void)motionEnded:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);

其中touches开头的方法是触摸事件相关的方法;presses开头的方法,是iOS9加入的给iPhone6s等支持Deep Press功能的设备使用的相关方法;motion开头的则是给设备的陀螺仪和加速传感器使用的方法,用于获取晃动等事件。

细心的朋友可能会发现,UIViewController(后面简称VC) 和 UIView 同样继承自UIResponder,这样是为了方便UIViewController 处理他的view属性的响应事件,我们也就不用继承UIView重写他的响应链来处理VCView的响应链了,VCView默认将响应链穿给自己的VC,在VC中处理就可以了。

触摸事件

触摸事件可以通过触摸链响应,也可以使用UIGesture(手势类)来响应。今天我们的例子中用了比较原始的响应链方式。

XXXSegmentView.m

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{[super touchesBegan:touches withEvent:event];
}- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{[super touchesEnded:touches withEvent:event];UITouch* touch = [touches anyObject];    CGPoint point = [touch locationInView:self];    NSInteger detla = self.frame.size.width / self.number;    NSInteger touchNumber = point.x / detla;    self.selected = touchNumber;//    [self setNeedsLayout];[self setSelectItemAtIndex:touchNumber animate:YES];
}

解释 touchesBegan是手指按下事件的方法,这里按下我们不做响应,单写了super方法调用父类方法,还是那句话,父类方法可能是空的不需要调用,单这是一个好习惯,可以避免一些因为继承类不调用父类方法造成的BUG。

touchesEnded是手指抬起事件的方法,首先touches这个集合中的UITouch对象,对应的就是触摸的手指。我们用anyObject取出其中之一,用locationInView:方法获取触摸点的位置。这个CGPoint是一个C中的结构体类型,只有x,y两个属性表示位置。

接下来我们根据Label的数量(self.number)来计算每个label的间隔,用总宽度除以个数。

NSInteger detla = self.frame.size.width / self.number;

接下来计算我们触摸的位置,在第几个区域

NSInteger touchNumber = point.x / detla;

这个touchNumber便是我们触摸的按钮的index。

接下来我们调用setSelectItemAtIndex方法来响应触摸这个Label的事件

- (void)setSelectItemAtIndex:(NSUInteger)idx animate:(BOOL)animated
{    self.idx = idx;[self.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {        if ([obj isKindOfClass:[UILabel class]]) {            UILabel* label = obj;            if (self.selected + 981 == label.tag) {label.textColor = self.tintColor;}            else{label.textColor = self.baseColor;}}}];
//这里是我们下方的那根线,移动的动画,下面详细说[UIView animateWithDuration:0.2 animations:^{        UILabel* label = (UILabel*)[self viewWithTag:idx + 981];[self.selectView setFrame:CGRectMake(label.frame.origin.x - self.leftAndRightLineEdge, label.frame.size.height + label.frame.origin.y   + 10, label.frame.size.width + self.leftAndRightLineEdge*2, 2)];}];
}

解释 每一次触摸,我们都需要遍历所有的Label,将选中的,也就是self.selected + 981 == label.tag的Label改变他的颜色。

UIView动画基础

我们在上面代码中,调用self.selectView这个属性,是这么定义的

@interface

@property (nonatomic, strong) UIView* selectView;

@implementation

- (UIView *)selectView
{    if (!_selectView) {_selectView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 2)];[self addSubview:_selectView];_selectView.backgroundColor = self.tintColor;}    return _selectView;
}

这个View在第一次调用self.selectView的时候会初始化,第二次调用时候,_selectView已经初始化过了,就不会再执行初始化方法了。

注意,关于getter和setter的内容,我们就不细说了,新手只要知道,当前的版本的编译器,自动为@property添加了@synthesize(合成)语句,所以iOS6以后,代码中很少见到

@synthesize selectView = _selectView;

这样的写法了,因为编译器自动帮你做了。所以_selectView是内部变量,单不要直接这样调用,而应该在除了- (UIView *)selectView这个getter方法外的地方,使用self.selectView来调用。

我们再来看看上面触摸代码中的动画代码:

  [UIView animateWithDuration:0.2 animations:^{        UILabel* label = (UILabel*)[self viewWithTag:idx + 981];[self.selectView setFrame:CGRectMake(label.frame.origin.x - self.leftAndRightLineEdge, label.frame.size.height + label.frame.origin.y   + 10, label.frame.size.width + self.leftAndRightLineEdge*2, 2)];}];

解释 先使用viewWithTag:方法获取Label,注意这里返回的是UIView类,所以需要使用(UILabel*)进行强行类型转换。

UIView animateWithDuration:animations: 这个方法,是iOS4.0加入的简化版的补帧动画方法。在这个block中去改变一个UIView的frame,系统则会根据传入的Duration(单位:秒),来自动完成补间动画,类似于Flash中的补间动画。

如果不在animateWithDuration中改变view的frame,view则会直接变为新的frame,则不会有中间改变的动画过程了,是不是很简单。

最后self.leftAndRightLineEdge这是一个CGFloat浮点型数值,用来控制下面线两端超出Label的长度,我们demo中第二个例子中这个数值为20。

这样,我们的最终效果就完成。

转载于:https://my.oschina.net/caijunrong/blog/643715

iOS开发-关于自定义控件很值得一看的文章( 三)相关推荐

  1. iOS开发-关于自定义控件很值得一看的文章(一)

    2019独角兽企业重金招聘Python工程师标准>>> 简介 本文将是一个关于Cocoa Touch中UIKit框架的自定义控件系列教程,我们将从基础开始,由浅入深,分析讲解自定义控 ...

  2. 【转自猫扑】被别人破解的一个男人日志。很值得一看!

    [转自猫扑]被别人破解的一个男人日志.很值得一看! 7月7日  我知道我不算帅哥,但曾经有人看我满月的照片时,也说过我左边的鼻孔很偶像派.  8月30日  独守空房,让人只能浪费:妻妾成群,让人懂得节 ...

  3. iOS开发技巧-国际化(Localization),只看一篇就够了

    转:https://www.jianshu.com/p/f8edd7b7a217 本文主要涉及iOS的国际化,网上虽然有很多相关的文章,但是仔细阅读下来感觉都不太全面,因此重开一篇总结,记录项目中遇到 ...

  4. 华为boss力荐公司高层看的一篇文章,很长很经典 很值得一看

    今天是 22 岁的最后一天.几个月前,我从沃顿商学院毕业,用文凭上"最高荣誉毕业"的标签安抚了已经年过半百的老妈,然后转头辞去了毕业后的第一份工作,跟一家很受尊敬的公司.还有 15 ...

  5. 一个爬虫的故事:这是人干的事儿?,很值得一看!

    爬虫原理 我是一个爬虫,每天穿行于互联网之上,爬取我需要的一切. 说起来还要感谢HTTP协议,因为它,全世界的网站和浏览器才能够连接通信,而我也是借助HTTP协议,获取我想要的数据. 我只需要伪装成一 ...

  6. 打造先进的SOA应用 -- 很值得一看

    在开始阅读本文之前,我想先建议你能给自己做一个调查,已明确自己阅读此文的初衷,并能帮助你更好地与此文互动.大家都知道,通常到周末的时候如果你有机会带小孩出去吃饭,为了激励一下他,你就会问他/她:'想要 ...

  7. 【转】前端开发值得一看的文章

    其实这篇文章不是这里的,只是,后台很傻B地进不了了.也不知道是什么乱七八糟的问题.先写在这里,当做这么久没更新的偷懒好了.(而且,挑出来的这些都是精华呢!),大家各取所需吧: 1. 默认Web字体样式 ...

  8. oracle优化查询前几条,一个查询优化的分析调整全过程!很值得一看

    Web翻页优化实例 提交时间: 2004-6-18 15:37:49      回复    发消息 环境: Linux version 2.4.20-8custom (root@web2) (gcc ...

  9. iOS开发—音视频入门学习必看

    音视频学习从零到整–(2) 音视频学习从零到整–(3) 音视频学习从零到整–(4) 音视频学习从零到整–(5) 音视频学习从零到整–(6) 音视频学习从零到整–(7) 一.音频基础复习 1.1 声音的 ...

最新文章

  1. 关于学习Python的一点学习总结(4->成员资格->list->列表操作)
  2. 协议地址结构_通信之路——用最简洁的文字告诉你互联网协议TCP/IP
  3. Linux内核省电社区,Linux 内核社区补丁对比
  4. python3打开文件的代码_Python3 对文件操作
  5. pc端常见布局样式总结(针对常见的)
  6. LeetCode 16 最接近的三数之和
  7. ASP.NET Core开发常见“坑”
  8. C++中的4种类型转换方式
  9. 面对锁等待难题,数仓如何实现问题的秒级定位和分析
  10. 如何实现实时文本过滤
  11. pe安装uefi linux,华硕U盘装机维护系统v2017 WIN10PE UEFI ISO版
  12. SQLite数据库使用(sqlite3 c++)
  13. 计算机科学与技术基础与核心,浅谈计算机科学与技术专业核心课程教学
  14. MongoDB——explain执行计划详解
  15. 在腾讯,有多少技术Leader在写代码?
  16. 使用Java实现简单的家庭记账程序
  17. 6691. 【2020.06.05省选模拟】六道剑「一念无量劫」
  18. pgbackrest配置监控、冗余策略
  19. 中文情感分析 (Sentiment Analysis) 的难点在哪?现在做得比较好的有哪几家?
  20. echarts 其他样式 折线 重叠_echarts 同一div同时显示饼图和折线图且两图联动 望大佬赐教...

热门文章

  1. 麻雀虽小五脏俱全的Vue拉勾项目,看看应该有帮助
  2. Java基础-hashMap原理剖析
  3. SpringBoot如何使用拦截器
  4. Apache POI导出Excel
  5. 《Android 3D游戏开发技术宝典——OpenGL ES 2.0》——2.4节文件I/O
  6. asm-3.3.1.jar详解 (转)
  7. 程序员应该知道的一些很cool网站
  8. [转载]Validation of viewstate MAC failed异常的原因及解决方法
  9. SpringCloud Sleuth + zipkin 实现微服务链路追踪功能
  10. idm 假冒_IDM出现假冒序列号问题解决