ViewFlipper简单学习笔记

来源:互联网 发布:手机mac地址怎么改 编辑:程序博客网 时间:2024/06/10 22:34
相信各位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的原理就如下:

//切换viewvoid 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在这里因为本人技术有限就不多说了



1 0