ViewFlipper源码分析以及通过view复用优化viewFlipper用法

本文介绍ViewFlipper控件及其在Android应用中的动画切换功能,并探讨如何结合GestureDetector实现滑动翻页效果。此外,还提出了一种优化方案,通过复用视图减少内存消耗。

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复用的方案,未整理,有兴趣可以封装~)

demo目录结构:














评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值