iOSマルチキャスト図

10103 ワード

マルチキャストマップはAppでよく使われる展示インタフェースで、主にUIscrollViewとUIpageControlが使用されています.難点は2つあります.1つはタイマー自動ローテーションで、1つは手動操作後に定器自動ローテーションに影響しないことです.

一、達成する効果


效果动图gif

二、論理分析


まず、轮播図は何枚かの画像を轮播する必要があります.scrollViewに対応する画像を何枚か置きます.ここでは3枚にします.画像の大きさの幅はScrollViewのframeと同じで、ページをめくるのに便利です.
そして、最初から3枚目になると、1枚目にジャンプしてループを実現する必要がありますが、スムーズであることを保証するには、scrollViewのcontentOffsetを(0,0)に直接設定することはできません.解決策は、scrollViewの最後にImageViewをもう1枚追加し、最初の画像を上に置くことです.そうすると、4枚目のImageView(ビジュアル効果は最初の画像)に輪番放送されたときにscrollViewのcontentOffsetを(0,0)に設定すると、ビジュアル効果がスムーズになります
第三に、2方向に輪番する必要があるので、scrollViewの先頭にImageViewを追加し、3枚目の画像を載せ、ここに輪番したときにscrollViewのcontentOffsetを最後から2枚目のimageViewに設定する位置を設定します.
以上、3枚の画像の輪番を実現するには、ScrollViewのcontentSizeの幅は5枚の画像幅、1枚目のImageViewは3枚目の画像、最後の1枚のImageViewは1枚目の画像、その他は順番に画像を置く.以上で実現できるのは指がスライドする輪播,自動輪播と指がスライドした後の自動輪播のやや複雑な機能であるが,核心原理はやはり上の原理である.直接コードをつけて、もっと味が合います

三、コード分析


UIscrollView、NStimer、およびUIPコントロールの追加
@property (nonatomic)UIScrollView *scrollView;
@property(nonatomic,strong)UIPageControl * pageController;// 
@property(nonatomic,strong)NSTimer * timer;// 

いくつかのマクロを定義
#define imageCount 3// 
// 
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
// 
#define kScreenHeight [UIScreen mainScreen].bounds.size.height

コントロールを初期化し、画像を追加します.
// 
self.timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
// scrollView
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 250)];
self.scrollView.contentSize = CGSizeMake((imageCount + 2)*kScreenWidth, 0);
self.scrollView.pagingEnabled = YES;
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.bounces = NO;
self.scrollView.scrollEnabled = YES;
self.scrollView.contentOffset = CGPointMake(1*kScreenWidth, 0);
self.scrollView.delegate = self;
[self.view addSubview:self.scrollView];
// 
for (int i = 0; i < imageCount+2; i++) {
    if (i == 0) {
        UIImageView * imageV = [[UIImageView alloc] initWithFrame:CGRectMake(i*kScreenWidth, 0, kScreenWidth, 250)];
        [self.scrollView addSubview:imageV];
        imageV.image = [UIImage imageNamed:@"13.jpg"];
    } else if(i == imageCount + 1){
        UIImageView * imageV = [[UIImageView alloc] initWithFrame:CGRectMake(i*kScreenWidth, 0, kScreenWidth, 250)];
        [self.scrollView addSubview:imageV];
        imageV.image = [UIImage imageNamed:@"11.jpg"];
    }else{
        UIImageView * imageV = [[UIImageView alloc] initWithFrame:CGRectMake(i*kScreenWidth, 0, kScreenWidth, 250)];
        [self.scrollView addSubview:imageV];
        imageV.image = [UIImage imageNamed:[NSString stringWithFormat:@"1%d.jpg",i]];
    }
}
// scrollView page
self.pageController = [[UIPageControl alloc] init];
[self.view addSubview:self.pageController];
self.pageController.frame = CGRectMake(kScreenWidth/2 - 50, 250 - 20, 100, 25);
self.pageController.numberOfPages = imageCount;
self.pageController.pageIndicatorTintColor = [UIColor whiteColor];
self.pageController.currentPageIndicatorTintColor = [UIColor cyanColor];
self.pageController.currentPage = 0;

