零基础iOS开发学习日记—控件篇—UIScrollView

841 阅读4分钟

开头

UIScrollView

实际用处

  • 图片轮播 — 图片缩放显示

基础用法

  • 使用UIScrollView有两个需要注意的尺寸自身frame和内容的contentSize
  • frame指的是UIScrollView的自身位置和大小,理解为一个框,是用户可见的范围
  • contentSize指的是放入UIScrollView的内容大小,是用户可移动的最大范围
  • UIScrollView的缩放显示,需要用到代理方法,而代理方法,在使用过程中可以理解为控件的监听方法,当控件在某一个状态中需要调用这个函数内的方法已实现某种需求
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"WechatIMG8793"]];
UIScrollView *scrollView = [UIScrollView new];

self.imageView = imageView;
self.scrollView = scrollView;
//设置代理
scrollView.delegate = self;
scrollView.backgroundColor = [UIColor redColor];
scrollView.frame = [UIScreen mainScreen].bounds;

imageView.frame = scrollView.frame;

[imageView sizeToFit];

//scrollView的缩放比例
scrollView.maximumZoomScale = 2.0;
scrollView.minimumZoomScale = 0.1;
//scrollView的内容大小
scrollView.contentSize = imageView.frame.size;
//scrollView横竖指示器
scrollView.showsVerticalScrollIndicator = NO;
scrollView.showsHorizontalScrollIndicator = NO;

[scrollView addSubview:imageView];
[self.view addSubview:scrollView];
  • 缩放代理方法,返回需要改变的控件,UIScrollView会进行根据最大最小缩放比例自动缩放
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    NSLog(@"zooming...");
    return self.imgView;
}
  • 但是在实际开发中,往往需要图片在屏幕中间位置,就需要对内容坐标进行偏移,就需要在UIScrollView结束缩放的状态进行操作。函数中的viewscrollView中的内容
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
    CGFloat offsetY = (scrollView.bounds.size.height - view.frame.size.height) * 0.5;
    offsetY = offsetY < 0 ? 0 : offsetY;
    CGFloat offsetX = (scrollView.bounds.size.width - view.frame.size.width) * 0.5;
    offsetX = offsetX < 0 ? 0 : offsetX;
    //设置间距
    scrollView.contentInset = UIEdgeInsetsMake(offsetY, offsetX, 0, 0);
}

图片轮播器

  • 使用UIScrollView实现图片轮播器的思路从以下几个方面考虑
  1. 如何实现内容,通过图片拼接作为scrollView内容
  2. 如何实现轮播,利用UIScrollViewpagingEnabled进行翻页效果的显示,也就是当内容到达下一个scrollView的自身的范围,会产生翻页的效果
  3. 如何获取页数,利用UIpageControl进行页数显示
  4. 如何实现自动滚动,利用定时器,设置scrollView偏移量,进行自动滚动
UIScrollView *scrollView = [UIScrollView new];
//指示器
UIPageControl *pageControl = [UIPageControl new];
//指示器的数量
pageControl.numberOfPages = 6;
//设置当前的页数
pageControl.currentPage = 0;
//指示器的颜色
pageControl.pageIndicatorTintColor = [UIColor redColor];
//指示器当前的颜色
pageControl.currentPageIndicatorTintColor = [UIColor blueColor];
//固定imageView的宽高
CGFloat imgW = 336;
CGFloat imgH = 448;

//创建6个imageView
for (int i = 0; i < 6; i++) {
    UIImageView *imageView = [UIImageView new];
    NSString *imageName = [NSString stringWithFormat:@"img_%02d", i];
    imageView.image = [UIImage imageNamed:imageName];
    //计算x坐标
    CGFloat imgX = i * imgW;
    imageView.frame = CGRectMake(imgX, 0, imgW, imgH);
    imageView.contentMode = UIViewContentModeScaleAspectFit;
    //根据x坐标的不同,拼接到scrollView中
    [scrollView addSubview:imageView];
}
scrollView.backgroundColor = [UIColor blackColor];
//scrollView的大小,要等于一页的imageView
scrollView.frame = CGRectMake(50, 50, imgW, imgH);
//contentSize的宽度要等一所有imageView合起来的宽度
scrollView.contentSize = CGSizeMake(imgW * 6, 0);
//实现分页效果
scrollView.pagingEnabled = YES;
//隐藏滚动指示器
scrollView.showsHorizontalScrollIndicator = NO;
//设置代理
scrollView.delegate = self;

[self.view addSubview:scrollView];
//页数指示器要添加到主界面上,与scrollView同级,否则会随着内容滚动
pageControl.frame = CGRectMake(100, 498, 200, 20);
[self.view addSubview:pageControl];

self.pageControl = pageControl;
self.scrollView = scrollView;
  • 关于页数获取,在正常使用的时候,用户希望在划动过程中就看到页数的变化,显得不会生硬
  1. UIscrollView偏移量的概念指的是,scrollView的内容移动的位置相对于最开始显示的位置
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    //1.获取当前滚动方向的偏移值
    CGFloat offsetX = scrollView.contentOffset.x;
    //优化,用已经偏移了的值,加上半页的宽度,在切换的过程中,只要拖动了半页,就会使pageControl变化
    offsetX = offsetX + (scrollView.frame.size.width * 0.5);
    //2. 用x方向的偏移值 / 每一页的宽度,取商,就是当前的页码(索引)
    int page = offsetX / scrollView.frame.size.width;
    self.pageControl.currentPage = page;
}
  • OC中主要有三种定时器,这里使用NSTimer,使用scheduledTimerWithTimeInterval...创建的定时器,会自动添加到消息循环中,模式为默认的NSDefaultRunLoopMode
  • 利用pageControl的页数进行偏移量的计算,然后进行设置
self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(scrollImage) userInfo:nil repeats:YES];
//定时器方法
- (void)scrollImage {
    //1.获取当前的页码
    NSInteger page = self.pageControl.currentPage;
    //2.页码是否到了最后一页,设置页码为0;如果没有到达,则页码+1
    if(page == self.pageControl.numberOfPages - 1)
    {
        page = 0;
    }
    else
    {
        page++;
    }
    //3.用每页的*(页码+1)== 计算下一页的contentOffset.x
    CGFloat offsetX = page * self.scrollView.frame.size.width;
    //4.设置scrollView的新偏移值
    [self.scrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
}
  • 由于定时器NSTimer优先级的问题,当使用其他控件的时候,会影响定时器的效果,所以要修改定时器的优先级与控件优先级一致
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:self.timer forMode:NSRunLoopCommonModes];
  • 而在开始拖动scrollViewWillBeginDragging时,要将定时器关闭,在结束拖动scrollViewDidEndDragging的时候,重新将定时器打开
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    //停止计时器
    //调用停止计时器,这个计时器就不可以再重用了,下次必须创建新的计时器对象
    [self.timer invalidate];
    //需要初始化这个计时器指针
    self.timer = nil;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    //重新打开计时器
    self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(scrollImage) userInfo:nil repeats:YES];
    //修改计时器的优先级与控件一样
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    [runLoop addTimer:self.timer forMode:NSRunLoopCommonModes];
}

总结

  • 综上,UIScrollView的使用,需要特别注意一下几个点
  1. 自身的frame大小与contentSize大小,前者决定了可见范围,后者决定了可移动的范围
  2. 偏移值,决定了相对显示的范围
  3. UIScrollView各个状态的代理函数