UIScrowllView

1 UIScrollView的基本使用

在storyboard和xib中UIScrollView的背景色background是不显示的,运行时会显示
这个按钮不用设置尺寸
temp2.center = CGPointMake(20, 30);这样赋值
 
UIScrollView要想能够滚动,必须设置contentSize
设置内容的大小(决定了滚动范围)
是否能够滚动
不能响应用户的点击事件,不能与用户交互
这是UIView里的属性,任何一个控件都可以通过这个属性让当前的控件不能被点击,不会响应用户的操作.例如
按钮,但按钮还有一个enable属性也可以控制按钮能不能用
UIScrollView没有enable这个属性
为什么按钮UIButton有enable属性呢?因为来自它的父类UIControll
仅仅是禁止scrollView的滚动,里边的按钮子控件依然可以点击
scrollView不仅无法滚动,里面的按钮也无法点击
只能通过enable = NO达到失效状态,设置userInteractionEnabled = NO,并不能让按钮达到失效状态
 
 

2 UIScrollView的常见属性

通过initWithImage创建的imageView,它的大小直接就初始化为该图片的大小
 
imageView.frame.size和imageView.bounds.size在这里都可以
 
UIScrollView在滚动的过程中,是里面的内容在动,UIScrollView本身是不动的
 
可以认为是内边距
 
 
Vertical是垂直方向上
Horizontal是水平方向上
在这两个方向上有没有弹簧效果,默认为NO
 
1)有contentSize属性,滚动范围,上面两句代码不管设置YES或NO,都依然会有弹簧效果
2)如果没有contentSzie属性,没有滚动范围,也就是无法滚动,YES,就在该方向上有弹簧效果,NO在该方向上即无滚动效果
这个属性是用来刷新
 
默认是能够滚动的
这样两个方向上就不会显示滚动条
这个是滚动条的样式属性
 
以后想取得scrollView的子控件,不建议通过位置,index来取
实验显示,设置contentSize之前,两个滚动条在数组的的前面,设置contentSize之后,两个滚动条就在数组的后面,让人很捉摸不透,所以不建议通过位置,index来取
怎样避免这种困扰呢?
去掉滚动条.这样scrollView的子控件就仅仅是imageView,能够精确的取到
是不是很机智

3 UIScrollView的常见属性 - contentOffset

内容偏移量,相对左上角来算的
 
偏移量怎么算?
内容左上角和scrollView左上角的差值
偏移量 = scrollView左上角的坐标 - 内容左上角的坐标
 
这样默认的偏移量 x = 0, y = 大的scrollView A y - 小的contentSize B左上角y(见下图分析)(可以参考UIScrollView详细构图里的坐标系)
 
苹果官方推荐用block设置动画
setContentOffset:
时间改不了,是默认的
 
这里的offset的坐标指的是content的左上角,可以在ppt里面模拟进行,到位后再看内容左上角的坐标
只有点击view才会起作用,点击scrollView是不会起作用的
这里的(-100, -200)是将scrollView的左上角作为原点的坐标
(-100, -200)是内容左上角,变成这样,一点view就弹回去了,因为它默认就会让它的偏移量弹回去,这是不合理的偏移量
因为红色框住部位已经是滚动范围的尽头
UIScrollView详细构图:
 
绿色的x和y方向是这样的
之前那样理解虽说结果是对的,但是自己主观假的.正确的理解是上面红的坐标系,而且偏移量是UIScrollView的左上角 - Content的左上角
 

4 UIScrollView的常见属性-contentInset(内边距)

设置内边距(在原来内容的周边,增加内边距,一出现就永远回不去了)
往下一拖,这里有20永远回不去了
内容的上边增加了内边距,只要是内边距就不能来显示内容,内边距就是内部某段距离是不能显示内容的
左边40下边80永远回不去了
右边也是,有160
contentSize和contentInset是分开的
contentInset不影响偏移量
 

5 UIScrollView的delegate

UIButton继承自UIControll,UIControll里有
这个方法,所以UIButton可以使用这个方法
UIControl的子类:
• UIButton
• UIDatePicker
• UIPageControl
• UIRefreshControl
• UISegmentedControl
• UISlider
• UIStepper
• UISwitch
• UITextField
 
