您的位置:首页 > 其它

ViewFlipper简单学习笔记

2015-12-15 19:59 399 查看
相信各位android程序猿对ViewFlipper这个组件并不陌生,它的的主要作用就是用来切换View的时候提供页面间的动画效果,这点从其父类的功能以及其父类的名字可以看出来:

它的父类的名字为ViewAnimator,其直接父类为ViewGroup,包含了两个动画的引用:

Animation mInAnimation;
    Animation mOutAnimation;
mInAnimation:这个Animation是用于将上一页或者下一页的View切换进来时的动画

moutAnimation:这个Animation是用于将当前页面的View退出时的动画

if(switchView){
     //让当前显示的View执行退出动画

     currentView.startAnimation(mOutAnimation);

  //让即将要显示的View执行进入动画

    nextView_or_preView.startAnimatioin(mInAnimation);

}


上面的伪代码可以很清晰的说明了ViewAnimator或者ViewFlipper的页面切换动画的实现原理,当然还不是很完善,随着博文的进行会逐一完善上面的伪代码。

因为ViewAnimator继承自ViewGroup,所以可以调用ViewGroup的addView几个相关的重载方法进行View的添加,这些添加进来的各个View按照添加的顺序添加到了ViewGroup的mChildren数组里面,ViewFlipper或者ViewAnimator切换View的时候就是切换的里面的这些被添加进来的View.当然ViewAnimator也重写了其父类的ViewGroup的一个AddView方法:

/**
*@param child View要添加到ViewFlipper或者ViewAnimator中的View
*/
@Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        super.addView(child, index, params);
     //如果只添加进来一个View,就直接显示
     if (getChildCount() == 1) {
          child.setVisibility(View.VISIBLE);
      } else {//
          child.setVisibility(View.GONE);
     }
    }


上面的代码很明显,如果整个页面就一页的话就直接显示,如果连续调用该方法的话,会将第一页的View显示,而其余页的View都会隐藏。当然我们可以直接调用ViewGroup的系列addView方法来完成相关功能。既然第一个页面为View.VISIABLE其余的页面的View为GONE,那么很容易猜出来实现页面的切换的核心逻辑的为:

1)隐藏当前页的View,即将当前的View可见性设置为GONE

2)显示即将切换进来的View(上一页或者下一页的View) ,设置为Visiable

如果添加上动画效果的话,结合上问所说的伪代码,可以讲上面伪代码进步完善:

if(switchView){
     //让当前显示的View执行退出动画
     currentView.startAnimation(mOutAnimation);
     //隐藏
     currentView.setVisibility(View.GONE);

      //让即将要显示的View执行进入动画
    nextView_or_preView.startAnimatioin(mInAnimation);
    //显示View
     nextView_or_preView.setVisibility(View.VISIBLE);
 }


实现上一页或者下一页的切换ViewFlipper的父类ViewAnimator提供了两个方法:

1)showNext:显示下一页的View。

2)showPrevious显示上一页的View。

其实继续追踪它的实现源码,正如上面的额伪代码所说的描述的那样,可以发现其原理也很简单:因为把每一页的View都加入到了一个数组里面,所以需要根据当前数组下标来获取上一页和下一页的View,这样的ViewFlipper或者ViewAnimator的原理就如下:

//切换view
void switchView(int index){
   for(int i=0;i<childrenCount;i++){
        View child = mViews[i];
       if(index=i){
           child.startAnimation(mInAnimation);
           child.setVisiablity(View.VISIABLE);

       }else{
       
          child.startAnimation(mOutAnimation);
          child.setVisiablity(View.GONE);
       }
   }
}


在ViewAnimator中提供了showNext()和showPrevious() 方法来切换下一页和上一页,追踪下源代码可以发现他们只是调用了setDisplayedChild方法:

