UIScrollView 平滑划动处理

在iOS开发中,实现UIScrollView平滑划动至关重要。常见策略包括一次性加载所有子视图或采用轮询加载三页视图,前者资源消耗大,后者可能出现卡顿。推荐针对页面数量和资源大小选择适当方法,如使用延迟加载优化。文中提到一种更优的解决方案,通过内容延迟加载确保平滑体验,同时介绍了两种实际应用技巧:一种是动态添加和删除页面,另一种是保持三个页面的滚动状态,如同‘木板搭桥’的游戏过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       iOS开发经常会用到UIScrollView,而能够平滑的展示划动效果,是至关重要的。比较常用的方法有两种:

      1)将所有的scrollview子页面都add到scrollview中,这样可以平滑滑动,但占用资源加多,并且初始化加载比较慢。

      2)使用三个页面View,在滑动过程中如指针轮询那样交替使用。优点是占用内存少,但如果单个页面比较大,经常会在划动到中间位置的时候,出现卡顿,很影响用户体验性。

    

      第一种方法就不多讲解,如果页面不多,并且每个页面加载的资源也比较少,那么建议采用第一种方式。如果页面比较多,资源比较大,则建议采用延迟加载的方式。


 更优的方法,请查看:《优化——UIScrollView通过内容延迟加载以达到平滑滑动。


      现在UIScrollView使用有两种方法:一种是App Dev里面的Sample,建立一个包含页面数据的数组,划动的同时,不断添加和删除其他页。而另外一种是定义三个页面,划动过程中,类似与木板搭桥过河游戏一样,prev->current->next->prev,只需重新加载新载入的页面。

1、创建UIScrollView和三个自定义的View:

    //***********************************UIScrollView***********************************/
    scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 54, TOP_BIG_IMAGE_WIDTH, TOP_BIG_IMAGE_HEIGHT)];
    scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
	self.scrollView.contentSize = CGSizeMake(numberOfPages * self.scrollView.frame.size.width, 
                                             self.scrollView.frame.size.height);
    self.scrollView.delegate = self;
    scrollView.autoresizesSubviews = YES;
    scrollView.pagingEnabled = YES;
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.scrollsToTop = NO;
    [selfView addSubview:scrollView];

三个自定义View。函数setPageContentWithPageView:(CustomView *)pageView withPageNumber:(NSInteger)pageNumber,是对customview进行更新操作的代码。

    prevPageView = [[CustomView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.frame.size.width,
                                                                self.scrollView.frame.size.height)];
    currentPageView = [[CustomView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.frame.size.width,
                                                                   self.scrollView.frame.size.height)];
    nextPageView = [[CustomView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.frame.size.width,
                                                                self.scrollView.frame.size.height)];
    CGFloat pageWidth = self.scrollView.frame.size.width;
    CGFloat pageHeight = self.scrollView.frame.size.height;
    
    currentPageView.frame = CGRectMake(currentPage * pageWidth, 0, pageWidth, pageHeight);
    [self setPageContentWithPageView:currentPageView withPageNumber:currentPage];
    
    //第一页
    if (currentPage == 0)
    {
        prevPageView.frame = CGRectZero;
        nextPageView.frame = CGRectMake(((currentPage + 1) * pageWidth), 0, pageWidth, pageHeight);
        
        if (numberOfPages - 1 >= currentPage + 1)
        {
            [self setPageContentWithPageView:nextPageView withPageNumber:currentPage + 1];
        }
    }
    //最后一页
    else if (currentPage == numberOfPages - 1)
    {
        prevPageView.frame = CGRectMake(((currentPage - 1) * pageWidth), 0, pageWidth, pageHeight);
        nextPageView.frame = CGRectZero;
        [self setPageContentWithPageView:prevPageView withPageNumber:currentPage - 1];
    }
    else
    {
        prevPageView.frame = CGRectMake(((currentPage - 1) * pageWidth), 0, pageWidth, pageHeight); 
        nextPageView.frame = CGRectMake(((currentPage + 1) * pageWidth), 0, pageWidth, pageHeight);
        [self setPageContentWithPageView:prevPageView withPageNumber:currentPage - 1];
        [self setPageContentWithPageView:nextPageView withPageNumber:currentPage + 1];
    }
    
    [self.scrollView addSubview:currentPageView];
    [self.scrollView addSubview:prevPageView];
    [self.scrollView addSubview:nextPageView];

	CGPoint offset = CGPointMake(currentPage * self.scrollView.frame.size.width, 0);
    [self.scrollView setContentOffset:offset animated:NO];

