UIScrollView使用方法详解 (ScrollView半屏滚动)

UIScrollView 详解

UIScrollView全解
最近看到一篇10年的老帖讨论几年Scroll的半屏滚动效果,正好闲来无事,对Scroll进行了比较详细的整理实现,文章后半部分实现了用基础方法实现的解决方案

基础知识

- (void)createScrollView{
    _scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame];
    UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"image"]];
    imageView.userInteractionEnabled = YES;
    //imageview对象添加到scrollview上
    [_scrollView addSubview:imageView];
    
    //设置scrollview内容的尺寸
    _scrollView.contentSize = imageView.bounds.size;
    //设置内容的偏移量,contentOffset参照contentSize的坐标系
    _scrollView.contentOffset = CGPointMake(1000, 500);
    //设置是否回弹
    _scrollView.bounces = YES;
    
    //设置内容的边距
    _scrollView.contentInset = UIEdgeInsetsMake(10, 10, 10, 10);
    //设置是否可以滚动
    _scrollView.scrollEnabled = YES;
    //是否可以滚动到内容的顶部(点击状态栏)
    _scrollView.scrollsToTop = YES;
    
    //按页滚动
    _scrollView.pagingEnabled =YES;
    
    //是否显示水平和垂直方向的指示器
    _scrollView.showsHorizontalScrollIndicator = YES;
    _scrollView.showsVerticalScrollIndicator = YES;
    //设置指示器的样式
    _scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
    
    //设置代理
    _scrollView.delegate = self;
    
    CGFloat imageWidth = imageView.frame.size.width;
    
    //设置最小和最大缩放比例
    _scrollView.minimumZoomScale = WIDTH / imageWidth;
    _scrollView.maximumZoomScale = 1.5;
    
    
    [self.view addSubview:_scrollView];
    
    //给UIImageView添加手势
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageViewTapGesture:)];
    tap.numberOfTapsRequired = 2;
    [imageView addGestureRecognizer:tap];
}

代理使用

UIScrollView 有自己的代理方法,在代理方法中有相当全面的调用时机,借用代理方法可以制作多种,scrollerView的高级使用

#pragma mark - UIScrollViewDelegate
//只要发生滚动,就会调用该方法
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
//    NSLog(@"scrollview滚动");
}                                               // any offset changes

//只要zoomScale发生变化,就会调用该方法
- (void)scrollViewDidZoom:(UIScrollView *)scrollView{
    NSLog(@"发生缩放");
} // any zoom scale changes

// called on start of dragging (may require some time and or distance to move)
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    NSLog(@"开始拖动");
}
// called on finger up if the user dragged. velocity is in points/millisecond. targetContentOffset may be changed to adjust where the scroll view comes to rest
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
    NSLog(@"将要结束拖动");
}
// called on finger up if the user dragged. decelerate is true if it will continue moving afterwards
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    NSLog(@"拖动结束");
}

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{
    NSLog(@"将要开始减速");
}   // called on finger up as we are moving
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    NSLog(@"减速结束");//停止滚动
}      // called when scroll view grinds to a halt

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView{
    NSLog(@"滚动动画结束");
} // called when setContentOffset/scrollRectVisible:animated: finishes. not called if not animating

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
    //返回可以进行缩放的子视图
    return scrollView.subviews[0];
}     // return a view that will be scaled. if delegate returns nil, nothing happens
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view {
    NSLog(@"将要开始缩放");

} // called before the scroll view begins zooming its content
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale{
    NSLog(@"缩放结束");
    NSLog(@"%@", view);

#if 0
    //恢复原来大小的时候,可能存在问题
    if(scale < 1.0){
        CGPoint center = view.center;
        center.y = HEIGHT / 2;
        view.center = center;
    }
#else
    if (view.frame.size.width > WIDTH) {
        scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
    }else{
        [UIView animateWithDuration:0.5 animations:^{
            scrollView.contentInset = UIEdgeInsetsMake((HEIGHT - view.frame.size.height) / 2, 0, 0, 0);
        }];
    }
    
    
#endif
    
} // scale between minimum and maximum. called after any 'bounce' animations

- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView{
    //scrollToTop = YES,才会调用该方法
    //返回YES,可以滚动到顶部;NO 不可以
    return YES;
}   // return a yes if you want to scroll to the top. if not defined, assumes YES
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView{
    NSLog(@"滚动到顶部");
}      // called when scrolling animation finished. may be called immediately if already at top

拓展使用 —— ScrollView制作仿乐乎半屏滚动效果

