View切换的控件—ViewFlipper介绍
简介
ViewFilpper类继承于ViewAnimator类。而ViewAnimator类继承于FrameLayout,我认为该类和viewpager有个很大的区别是viewflipper提供了动画切换的方法,比较viewpager更方便页面切换时增加动画。
查看ViewAnimator类的源码可以看出此类的作用主要是为其中的View切换提供动画效果。
该类有如下几个和动画相关的方法。
1. setInAnimation:设置View进入屏幕时候使用的动画。该方法有两个重载方法,即可以直接传入Animation对象,也可以传入定义的Animation文件的resourceID。
2. setOutAnimation:设置View退出屏幕时候使用的动画。使用方法和setInAnimation方法一样。
3. showNext:调用该方法可以显示FrameLayout里面的下一个View。
4. showPrevious:调用该方法可以来显示FrameLayout里面的上一个View
ViewFliper关键方法:
1. setFilpInterval:设置View切换的时间间隔。参数为毫秒。
2. startFlipping:开始进行View的切换,时间间隔是上述方法设置的间隔数。切换会循环进行。
3. stopFlipping:停止View切换。
4. setAutoStart:设置是否自动开始。如果设置为“true”,当ViewFlipper显示的时候View的切换会自动开始。
一般情况下,我们都会使用ViewFilpper类实现View的切换,而不使用它的父类ViewAnimator类。
实现滑动—GestureDetector介绍
如果想要实现滑动翻页的效果,就要了解另外一个类:Android.view.GestureDetector类。GestureDetector类中可以用来检测各种手势事件。该类有两个回调接口,分别用来通知具体的事件。
GestureDetector.OnDoubleTapListener:用来通知DoubleTap事件,类似于PC上面的鼠标的双击事件。
GestureDetector.OnGestureListener:用来通知普通的手势事件,该接口有六个回调方法,具体的可以查看API。这里想要实现滑动的判断,就需要用到其中的onFling()方法
Viewflipper的用法
说明:viewfliper的经典用法可参考这位同学的http://blog.youkuaiyun.com/u013378580/article/details/52038255,今天要实现的是在上述博客中提到中的基础上增加viewflipper中view的复用,完成viewFlipper的优化使用。比如一些资讯类的APP,首页有20条数据,需要滚动展示,如果使用viewflipper的经典用法,需要创建20个view实现轮询展示,view比较复杂时20个view浪费内存(虽然不会浪费太多,但是每次轮询都new view略显low~~~哈哈)。复用view实现的思路是:20条数据的展示,用2个view来实现复用实现轮播(前提是20条数据的view样式是一样的哈)下面直接上代码~
效果:
ViewFlipper源码分析:
参考viewFlipper源码中切换view的代码重新实现view切换,请确保已经了解ViewFlipper的用法,不然后面说的可能看不懂~。
先看viewFlipper源码中实现view切换关键源码:
//切换view代码入口
public void startFlipping() {
mStarted = true;
updateRunning();
}
看下updateRunning()的具体实现
private void updateRunning() {
updateRunning(true);
}
/**
* Internal method to start or stop dispatching flip {@link Message} based
* on {@link #mRunning} and {@link #mVisible} state.
*
* @param flipNow Determines whether or not to execute the animation now, in
* addition to queuing future flips. If omitted, defaults to
* true.
*/
private void updateRunning(boolean flipNow) {
boolean running = mVisible && mStarted && mUserPresent;
if (running != mRunning) {
if (running) {
showOnly(mWhichChild, flipNow);
postDelayed(mFlipRunnable, mFlipInterval);
} else {
removeCallbacks(mFlipRunnable);
}
mRunning = running;
}
if (LOGD) {
Log.d(TAG, "updateRunning() mVisible=" + mVisible + ", mStarted=" + mStarted
+ ", mUserPresent=" + mUserPresent + ", mRunning=" + mRunning);
}
}
上面代码中17、18两行是关键
showOnly(mWhichChild, flipNow);
postDelayed(mFlipRunnable, mFlipInterval);
先看父类viewAnimal中showOnly方法--真正实现切换的逻辑。
//该方法是只显示当前的view,其他数据的view先隐藏
void showOnly(int childIndex, boolean animate) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (i == childIndex) {
if (animate && mInAnimation != null) {
child.startAnimation(mInAnimation);
}
child.setVisibility(View.VISIBLE);
mFirstTime = false;
} else {
if (animate && mOutAnimation != null && child.getVisibility() == View.VISIBLE) {
child.startAnimation(mOutAnimation);
} else if (child.getAnimation() == mInAnimation)
child.clearAnimation();
child.setVisibility(View.GONE);
}
}
}
通过handler消息机制实现轮询
private final Runnable mFlipRunnable = new Runnable() {
@Override
public void run() {
if (mRunning) {
showNext();
postDelayed(mFlipRunnable, mFlipInterval);
}
}
};
总体思路:
1. viewFlipper继承于FrameLayout,当多次addView时优先展示位于上层且visible的view,根据索引将当前要显示的view置为visible,其他view设置gone。2. handler消息机制维持页面轮询切换。
view复用的逻辑
思路:创建ViewFlipper的子类,重写showonly方法,让viewFliper中getChildCount最大保持为2。当viewfliper中包含2个子view时removeAtIndex(1),初始化view,再addView(view,0);第1个子view设置visible,第二个子view设置gone。之所以复用2个而不使用1个view,因为1个view不能实现平滑滑动。//复用view逻辑主要在这里
public void flipToNext(boolean isPrevious)
{
if(flipperListener != null)
{
int childcount = getChildCount();
if(2 == childcount)
{
removeViewAt(1);
}
View v = null;
if(!isPrevious)
{
v = flipperListener.getNextView();
}else
{
v = flipperListener.getPrevious();
}
if(v == null) return;
addView(v,0);
childcount = getChildCount();
if(0 != childcount)
{
setInAnimation(getContext(), R.anim.slide_in_vertical);
setOutAnimation(getContext(),R.anim.slide_out_vertical);
//显示第一个view,其他view隐藏
setDisplayedChild(0);
}
}
}
View复用整体思路:
1. 首先在xml布局中创建扩展后的ViewFlipper控件 <demo.luqh.com.flipviewdemo.view.DynamicFlipperView
android:id="@+id/flipview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center" />
2. 在java文件中实例化ViewFlipper控件
3. 设置响应的动画效果或者自动切换时间,并开启切换。
具体用法可见demo,效果图见上面动画,点击下载源码
(本demo中添加了上下手势滑动事件,仅仅提供view复用的方案,未整理,有兴趣可以封装~)