UIView的子类:
• ADBannerView
• GLKView
• MKAnnotationView
• MKMapView
• MKOverlayView
• MPVolumeView
• SCNView
• SKView
• UIActionSheet
• UIActivityIndicatorView
• UIAlertView
• UICollectionReusableView
• UIControl
• UIImageView
• UIInputView
• UILabel
• UINavigationBar
• UIPickerView
• UIPopoverBackgroundView
• UIProgressView
• UIScrollView
• UISearchBar
• UITabBar
• UITableViewCell
• UITableViewHeaderFooterView
• UIToolbar
• UIVisualEffectView
• UIWebView
• UIWindow
• WKWebView
 
 
代理能够监听UIScrollView的一些行为
通过代码创建UIScrollView
这里的UIScrollView数组里面是空的,但通过storyboard创建出来的UIScrollView里,一创建出来就有两个滚动条
设置过contentSize过后,滚动条依然没有出现,注意在这里不要使用subviews[index]来获取数组,因为有很多不确定的情况
 
刺头
 
通过storyboard或者xib创建出来的scrollView和通过代码创建出来的scrollView是有区别的
 
1.控制器成为代理

2.要求控制器遵守协议
协议可以写在.h文件当中,但建议尽量写在类扩展里面
协议里面有很多方法声明

3.控制器实现协议里面的方法
方法实现
代理方法一般以scrollView开头
代理方法控制器会自动调用
在scrollView滚动时调用此方法
 

用户即将停止拖拽时调用

用户已经停止拖拽时,有时候它也能监听停止滚动

用户开始拖拽那一刻

停止滚动
没有减速那来的结束减速
如果一松手,即停止就不会调用停止滚动这个方法

 
松手就停止,没有减速
这个就有一个拖拽,松手,减速的过程

开发中:一般这样判断scrollView是否停止滚动
 
代理是id类型,没有限制类型
开发UI的东西,要包含这个头文件
如果敲<UIScrollViewDelegate>不出现,可能没有引入UIKit头文件
 
这就说明代理这个属性是一个弱指针,既然是弱指针,这就意味着小猫没有强指针指着,就会死掉
控制器不会死,有其他强指针指着它,这里再有一个弱指针指着它也没影响,没关系

给🐱一个强指针指着它,
这里的小猫的遵守协议应该写在.h文件当中,写到分类当中就会报警告
因为viewController.m文件中导入的是,若将小猫遵守协议放到它的.m当中,编译器就不会发现它遵守了协议,所以要写在.h文件当中
就可以当代理
证明了任何对象都可以做它的代理,只要遵守协议<UIScrollViewDelegate>
 
一般情况下,控制器就是代理,因为一般控件在控制器里面创建,又作为管家,当代理很合适.
 
为什么用@property(weak, nonatomic)id delegate 这里用weak?
因为一般情况下控制器做代理.
 
好像不是rowViewController,以后还会讲
一旦这个强指针释放,就会依次销毁,不会内存泄露

代理使用的一般规律
•作用:用来监听控件的某些行为
•代理:是控制器对象
•代理:是id类型,并且是弱指针
• 代理协议的格式:控件类名Delegate,比如UIScrollViewDelegate、UITextFieldDelegate
•代理方法:方法名一般是控件名开头,比如UIScrollView的代理方法一般以scrollView开头
 
如何监听控件的行为
• 通过addTarget:
◦ 只有继承自UIControl的控件,才有这个功能
◦ UIControlEventTouchUpInside : 点击事件(UIButton)
◦ UIControlEventValueChanged : 值改变事件(UISwitch、UISegmentControl、UISlider)
◦ UIControlEventEditingChanged : 文字改变事件(UITextField)
• 通过delegate
◦ 只有拥有delegate属性的控件,才有这个功能
 
UITextField两个功能都有
两种方式都可以监听
看这个控件有没有delegate,或者是否继承自UIControl
如果需要监听东西,一般都会有其中一种方式
 
addTarget方法
监听谁的事件,那个控件的事件,就把谁,那个控件传进去
borderStyle是输入框的样式,枚举值,可以去底层看.一共四种.
监听tf的的事件就将tf传进去
这样就可以监听UITextField输入什么内容
 

6 利用UIScrollView实现内容缩放

设置代理有两种方式:
第一种方式:
第二种方式:
 
一般代理方法都是以ScrollView开头的,但是有些代理方法是不是的
当代理检测到捏合手势时,控制器会自动调用这个方法,并且拿到这个方法的返回值,它就知道缩放谁了.代理在这就不是监听,而是帮UIScrollView做一些事情
 
此时还差缩放比例
最大缩放比例
最小缩放比例
你的手指没有碰到imageView依然能进行缩放,为什么,因为代理那个方法返回的是imageView
进行缩放时,实时调用的方法
完成缩放时的比例
 

7 UITextField的代理方法简介

控制器作TextField的代理
遵守协议
代理方法一般以textField开头,
当你不知道返回啥时,先返回YES,返回NO可能出一些问题.
文字改变就会调用该方法
有些控件既能用addTarget监听改变,还有自身的一些方法监听改变
 
YES 即可往里面输入字符,即使YES,也可以往里面加入来控制0不可以输入
NO就不可以输入
作用:
1.监听textField文字的改变
2.禁止用户输入