对于ScrollView的半屏滚动,由于PagEnable打开以后只能根据scrollView本身的高宽进行按页滚动,实现原理主要是调用DidScroll代理方法,对内容进行跟踪滚动,可以实现任意距离跟踪滚动,希望有所帮助

123.gif
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        rateDistance = 380;
        _imagetViewArr = [[NSMutableArray alloc]init];
        self.delegate = self;
        self.contentOffset = CGPointMake(0, 0);
        
    }
    return self;
}

-(void)setImagetViewArr:(NSMutableArray *)imagetViewArr
{
    _imagetViewArr = imagetViewArr;
    [self creatMainview];
}

-(void)creatMainview
{
    self.contentSize = CGSizeMake(self.frame.size.width * _imagetViewArr.count, self.frame.size.height);
    moverate = 0;
    NSLog(@"%lu",(unsigned long)_imagetViewArr.count);
    self.pagingEnabled = YES;
    self.showsHorizontalScrollIndicator = NO;
    self.showsVerticalScrollIndicator = NO;
    [self SetImagerView];
    
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    UITouch * evt = [touches anyObject];
    CGPoint point = [evt locationInView:self];
    CGFloat wide = self.frame.size.width;
    CGFloat x1 = self.contentOffset.x + wide;
    CGFloat x2 = self.contentOffset.x - wide;
    if(point.x - moverate >= self.frame.size.width * 0.79 && point.x < self.frame.size.width * 7)
    {
        [UIView animateWithDuration:0.2 animations:^{

            self.contentOffset = CGPointMake(x1, 0);
                [self scrollViewDidScroll:self];
        } completion:^(BOOL finished) {
        }];
    }
    else if(point.x - moverate <= self.frame.size.width * 0.21 && point.x > self.frame.size.width*0.25)
    {
        [UIView animateWithDuration:0.2 animations:^{
           self.contentOffset = CGPointMake(x2, 0);
                [self scrollViewDidScroll:self];
        } completion:^(BOOL finished) {
           
        }];
    }
    
    [self scrollViewDidScroll:self];
}

-(void)SetImagerView
{
    ImageXarr = [[NSMutableArray alloc]init];
    
    int ii = (int)_imagetViewArr.count;
    for (int i = 0 ; i < ii; i++) {
        UIImageView * imageView = [[UIImageView alloc]initWithFrame:CGRectMake(self.frame.size.width / _imagetViewArr.count * i, 0, self.frame.size.width * 0.6  , self.frame.size.width * 0.5)];
        imageView.center = CGPointMake((self.frame.size.width*0.6)/2 * (2 * i + 1.67) , self.frame.size.height/2.0);
        //设置背景
        CALayer * layer = [imageView layer];
//        边框
//        layer.borderColor = [[UIColor blackColor]CGColor];
//        layer.borderWidth = 5;
//        阴影
        layer.shadowColor = [[UIColor blackColor]CGColor];
        layer.shadowOffset = CGSizeMake(10, 5);
        layer.shadowRadius = 10;
        layer.shadowOpacity = 0.5;
        
//        layer.cornerRadius = 40;
//        layer.masksToBounds = YES;
        
        imageView.backgroundColor = [UIColor redColor];
        [imageView sd_setImageWithPreviousCachedImageWithURL:_imagetViewArr[i] placeholderImage:[UIImage imageNamed:@"arrow"] options:2 progress:^(NSInteger receivedSize, NSInteger expectedSize) {
            
        } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
           
//            float reat = image.size.height / image.size.width;
            
           // imageView.frame = CGRectMake(imageView.frame.origin.x, imageView.frame.origin.y, imageView.frame.size.width, imageView.frame.size.height * reat);
           
        }];
        
        
        
        
        imageView.tag = i + 100;
        //[_imagetViewArr addObject:imageView];
        [self addSubview:imageView];
    };
    
    [self scrollViewDidScroll:self];
}

-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat rate;
    CGFloat reduce;
    
    reduce = moverate - scrollView.contentOffset.x;
    
    moveNum += reduce;
    //NSLog(@"%f",reduce);
    for (int i = 0 ; i < _imagetViewArr.count; i++) {
        
        UIView * view = [self viewWithTag:100 + i];
        CGFloat distance = fabs(scrollView.contentOffset.x + self.frame.size.width/2  - view.center.x);
        
        CGFloat ratex = view.center.x - reduce * 0.4;
        
        view.center = CGPointMake(ratex,view.center.y);
        
        if (distance >= rateDistance)
            rate = 0.7;
        else
            rate =  (rateDistance - distance*0.2) / (rateDistance ) ;
       
        view.transform = CGAffineTransformMakeScale(rate, rate);
    }
       moverate = scrollView.contentOffset.x;
    
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容