ScrollViewをスライドさせる場合、ページコントロールPageControlの変更を設定したり、最後の1枚と最初のImageViewでジャンプを設定したりすることは、エージェントメソッドで実現できます.エージェントUIscrollViewDelegateに従う
ScrollViewがスライドしている限り歩くエージェントメソッドでPageControlの変更を設定する
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
    // scrollView , page
    CGFloat scroll = scrollView.contentOffset.x/kScreenWidth;
    NSInteger number = (NSInteger)scroll;// 
    if (number == imageCount+1||(number == imageCount&&scroll - number > kScreenWidth/2)) {// 
        self.pageController.currentPage = 0;
    }else if (number == 0||(number == 0&&scroll-number < kScreenWidth/2)){// 
        self.pageController.currentPage = imageCount- 1;
    }else{
        if (scroll - number>kScreenWidth/2) {
            self.pageController.currentPage = (number-1)+1;
        }
        if (scroll - number<=kScreenWidth/2) {
            self.pageController.currentPage = (number-1);
        }
    }
}

スライド終了減速時の代理メソッドでオフセットを設定する
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    if (self.scrollView.contentOffset.x == (imageCount + 1)*kScreenWidth) {// ImageView
        self.scrollView.contentOffset = CGPointMake(kScreenWidth, 0);
    }else if (self.scrollView.contentOffset.x == 0*kScreenWidth) {// ImageView
        self.scrollView.contentOffset = CGPointMake(imageCount*kScreenWidth, 0);
    }
}

以上は手動でのマルチキャストを実現し,以下は自動マルチキャストの実現である.
自動マルチキャストの実現は主にタイマのタイミングイベントで機能を実現する.まずグローバル変数を作成し、表示されるピクチャのコーナーマークを制御し、繰り返し使用します.
static NSInteger pageNumber = 0;// 

タイマのタイミングイベントメソッドを実装します
-(void)timerAction{
    if(pageNumber == imageCount){// , 
        pageNumber = 0;
        // 
        self.scrollView.contentOffset = CGPointMake(kScreenWidth,0);
        // 
        [UIView animateWithDuration:0.5 animations:^{
            self.scrollView.contentOffset = CGPointMake((pageNumber+2)*kScreenWidth,0);
        }];
    }else if(pageNumber == 0){
        // 
        [UIView animateWithDuration:0.5 animations:^{
            self.scrollView.contentOffset = CGPointMake((pageNumber+2)*kScreenWidth,0);
        }];
    }else {
        [UIView animateWithDuration:0.5 animations:^{
            self.scrollView.contentOffset = CGPointMake((pageNumber+2)*kScreenWidth,0);
        }];
    }
    pageNumber++;
}

上記の方法におけるpageNumberの理解:pageNumber=0の場合、現在は1枚目の図が表示されますが、2枚目の図が表示されます.1に等しい場合は現在2枚目の図が表示され、3枚目の図が表示されます.pageNumber=3の場合、最後のImageView、すなわち1枚目の図が表示されるので、pageNumberを0に設定し、ループ表示するので、Scrollviewのオフセットを(kScreenWidth,0)、すなわち1枚目の図に設定し、このとき2枚目の図を表示することで、ループ自動マルチキャストが完了する
手動マルチキャストと自動マルチキャストが実現されました.これから実現するのは自動+手動マルチキャストです.
考え方:ScrollViewが次の図に自動的に放送されるようになったとき、私はちょうど手動で操作しました.そうすると、ScrollViewは自動で次の図に再生されますか、それとも手動で次の図にスライドしますか.衝突を感じる.ここでの処理は、手動操作を行うと自動再生が停止し、手動操作が完了して自動再生がオンになるので衝突しません
まず2つの方法を書き、タイマーをオンにする方法とタイマーを終了する方法
-(void)beginAction{// 
    //    
    if (self.timer) [self stopAction];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
}
-(void)stopAction{// 
    [self.timer invalidate];
    self.timer = nil;
}

まず,ScrollViewがドラッグされ始めたときにタイマーを停止し,ScrollViewがドラッグを開始するエージェントメソッドを実現する.
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    // 
    [self stopAction];
}

ドラッグ完了時にタイマーをオンにすると、ScrolViewの減速終了のプロキシメソッドにタイマーをオンにするコードを追加できます(このプロキシメソッドには書いてありますが、直接コードを1行追加すればいいです).
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    if (self.scrollView.contentOffset.x == (imageCount + 1)*kScreenWidth) {// ImageView
        self.scrollView.contentOffset = CGPointMake(kScreenWidth, 0);
    }else if (self.scrollView.contentOffset.x == 0*kScreenWidth) {// ImageView
        self.scrollView.contentOffset = CGPointMake(imageCount*kScreenWidth, 0);
    }
    // 
    [self beginAction];
}

指スライドが終了すると、自動再生が開始され、タイマのタイミングイベントメソッド(timerAction)が機能し、どの図を再生するかはpageNumber=数で決定されるが、タイマ停止時のpageNumberの値により、どの図が表示されたかを正確に指示できないため、再び手動でスライドした場合、pageNumberの値を同期して変更すべきである.ScrollViewの減速終了エージェントメソッドにコードを追加する
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    if (self.scrollView.contentOffset.x == (imageCount + 1)*kScreenWidth) {// ImageView
        self.scrollView.contentOffset = CGPointMake(kScreenWidth, 0);
    }else if (self.scrollView.contentOffset.x == 0*kScreenWidth) {// ImageView
        self.scrollView.contentOffset = CGPointMake(imageCount*kScreenWidth, 0);
    }
    // 
    [self beginAction];
    // 
    NSInteger number = (NSInteger)self.scrollView.contentOffset.x/kScreenWidth;
    if (number == imageCount+1){// ( )
        pageNumber = 0;
    }else if(number == 0){// scrollView ( )
        pageNumber = imageCount -1;
    }else{
        pageNumber = number - 1;
    }
}

これで大功を成し遂げた

四、demoダウンロード


gitHubダウンロードアドレス

五、補充


今日面接に行って、面接官は、ピントを落とさないで、ずっと滑って、頭を滑って、滑らないと言っていました.このような状況はどのように処理しますか?当時は答えられず、考えもせず、家に帰って以前のDEMOを遊んだが、確かにそんなことは考えていなかった.しかし、検証を重ね、解決策を見つけた.一番簡単ではないかもしれません.先に出して、味わってください.
考え方:scrollViewが動いている限り、scrollViewDidScrollエージェントメソッドを実行します.オフセット量が最大と最小の瞬間を捉え、その瞬間にscrollViewのオフセット量を対応する位置に設定すればいいのです.ずっとドラッグしていた状態がscrollViewWillBeginDraggingエージェントメソッドを歩いたことに気づきましたが、scrollViewDidEndDraggingエージェントメソッドを歩いていません.scrollViewDidEndDraggingエージェントメソッドを歩いたら、ドラッグは終わります.したがって、ドラッグした状態を記録するグローバル変数を設定できます.ドラッグした状態で、オフセット量の最大値と最小値をscrollViewDidScrollの方法でキャプチャできます.具体的には以下の実装を参照してください.
まず、ドラッグ状態かどうかを記録するアトリビュート、ブール値タイプを追加します.
@property(nonatomic,assign)BOOL isDraging;// 

もちろん、初期値を与えるべきです.これは私の習慣です.
    self.isDraging = NO;

この属性に値を付けます
scrollViewのドラッグ開始エージェントメソッドで、isDragingプロパティの値をYESに変更し、ドラッグ状態に入ったことを示します.
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    // 
    [self stopAction];
    self.isDraging = YES;
}

scrollViewがドラッグを終了するエージェントメソッドでは、isDragingプロパティの値をNOに変更し、ドラッグを終了した状態を示します.
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    self.isDraging = NO;
}

次にプロキシメソッド:scrollViewDidScrollに2つの判定を加えます.すなわち、ドラッグ状態で最大値にスライドし、最小値にスライドしたときに、最初のピクチャ位置(この位置オフセット量は1ピクチャの幅)と最後のピクチャ位置(この位置オフセット量は3ピクチャの幅オフセット量位置)にジャンプします.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
    if (self.isDraging&&self.scrollView.contentOffset.x == 0) {
        self.scrollView.contentOffset = CGPointMake(imageCount*kScreenWidth, 0);// ImageView( )
    }
    if (self.isDraging&&self.scrollView.contentOffset.x == (imageCount + 1)*kScreenWidth) {
        self.scrollView.contentOffset = CGPointMake(kScreenWidth,0);// 
    }
    ...
}

これで問題は解決した.ご指導を歓迎します.