一、目标:

1)

UIScrollView的常见属性

实现滚动缩放

常用的代理方法(后面学习的控件都与代理方法有关)

UIScrollView与UIPageControl的分页

NSTimer的使用,计时器控件周期性执行任务

2)

2.1)什么是UIScrollView?

UI控件 具有缩放 滚动 功能

2.2)为什么会滚动,滚动到哪?

因为:一个屏幕无法显示全部内容

滚动截止:内容结束的地方

2.3)什么在滚动?

scrollview中的内容滚动

2.4)怎么添加scrollview

创建scrollview- 向scrollview中添加子view-限定滚动的范围-注意,滚动范围一定要比原先的scrollview大,而不是比屏幕大 

contentSize的宽高一定要大于scrollview的宽高才会滚动

 

二、scrollview 的常见属性使用

a.@property(weak,nonatomic) UIScrollView*scrollview;

b. _scrollview=[[UIScrollView alloc]initWithFrame:CGRectMake(0,0,100,100)]];

c. _scrollview.contentSize = self.imageview.frame.size;//此处可直接设置大小,也可依据显示内容设置大小

_scrollview.contentSize = CGSizeMake(1024,0)//当高度不希望滚动时,设置为0即可

d.设置显示滚动指示器与否 默认显示

_scrollview.showsVerticalScrollIndicator =NO;

_scrollview.showsHorizontalScrollIndicator = NO;

e.设置弹簧动画效果 默认开启

_scrollview.bounces = YES;

f.即使不设置contentSize 但是在水平和垂直方向上还是可以具备弹簧效果 前提是bounces属性开启

_scrollview.alwaysBounceVertical =YES;

_scrollview.alwaysBounceHorizontal =YES;

g.没有设置contentInset的时候,imageview就会默认停留在初始位置 变相的增加了滚动的范围 top left bottom right

_scrollview.contentInset= UIEdgeInsetsMake(10,20,30,40);

h.contentOffset offset 偏移量,滚动到了某个位置

_scrollview.contentOffset =CGPointMake(100,100);

偏移量的意思是当scrollview移动时与显示在scrollview的视图之间所产生的x、y之间的差值

 

三、总结scrollView不能滚动的几点原因

1、contentSize的大小小于scrollview的size

2、UserInteractorEnable 用户交互被禁止

3、_scrollview.scrollEnabled =NO

 

四、如何对offset进行手动修改

CGPoint offset = _scrollview.contentOffset;

offset.x+=10;

offset.y+=10;

如何在赋值的时候显示动画效果

 [UIView animateWithDuration:0.4 animations:^{

  _scrollview.contentOffset = offset;

}];

或者可以直接调用 setContentOffset 

[_scrollview setContentOffset :offset animated:true];

观察在滚动的时候contentSize 和scrollview.frame.size 的变化

NSLog(@"contentSize :%@ scrollview.frame.size:%@",NSStringFromCGSize(_scrollview.contentOffset),NSStringFromCGSize(_scrollview.frame.size));

注意CGSize和CGPoint在转换成NSString 的时候,使用方式

 NSStringFromCGSize/ NSStringFromCGPoint

 

五、显示喜马拉雅电台的布局(使用ScrollView和浮动在上方的View)

注意如何让顶部的View属于浮动状态而不是跟着ScrollView滚动:将View放置在ScrollView上方

获取最底下的Y值

CGFloat Ymax =CGRectGetMaxY(imageview.frame);

 

六、代理的使用

在viewController控制器中,ScrollView在滚动的时候,不停的对外发消息 用代理(发消息监听)

什么情况下使用代理?

自己不能做 或者 自己不适合做的时候

以猪肉销售商和猪肉养殖户为例,

首先;销售商 需要制定一个标准: “我需要什么样的猪肉” 

其次: 双方认可协议签订

最后: 当销售商清楚知道自己缺猪肉的情况下,就会发出消息通知养殖户

 

这其中涉及的就是代理的过程

制定协议-遵守协议、设置代理、实现相互认识 view.delegate=self; -通知代理*(调用代理放法);

总结:使用代理的时候:

1、制定协议以及代理方法,定义代理属性

2、遵守协议,实现对应的代理方法

3、制定协议者在适当的时候调用代理方法

@protocol HuiDelegate <NSObject>

@property(nonatomic,weak) id<HuiDelegate> delegate

执行方法

-(instancestype)initWithFrame:(CGRect )frame

{

if (self=[super initWithFrame:frame ])

{

//creat button....

[btn addTraget:self action:@selector(didClick) forControlEvent:UIControlEventTouchUpInside];

[self addSubview :btn]

}

-(void)didClick

{

if([self.delegate respondsToSelector:@selector(needPigMeet)])

{[self.delegat needPigMeet];}}

注意为什么使用self.delegate respondsToSelector :@selector(needPigMeet)]

如果不写的话,一旦delegate中的代理方法没有设置 系统就会直接崩溃 返回的是一个BOOL值

以上都是“猪肉养殖户”执行的操作:

    定义代理-定义代理属性 - 设置代理方法

 

在ViewController中:

#import“Hui.h”

@interface ViewController()<HuiDelegate>

Hui *h =[[Hui alloc ]initWithFrame:CGRectMake(0,0,200,200)];

h.delegate = self;

-(void) neegPigMeet

{

NSLog(@"ok you got meet");

}