代理方法:
有BOOL值的
第一,可以监听一些事情
第二,可以告诉控件,你可以干什么,不可以干什么
NSStringFromSize (CGRect Range)将结构体转为字符串
 
 
8 UIScrollView的分页
 


 
这里写0,只代表竖直方向上不可以滚动,不会影响图片会不会显示
如果你想禁止在那个方向上无法滚动,只需写0,就可以禁止
 

 
它是以scrollView的尺寸(宽度)来判断一页的
水平方向竖直方向都可以分页
这种做法只适合引导页,也就是软件更新过后进入软件显示的功能介绍界面’因为这种做法有缓存.
引导页只需将图片的尺寸,设置为跟scrollView的尺寸一样,充满整个屏幕即可
 

 
怎样在分页里面显示小圆点,拖入UIPageControl
UIPageControl控件的height是固定不可改变的37
UISwitch也不可以更改
 
CurentPage 当前所在页的小圆点显示什么颜色
TintColor 其它页显示什么颜色
Pages一共有多少页
Current当前处于第几页(默认)
PageControl不要加入UIScrollView里面,要不然一翻页,PageControl就跟着翻页了
要想控制它的页码的改变,首先拥有它的页码属性
让控制器成为UIScrollView的代理
遵守协议<UIScrollViewDelegate>
 

 
这样,每当完全到下一页,小圆点才会动

四舍五入两种思路:
直接强制类型转换和%.f成整数是不一样的
1) %.f是四舍五入的
2) (int)是直接去掉.后面的数字

这里实现四舍五入的方法:
这样即可实现图片刚翻过半页小圆点就会变化
 
这样即可实现图片翻过整一页小圆点才会变化
 

 
小于等于一张图片时不会显示小圆点:
方法一:
这样小于等于一张图片时,小圆点就不会显示
方法二:
这样写也行,单页就隐藏
 
 

 
如果想更改小圆点的形状,怎么办?
设置页码图片
注意图片的大小,不要太大
 

 
当你点击pageControl右边时,就会跳到下一页,点击左边时,就会跳到上一页,这是它自带的功能
不想用这个功能,关闭这个功能就可以
如果想使用,监听pageControl的value的改变,value改变,控制UIScrollView偏移量,到下一页或者上一页

9 UIScrollView的分页-NSTimer定时器

仅仅是延迟做事情
这是一种方案,但一般不用
 

 
NSTimer
写NO就是不重复,只调用一次
这样写会越界,到page = 5就没有图片显示.加入这句代码

 
这里是代码,让图片滚动,只要发生滚动就会自动调用这个方法,小圆点随之动态改变
 

 
当用户即将拖拽scrollView时,停止定时器
当用户已经结束拖拽scrollView时,开启定时器
这里NSTimer并没有用指针指着它,它也能活,说明它内部有强指针指着它.
原则:能用weak用weak,安全
虽然弱指针死了,会被清空为空指针,我建议赶紧清掉就可以了,这里不清空也是可以的,MJ建议立即清空
 

加载过内容后,开启定时器
 
scheduled:规定的,预定的
返回一个已经定制好任务的timer,返回过后就会自动开始任务.
userInfo 
userInfo里的东西传到@selector所指的方法里面去
即将userInfo传到了nextPage:里面去了

10 UIScrollView的分页06-NSTimer细节

1.NSTimer有一个特点,只要你关掉它了,就再也不能再开启它了,一次性的.停掉它就需要在创建一个新的NSTimer
2.
NSRunLoop多线程的时候会讲
用弱指针,只要指向的那个对象死了,那个弱指针打印出来就是空指针,不会有任何内存泄露问题,空指针是非常安全的
原则:能用弱指针就用弱指针
如果我用的是强指针,另一个指向NSTimer强指针死了,还需要我手动释放这个强指针,麻烦.用弱指针就没有关系
 
UITextView 可以理解为UILabel 和UIScrollView 和 UITextField的结合体
 
线程:用来执行任务的
程序一启动,就会创建一条主线程,一个线程同一时间只能做一件事情
主线程:显示UI界面,刷新UI界面,处理UI界面
当你拖拽红色框时,上面不会滚屏.NSTimer失效
 
因为主线程,在专心的处理ScrollView滚动事件
 
定时器已被NSRunLoop强引用,其实一执行startTimer这个方法里的scheduled那个方法,就已经调用了[NSRunLoop mainRunLoop] addTimer 这个方法,就是将Timer已经添加到了mainRunLoop里去了
这里只是改模式为通用模式
 
将时间切割
这个时刻在处理这个,下一个时刻在处理那个,给人的感觉就是在同一时间处理