2、在- (void)scrollViewDidScroll:(UIScrollView *)sender方法中进行页面更新。

#pragma mark -
#pragma mark UIScrollViewDelegate Methods

- (void)scrollViewDidScroll:(UIScrollView *)sender
{
    CGFloat pageWidth = self.scrollView.frame.size.width;
    NSInteger page = floor((self.scrollView.contentOffset.x - pageWidth/2) / pageWidth) + 1;
    
    //  已经是第一页再往向前翻页,或者已经是最后一页再往后翻页。
    if (currentPage == page || page < 0 || page >= numberOfPages)
    {        
        return;
    }
    else
    {
        //先赋值,防止scrollView在执行线程后还未执行currentPage = page,导致不断进入该段代码区执行 
        NSInteger prevPage = currentPage;
        currentPage = page;
        
        //防止用户快速滑动,出现因线程未加载完,出现空百夜
        self.scrollView.userInteractionEnabled = NO;
        //线程处理,使得加载动作不会阻塞主线程而出现卡顿。注意,不加afterDelay:0.1,线程会立刻执行,卡顿会出现。
        [self performSelector:@selector(refreshPageViewAfterPaged:)
                   withObject:[NSNumber numberWithInteger:prevPage]
                   afterDelay:0.1];
    }
}

函数refreshPageViewAfterPaged是页面的更新操作判断。

- (void)refreshPageViewAfterPaged:(NSNumber *)prevPageNumber
{
    NSAutoreleasePool *pool  = [[NSAutoreleasePool alloc] init];
    
    self.scrollView.userInteractionEnabled = YES;
    
    CGFloat pageWidth = self.scrollView.frame.size.width;
    CGFloat pageHeight = self.scrollView.frame.size.height;

    NSInteger prevPage = [prevPageNumber integerValue];
    //页面向后滑动一页
    TopPicView *tempPageView = nil;
    if (currentPage - 1 == prevPage)
    {
        tempPageView = currentPageView;
        currentPageView = nextPageView;
        nextPageView = prevPageView;
        prevPageView = tempPageView;
        
        prevPageView.frame = CGRectMake(((currentPage - 1) * pageWidth), 0, pageWidth, pageHeight);
        currentPageView.frame = CGRectMake(currentPage * pageWidth, 0, pageWidth, pageHeight);
        
        if (currentPage == (numberOfPages - 1))
        {
            nextPageView.frame = CGRectZero;
        }
        else
        {
            nextPageView.frame = CGRectMake(((currentPage + 1) * pageWidth), 0, pageWidth, pageHeight);
			//页面更新操作的实质代码:
            [self setPageContentWithPageView:nextPageView withPageNumber:currentPage + 1];
        }
        
        
    }
    else if (currentPage + 1 == prevPage)
    {
        tempPageView = currentPageView;
        currentPageView = prevPageView;
        prevPageView = nextPageView;
        nextPageView = tempPageView;
        
        currentPageView.frame = CGRectMake(currentPage * pageWidth, 0, pageWidth, pageHeight);
        nextPageView.frame = CGRectMake(((currentPage + 1) * pageWidth), 0, pageWidth, pageHeight);
        
        if (currentPage == 0)
        {
            prevPageView.frame = CGRectZero;
        }
        else
        {
            prevPageView.frame = CGRectMake(((currentPage - 1) * pageWidth), 0, pageWidth, pageHeight);
            [self setPageContentWithPageView:prevPageView withPageNumber:currentPage - 1];
        }
    }

    [pool release];
}


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值