zoukankan      html  css  js  c++  java
  • UIScrollview 无缝循环滚动实现

    头文件:

    #import 
    
    @class ArticleViewController;
    
    @interface ArticleScrollViewController : UIViewController  {
            //不使用数组,看起来更明了,为了节省内存同时还要看起来无缝,3个view最好
    	ArticleViewController	*article1;
    	ArticleViewController	*article2;
    	ArticleViewController	*article3;
    }
    
    @end

    实现:

    #import "ArticleScrollViewController.h"
    #import "ArticleViewController.h"
    #import "ViewSwitcher.h"
    @implementation ArticleScrollViewController
    
    // vieDidLoad函数不重要,只要初始化了三个view并放在uiscrollview里面,正确设定uiscrollview的content size就行了
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        UIScrollView *scrollView = (UIScrollView *)self.view;
        scrollView.contentSize = CGSizeMake(self.view.frame.size.width*3, self.view.frame.size.height);
        CGRect frame = self.view.frame;
        frame.origin.y = 0.0f;
        NSInteger article2Index = [ViewSwitcher getInstance].currentArticleIndex;
        NSInteger article1Index = article2Index - 1;
        article1Index = article1Index < 0 ? [ViewSwitcher getInstance].articleCount - 1 : article1Index;
        article1Index = article1Index >= [ViewSwitcher getInstance].articleCount ? 0 : article1Index;
        NSInteger article3Index = article2Index + 1;
        article3Index = article3Index < 0 ? [ViewSwitcher getInstance].articleCount - 1 : article3Index;
        article3Index = article3Index >= [ViewSwitcher getInstance].articleCount ? 0 : article3Index;
    
        article1 = [[ArticleViewController alloc] initWithArticleIndex:article1Index];
        [article1.view setFrame:frame];
    
        article2 = [[ArticleViewController alloc] initWithArticleIndex:article2Index];
        frame.origin.x += self.view.frame.size.width;
        [article2.view setFrame:frame];
    
        article3 = [[ArticleViewController alloc] initWithArticleIndex:article3Index];
        frame.origin.x += self.view.frame.size.width;
        [article3.view setFrame:frame];
    
        [scrollView addSubview:article1.view];
        [scrollView addSubview:article2.view];
        [scrollView addSubview:article3.view];
    
        CGPoint p = CGPointZero;
        p.x = scrollView.frame.size.width;
        [scrollView setContentOffset:p animated:NO];
        [article2 reloadData];
    }
    #pragma mark -
    #pragma mark UIScrollViewDelegate
    
    #define SET_FRAME(ARTICLEX) x = ARTICLEX.view.frame.origin.x + increase;\
                                if(x < 0) x = pageWidth * 2;\
                                if(x > pageWidth * 2) x = 0.0f;\
                                [ARTICLEX.view setFrame:CGRectMake(x, \
                                    ARTICLEX.view.frame.origin.y,\
                                    ARTICLEX.view.frame.size.width,\
                                    ARTICLEX.view.frame.size.height)]
    //将三个view都向右移动,并更新三个指针的指向,article2永远指向当前显示的view,article1是左边的,article3是右边的
    - (void)allArticlesMoveRight:(CGFloat)pageWidth {
        //上一篇
        article3.articleIndex = article1.articleIndex - 1;
        if (article3.articleIndex < 0) {
            article3.articleIndex = [ViewSwitcher getInstance].articleCount - 1;
        }
        [article1 reloadData];
        ArticleViewController *tmpArticleViewController = article3;
        article3 = article2;
        article2 = article1;
        article1 = tmpArticleViewController;
    
        float increase = pageWidth;
        CGFloat x = 0.0f;
        SET_FRAME(article3);
        SET_FRAME(article1);
        SET_FRAME(article2);
    }
    - (void)allArticlesMoveLeft:(CGFloat)pageWidth {
        article1.articleIndex = article3.articleIndex + 1;
        if (article1.articleIndex >= [ViewSwitcher getInstance].articleCount) {
            article1.articleIndex = 0;
        }
        [article3 reloadData];//[article2 resetView];[article3 resetView];
        ArticleViewController *tmpArticleViewController = article1;
        article1 = article2;
        article2 = article3;
        article3 = tmpArticleViewController;
    
        float increase = -pageWidth;
        CGFloat x = 0.0f;
        SET_FRAME(article2);
        SET_FRAME(article3);
        SET_FRAME(article1);
    }
    /*
     循环滚动
     每次滚动后都将scrollview的offset设置为中间的一页
     若本次滚动是向前一页滚动,则把三页都向后放置,最后一页放到开头
     若本次滚动是向后一页滚动,则把三页都向前放置,第一页放到末尾
     */
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)theScrollView
    {
        CGFloat pageWidth = theScrollView.frame.size.width;
        // 0 1 2
        int page = floor((theScrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
        if(page == 1) {
            //用户拖动了,但是滚动事件没有生效
            return;
        } else if (page == 0) {
            [self allArticlesMoveRight:pageWidth];
        } else {
            [self allArticlesMoveLeft:pageWidth];
        }
        CGPoint p = CGPointZero;
        p.x = pageWidth;
        [theScrollView setContentOffset:p animated:NO];
        [article1 resetView];
        [article3 resetView];
    }
    #pragma mark -
    #pragma mark dealloc
    - (void)didReceiveMemoryWarning {
        // Releases the view if it doesn't have a superview.
        [super didReceiveMemoryWarning];
    
        // Release any cached data, images, etc. that aren't in use.
    }
    
    - (void)viewDidUnload {
        [super viewDidUnload];
        // Release any retained subviews of the main view.
        // e.g. self.myOutlet = nil;
        [article1    release];article1 = nil;
        [article2    release];article2 = nil;
        [article3    release];article3 = nil;
    }
    
    - (void)dealloc {
        [article1    release];
        [article2    release];
        [article3    release];
        [super dealloc];
    }
    
    @end

    这里的雕虫小技主要在于:

    以手指向右拖动为例,【屏幕】指的是scorllview的显示区域

      article1 article2 article3
               【屏幕】

      拖动以后成这样:

     article1 article2 article3
    【屏幕】

    将article3放到第一个去(设定article3的frame),这是屏幕还显示的是article1的内容
    article3 article1 article2
    【屏幕】
    

    将屏幕移到中间:使用setContentOffset,禁用动画,这样骗过人眼

    article3 article1 article2
              【屏幕】
    

    最后更新指针顺序:

    article1 article2 article3
              【屏幕】
    

    无缝循环实现了。

    by gqzhu

    http://www.dreamingwish.com/dream-2011/uiscrollview-infinite-loop-scrolling.html

  • 相关阅读:
    LeetCode 965. Univalued Binary Tree
    LeetCode 961. N-Repeated Element in Size 2N Array
    LeetCode 832. Flipping an Image
    语法设计——基于LL(1)文法的预测分析表法
    简单的词法设计——DFA模拟程序
    LeetCode 905. Sort Array By Parity
    LeetCode 804. Unique Morse Code Words
    【原创】用事实说话,Firefox 的性能是 Chrome 的 2 倍,Edge 的 4 倍,IE11 的 6 倍!
    【新特性速递】新增单标签页模式,界面更加清爽!
    【新特性速递】重构表格列锁定代码,只有一个横向滚动条,更加现代化!
  • 原文地址:https://www.cnblogs.com/ydhliphonedev/p/2480256.html
Copyright © 2011-2022 走看看