以上都是“猪肉销售商”执行的代理过程  

     遵守协议-设置代理-实现代理方法

 

(一般情况下,我们的是看不到代理内部设置的过程,但是我们会知道代理内部有哪些方法,然后进行实现)

 

七、监听scrollview内部 -联系delegate

 

1、遵守代理协议

@interface ViewController ()<UIScrollViewDelegate>

2、设置代理

_scrollview.delegate =self;

3、实现协议方法

-(void) scrollViewDidScroll:(UIScrollView *)scrollView

{

NSLog (@"滚动的时候调用:%@",NSStringFromCGPoint(scrollview.contentOffset));

}

-(void)scrollViewWillBeginDragging:(UIScrollView*)scrollview

{

NSLog(@"开始拖拽的时候调用");

}

-(void)scrollViewDidEndDragging:(UIScrollView *)scrollview willDecelerate :(BOOL)decelerate

{

NSLog(@" 停止拖拽的时候调用");

}

 

八、图片的缩放 (viewForZoomingInScrollView) 代理(内部)

1、遵守协议

<UIScrollViewDelegate>

2、设置代理

_scrollview.delegate=self;

3、设置缩放倍数的范围

_scrollview.minimumZoomScale =0.3;

_scrollview.maxmumZoomScale =3;

4 、设置代理方法

-(UIView*) viewForZoomingInScrollView:(UIScrollView *)scrollview

{

return _imageview;//注意,返回的是你要执行缩放操作的view

}

-(void)scrollViewWillBeginZooming:(UIScrollView*)scrollview withView:(UIView *) view

{

NSLog(@"scrollview开始缩放");

}

-(void)scrollViewDidEndZooming:(UIScrollView *)scrollview withView:(UIView*)view

{

NSLog(@"scrollview结束时调用");

}

 

九、图片轮播器(计时器和scrollview 和pageControl使用)

1、首先实现图片的scrollview滚动

实现图片的拼接

[_imageNamed setImage:[UIImage imageNamed:[NSString stringWithFormat:"img_%02d",i+1]]];

 

2、其次添加pageControl

关于pageControl的一些属性

  a、numberOfPages

  b、currentPage

  c、currentPageIndicatorTintColor

  d、PageIndicatorTintColor

_pageControl.currentPage =1;(注意 currentPage的范围是从0-numberOfPages-1)

_pageControl.numberOfPages=4;

_pageControl.currentPageIndicatorTintColor =[UIColor redColor];//设置当前page指示器颜色

_pageControl.PageIndicatorTintColot =[UIColor grayColor];//设置page指示器未指示的颜色属性

 

3、结合pageControl和scrollView(contentOffset变化判断currentPage的变化)

减速的时候,就是一张页面播放完毕的时候

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollview

{

_pageControl.currentPage = (scrollview.contentOffset.x)/(scrollview.frame.size.width);

}

 

4、自动滚动时候使用Timer(shceduledTimerWithInterval方法)

a、定义NSTimer属性

@property(nonatomic,strong)NSTimer *timer;

b、初始化Timer

c、使用Timer 的scheduledTImerWithInterval 方法

-(void)initTimer

{

_timer =[NSTimer scheduledTimerWithInterval:2//时间间隔

targer:self //控制器

selector:@selector(didclick) //执行的方法

userInfo:nil //用户自定义参数

repeats:true];// 是否重复

[timer fire];//[timer invalidate]; //fire的话,不会等待Inteval 直接执行滚动操作 //invalidate  关闭Timer 而且一旦关闭就无法再开启 Timer必须要重新创建才可以

}

 

5、出现一个状况,当在view中再添加一个textView的时候,会发现,一旦textView中进行滚动,轮播中的scrollview将会停止(考虑用户交互优先级 )

改变Timer的用户交互优先级

NSRunLoop *mainrunloop =[NSRunLoop mainRunLoop];

[mainrunloop addTimer:_timer forMode:NSDefaultRunLoopModel];

有两种类型:

NSDefaultRunLoopMode

NSRunLoopCommonModes

很明显Default低一点

 

十、为什么delegate设置属性的时候用weak修饰符?

使用weak是为了防止循环饮用 协议遵守再类扩展名之后

可以自定义两个view 

1、SecondView :

@protocol SecondViewDelegate<NSObject>

@property(nonatomic, weak) id<SecondViewDelegate> delegate;

2、FirstView

@interface FirstView()<SecondViewDelegate>

-(instancetype) initWithFrame:(CGRect)frame

{

if(self=[super initWithFrame:frame])

{

SecondView *secondview =[[SecondView alloc]init];//在firstview中引用secondview

secondview.delegate =self; //将secondview的代理指向firstview 也就是说,secondview对firstview有一个会strong/weak的引用

[self addSubview:secondview];

}

}

3、viewController

FirstView *firstview=[[FirstView alloc]initWithFrame:CGRectMake(0,0,100,100)];

可以通过在双方view的执行方法中加入 

-(void)dealloc

{

NSLog(@"已回收XXview");

}

可以看出 设为strong 的时候,两边view都是强引用,导致一直未被释放

但是设为weak的时候,firstview对secondview是强引用,secondview对firstview是弱引用 最后两个都被释放了

总结:

只要有两个对象相互引用的时候,其中一个必须为weak 否则无法释放,容易造成循环引用