/**
*@param whichChild 要显示的View在viewGroup数组中的索引
*/ 
public void setDisplayedChild(int whichChild) {
        mWhichChild = whichChild;
        //通过这个可以发现,
        if (whichChild >= getChildCount()) {
            mWhichChild = 0;
        } else if (whichChild < 0) {
            mWhichChild = getChildCount() - 1;
        }
        boolean hasFocus = getFocusedChild() != null;
        // This will clear old focus if we had it
        showOnly(mWhichChild);
        if (hasFocus) {
            // Try to retake focus if we had it
            requestFocus(FOCUS_FORWARD);
        }
    }


通过什么的方法可以得出这个一个结论:当一直调用showNext()显示下一页的时候,如果此时已经处于最后一页再调用showNext()方法的话,那么就会显示第一页的View;如果已经处于第一页再次调用showPrevious()的话,会显示最后一页的View。其实根据setDisplayedChild这个方法可以实现跳页的效果,比如在TV端用户操控遥控器输入数字键,让ViewFlipper跳到制定的页数这样的功能。最终实现View的切换逻辑是在showOnly里面,这个方法原理正如上面的伪代码一样,很容易看明白:

void showOnly(int childIndex, boolean animate) {
        final int count = getChildCount();
        //对View进行遍历
         for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
           if (i == childIndex) {//即将显示的View
                if (animate && mInAnimation != null) {//执行显示动画
                    child.startAnimation(mInAnimation);
                }
                //设置可见
                child.setVisibility(View.VISIBLE);
                mFirstTime = false;
            } else {//关闭其他的且可见的View
                if (animate && mOutAnimation != null && child.getVisibility() == View.VISIBLE) {
                    child.startAnimation(mOutAnimation);//执行动画
                } else if (child.getAnimation() == mInAnimation)
                    child.clearAnimation();
                  //设置不可见
                  child.setVisibility(View.GONE);
            }
        }
    }


其实通过上面对ViewAnimator的讲解,完全可以通过ViewAnimator这个类而不用其子类ViewFilpper来实现类似PPT的功能或者页面轮播功能,核心原理也很简单:用定时器或者延迟消息,每隔一段时间调用showNext()方法并添加自定义Animation即可,其伪代码如下:

showPPT(){
   sendMsgDelayed(msg,delayed_time);
}

handleMsg(){
   viewAnimator.showNext();
   sendMsgDelayed(msg,delayed_time);
}


这个类似ppt页面切换的demo源代码点此(,源代码很简单,当然按照屌丝程序员惯例,图片都是从网上搜的美女图



如果按照上面所说的话ViewAnimator这个类就可以实现基本的页面切换的功能了,那么它的子类ViewFilpper又对ViewAnimator做了什么扩展呢?其实它做的功能的拓展也很简单,总的来说就是提供了startFlipping()和stopFlipping()方法,一直调用startFlipping()的话也可以实现类似ppt的效果,其核心原理也是发送延迟消息,并不断调用其父类ViewAnimator的showNext()方法,只不过用户可以调用 setFlipInterval(int milliseconds)方法来设置页面切换的速度,具有可控性。具体的源代码就不贴出来了,核心原理跟上面所说的demo里面的很类似。并可以调用isFlipping方法来判断ViewFlipper是否在进行页面的轮播或者切换

同时ViewFlipper还定义了一个广播来监听屏幕是否关闭和打开,来控制是否轮播。

到文章的最后,需要说一情况:在qq群里面有讨论技术的时候有些人总有一种误区就是自定义View一定要重写onMeasure或者onLayout方法,其实 这个打破这个误区也很简单,比如这个viewAnimator和ViewFlipper仅仅只是用了ViewGroup的addView的功能,在加上动画效果。他们并没有重写View的onMeasure或者onLayout方法,自定义view根据具体的需求来完成的,当然有的简单有的复杂,比如特殊的动画效果,扩展TextView来实现滚动的手动暂停和开始等,自定义view在这里因为本人技术有限就不多说了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: