UIScrollView、控件悬停、顶部图下拉放大效果、UITouch事件
UIScrollView的基本属性
- 超出UIScrollView边框的内容会被自动隐藏
- contentSize
- 设置scrollView的contentSize属性,告诉UIScrollView所有内容的尺寸,也就是告诉它滚动范围(最多能滚多远)
- UIScrollView无法滚动的可能原因
- 没有设置contentSize
- scrollEnabled = NO;
- 禁止了触摸事件:userInteractionEnabled = NO
- 如果想要禁止某个方向的滚动,那么就可以直接设置这个方向的contentSize为0
eg:
// 禁止水平方向上滚动
self.scrollView.contentSize = CGSizeMake(0, 500);
contentOffset:(偏移量)
- 记录UIScrollView滚动的位置,也就是内容的左上角和scrollView自身左上角X\Y的差值
- 对于X\Y值,如果内容往左上方滚动,X\Y都是增加,如果内容往右下方滚动,X\Y都是减少
eg:
- 对于X\Y值,如果内容往左上方滚动,X\Y都是增加,如果内容往右下方滚动,X\Y都是减少
// 往下移动64
self.scrollView.contentOffset = CGPointMake(0, -64);
OC语法细节:OC不允许直接修改结构体对象的属性成员变量
contentInset:内边距
- 这个属性能够在UIScrollView的四周增加额外的滚动区域,一般用来避免scrollView的内容被其他控件挡住(比如不被导航条挡住)
eg:
// 顶部多出64的内边距
self.scrollView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
UIScrollView的其他属性
- BOOL bounces
- 设置UIScrollView是否需要弹簧效果
- BOOL scrollEnabled
- 设置UIScrollView是否能滚动
- BOOL showHorizontalScrollIndicator
- 是否显示水平滚动条
- BOOL showsVerticalScrollIndicator
- 是否显示垂直滚动条
- BOOL pagingEnabled
- 是否分页
注意
- 是否分页
iOS7以后,导航控制器会为其中的scrollView的顶部自动添加64的内边距,如果想去掉,可以通过下列属性去掉
tabBarController为间隔区域的bottom添加49
取消自动添加额外滚动区域
self.automaticallyAdjustsScrollViewInsets = NO;
UIScrollView的代理方法
使用方法
首先准守
设置代理
实现代理方法
注意
如果其他类(A类)成为该类中UIScrollView的代理的话,需要将 A类设成Strong,然后它成为当前类中scrollView的代理
常用代理方法为
/**
* 滚动的时候调用
*/
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
}
/**
* 即将开始拖拽的时候调用
*/
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
}
/**
* 结束拖拽的时候调用
*/
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
}
/**
* (减速完毕)停止滚动的时候调用
*/
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
}
scrollView实现内容缩放
// 最大缩放比例
self.scrollView.maximumZoomScale = 2.0;
// 最小缩放比例
self.scrollView.minimumZoomScale = 0.2;
// 同时实现代理方法
// 返回要缩放的内容控件,注意,该内容控件必须是scrollView的子控件
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
// 这个方式是内容缩放的时候调用,通过在该方法中调节内容控件的frame可以使缩放的时候内容控件始终处于scrollView的正中间
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
}
其他方法
// 将scrollView中的所有子控件都执行removeFromSuperview方法
[scrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
ScrollView内部子控件添加约束的注意点
子控件的尺寸不能通过UIScrollView来计算,可以考虑通过以下方式计算
可以设置尺寸为固定值
可以相对于UIScrollView以外的其他控件来计算尺寸
UIScrollView的frame应该通过子控件以外的其他控件来计算
UIScrollView的contentSize的尺寸是通过子控件来计算的
根据子控件的尺寸以及子控件与UIScrollView之间的间距
ScrollView的一些特效效果
控件悬停效果
当scrollView往上拖拽到某一个位置的时候,控件(testView)悬停到某一个位置,当scrollView往下拉的时候,该控件(testView)又随着scrollView一起移动
实现思路:
当往上拖拽到一定位置的时候(通过计算偏移量来判断),让该控件(testView)添加到self.view上,并设置该控件(testView)的frame固定到该位置,当scrollView再次往回拖拽到该位置的时候,再让该控件(testView)再添加到scrollView上,成为scrollView的子控件
顶部图片下拉放大效果
当scrollView往下拖拽的时候,让顶部的imageView按比例放大
实现思路:
当scrollView往下拖拽的时候,通过偏移量来修改顶部imageView的transform(缩放的transform)。
eg:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat imageH = self.imageView.frame.size.height;
CGFloat offsetY = scrollView.contentOffset.y;
// 该判断是实现scrollView内部的子控件悬停效果
if (offsetY >= imageH) {
// 将红色控件添加到控制器的view中,设置Y值为0
CGRect redF = self.redView.frame;
redF.origin.y = 0;
self.redView.frame = redF;
[self.view addSubview:self.redView];
}else{
// 将红色控件添加到scrollView中,设置Y值为图片的高度
CGRect redF = self.redView.frame;
redF.origin.y = 140;
self.redView.frame = redF;
[self.scrollView addSubview:self.redView];
}
// 实现下拉放大顶部图片效果
CGFloat scale = 1 - (offsetY / 70);
scale = (scale >= 1) ? scale : 1;
self.imageView.transform = CGAffineTransformMakeScale(scale, scale);
}
分页指示器UIPageControl
UIPageControl
颜色指示器
tintColor: 其他页面的指示颜色
currentPageIndicatorTintColor:当前页颜色
numberOfPages:总共有多少页
注意 一定不要将UIPageControl放到UIScrollView里,这样的话UIScrollView的内容拖动的时候容易把UIPageControl拖走
pageControl.hidesForSinglePage = YES;
当只有一页时自动隐藏pageControl
关于UIScrollView不能响应UITouch事件的解决办法
原因是:UIView的touch事件被UIScrollView捕获了。
解决办法:让UIScrollView将事件传递过去。于是最简单的解决办法就是加一个UIScrollView的category。这样每个用到UIScrollView的地方只要导入这个category就可以直接响应相关的touch事件了。
#import "UIScrollView+UITouch.h"
@implementation UIScrollView (UITouch)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[[self nextResponder] touchesBegan:touches withEvent:event];
[super touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[[self nextResponder] touchesMoved:touches withEvent:event];
[super touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[[self nextResponder] touchesEnded:touches withEvent:event];
[super touchesEnded:touches withEvent:event];
}
@end