11 UIScrollView的分页07-封装分页控件

PageControl改变不了高度
UISwitch也改不了
PageControl不能放在ScrollView里面
 
加载完xib会调用的方法
不建议这种一边遍历数组,一边删除东西,删除一张图片,数组总数就会改变,可能会出现一些莫名其妙的问题,不建议这样做.
让数组中所有的对象都执行removeFromSuperview这个方法
 
封装控件:
1.易用性
2.公共属性,可以无限赋值,重复赋值的问题
 
控制器的复用性是最差的,每个控制器都是来做业务逻辑的,包含了太多功能性的东西,
12 小型轮播广告代码逻辑解析:
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats
创建并返回一个新的NSTimer对象,并安排其在默认模式下,在当前的循环线程里.
 
手动打开定时器
跳到定制器开始的函数
返回一个自动开始执行任务的定时器,自动运行间隔为2秒,这个定时器会做什么事?2秒后控制器调用nextPage:方法,传入参数123,并这样重复的进行下去,除非关闭定时器.
修改NSTimer在NSRunLoop中的模式为:NSRunLoopCommonModes,之前的模式不是这个模式
计算当前的页码
如果页码到最后一页,直接返回第一页
offset是内容content左上角所在的位置,并以动画效果移动该位置
当content内容一滚动,scrollView的代理控制器viewController就会调用这个方法,根据内容的偏移量来计算现在所在的页数.
将所在的页数赋值给pageControl.currentPage,这样小圆点就会根据所在画面的不同,跟着变化
 
然后就会这样循环
画面自己改变,也就是scrollView滚动时调用
 
直到你拖拽图片
跳到stopTimer方法,取消定时器
当用户已经结束拖拽scrollView时,开始定时器
停掉一个NSTimer就需要再创建一个新的NSTimer
开始新的循环
 
 
 
13 封装分页控件详细解析
创建一个xib,里面包含Scroll View和Page Control 
Page Control 可能会拖到Scroll View里面,可以通过调整Page Control 的坐标来调整它的位置
注意把UIView的Class改为CFPageView
 
我试验得到
代码里面没有设置可以分页
xib里面也没有设置,依然可以自动滚动翻页,应该是由于nextPage:这个方法的原因
 
通过类工厂方法加载xib得到xib里面已经布好局的CFPageView
返回一个CFPageView的对象
设置位置坐标
传图片数组数据,通过set方法赋值
这里为什么要赋值给CFPageView的属性
因为CFPageView.m当中的其它方法依然可能用到_imagNames,到时候直接拿去就可以用了
移除所有的之前的imageView数据,每赋值一次就清理一下之前的数据,重新赋值,记住这个方法,让数组中的所有元素都去干这件事
CFPageView匿名分类拥有这个属性
依次取出每一个imageNames,设置frame,并装入scrollView的subViews里去.
取消水平方向上的滚动条
设置内容的范围大小
设置总页数,决定小圆点显示几个
将PageView加入到控制器的view里面去
 
 
一加载完xib就会调用这个方法初始化
单页时自动隐藏
分别给小圆点的两种形态所显示的图片属性赋值,利用kvc方法
手动开始定时器
跳到startTimer这个方法
返回一个已经设置好的自动开始执行的重复执行的定时器
修改它的主线程为通用模式,以达到即使在模拟器上干其他事(操作其他控件)也不会影响到定时器的运行
当执行定时器时,会执行CFPageView的下一页这个方法
根据当前小圆点的所在页数,计算得出下一页的页码
如果页码到达最后一页,也就是和图片的总数相等,则返回第一页,就是page = 0,重新循环
计算出此时页码page所对应的偏移量,并用动画效果实现,达到一个循环.
 
当scrollView滚动时,即会调用该方法,动态计算出小圆点所在当前页,实现小圆点的动态改变
 
当用户即将开始拖拽时,CFPageView调用stopTimer方法
停止,这一点具体看笔记
当用户停止拖拽时,调用CFPageView的startTimer方法
然后又开始循环了
 
关键点:
1 记住设置代理delegate
点击delegate拖拽给PageView
2
引入CFPageView的头文件
3
set方法赋值
将图片名字数组传给CFPageView的imageNames数组,在这里面,设置每一个imageView的frame,并加入subView里面去,并设置好滚动范围,总页数.
4.谁去触发定时器,加载完xib后会自动调用
在这里面初始化一些其他数据,
并开启定时器
14 封装好的分页控件的使用
将这三个文件拖拽进去
传入所需图片
新的图片imageView默认的模式是Scale To Fill ,将图片拉伸至整个imageView
引入头文件,创建pageView,传入数据,即可
posted @ 2015-10-20 14:13  琦灵  阅读(391)  评论(0编辑  收藏  举报