Android Browser學習六 多窗口: NavScreen 切換窗口

前面咱們簡單介紹了Tab和TabControl的大致結構,可是若是想要實現瀏覽器的多標籤切換功能, 還須要一個用戶交互界面, 這個界面在Android Browser中就是NavScreen了: java

這裏咱們介紹一下下面這個UI的實現, 主要代碼在NavScreen.java中. web

咱們知道, 在Android Browser中 用以和用戶打交道的功能基本都被限制在了BaseUI中, 在手機上它的實現就是PhoneUI: 瀏覽器

顯示多窗口列表固然也是不例外的:PhoneUI::showNavScreen: 數據結構


//點擊按鈕顯示多窗口列表
    void showNavScreen() {
        mUiController.setBlockEvents(true); //攔截多窗口外的其餘操做
        if (mNavScreen == null) {
            mNavScreen = new NavScreen(mActivity, mUiController, this);
            mCustomViewContainer.addView(mNavScreen, COVER_SCREEN_PARAMS);
        } else {
            mNavScreen.setVisibility(View.VISIBLE);
            mNavScreen.setAlpha(1f);
            mNavScreen.refreshAdapter();
        }
        mActiveTab.capture();
        if (mAnimScreen == null) {
            //這是動畫的視圖 ,多標籤窗口切換的動畫師phoneui來實現的而不是 navscreen ,也就是說我點擊一個tab 剩下的看到的實際上是
            //真正的web窗口
            mAnimScreen = new AnimScreen(mActivity);
        } else {
            mAnimScreen.mMain.setAlpha(1f);
            mAnimScreen.mTitle.setAlpha(1f);
            mAnimScreen.setScaleFactor(1f);
        }
        //設置動畫須要截圖的view
        mAnimScreen.set(getTitleBar(), getWebView());
        if (mAnimScreen.mMain.getParent() == null) {
            //若是animscreen 的main沒有父親, 說明是執行了 全屏模式
            mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS);
        }
        mCustomViewContainer.setVisibility(View.VISIBLE);
        mCustomViewContainer.bringToFront();//把這個view放到頂層
        mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(),
                mContentView.getHeight()); //動畫的寬度和contentview同樣大
        int fromLeft = 0;
        int fromTop = getTitleBar().getHeight();
        int fromRight = mContentView.getWidth();
        int fromBottom = mContentView.getHeight();
        int width = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_width);
        int height = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_height);
        int ntth = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_titleheight);
        int toLeft = (mContentView.getWidth() - width) / 2;
        int toTop = ((fromBottom - (ntth + height)) / 2 + ntth);
        int toRight = toLeft + width;
        int toBottom = toTop + height;
        float scaleFactor = width / (float) mContentView.getWidth();
        detachTab(mActiveTab);
        mContentView.setVisibility(View.GONE);
        AnimatorSet set1 = new AnimatorSet();
        AnimatorSet inanim = new AnimatorSet();
        //使用上下左右的位置 使得  tab的運動軌跡 從整個屏幕 位置縮小到tab,不管當前tab在哪裏
        ObjectAnimator tx = ObjectAnimator.ofInt(mAnimScreen.mContent, "left",
                fromLeft, toLeft);
        ObjectAnimator ty = ObjectAnimator.ofInt(mAnimScreen.mContent, "top",
                fromTop, toTop);
        ObjectAnimator tr = ObjectAnimator.ofInt(mAnimScreen.mContent, "right",
                fromRight, toRight);
        ObjectAnimator tb = ObjectAnimator.ofInt(mAnimScreen.mContent, "bottom",
                fromBottom, toBottom);
        ObjectAnimator title = ObjectAnimator.ofFloat(mAnimScreen.mTitle, "alpha",
                1f, 0f);
        ObjectAnimator sx = ObjectAnimator.ofFloat(mAnimScreen, "scaleFactor",
                1f, scaleFactor);
       
        ObjectAnimator blend1 = ObjectAnimator.ofFloat(mAnimScreen.mMain,
                "alpha", 1f, 0f);
        blend1.setDuration(100);

        inanim.playTogether(tx, ty, tr, tb, sx, title);
        inanim.setDuration(200);
        set1.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator anim) {
                mCustomViewContainer.removeView(mAnimScreen.mMain);
                finishAnimationIn();
                mUiController.setBlockEvents(false);
            }
        });
        set1.playSequentially(inanim, blend1);//inanim播放ok後播放 blend1 也就是先縮放而後在透明 
        set1.start();
    }



這裏還實現了一個打開多窗口的動畫, 咱們暫時先不去考慮, 先看NavScreen的數據結構:


他的結構也不是很複雜, 拿到了Activity 和Controller的引用, 而後有一個NavTabScroller (繼承自NavTabScroller )和 一個TabAdapter (繼承自 BaseAdapter)的成員, 他們是多窗口列表view的具體實現和數據來源了. NavScreen有一些Tab的操做, 他們基本都須要通知到Controller, 由於NavScreen只不過是UI 真正的操做是Controller來作的.  ide

看一下NavTabScroller 是一個ScrollView, 多窗口之因此能夠滑動就全靠他了, 他還實現了橫向豎向滑動, 載入adapter的數據等功能: 函數


public class NavTabScroller extends ScrollerView {
    static final int INVALID_POSITION = -1;
    static final float[] PULL_FACTOR = { 2.5f, 0.9f };

    interface OnRemoveListener {
        public void onRemovePosition(int position);
    }

    interface OnLayoutListener {
        public void onLayout(int l, int t, int r, int b);
    }

    private ContentLayout mContentView; //其實是一個linearlayout
    private BaseAdapter mAdapter;
    private OnRemoveListener mRemoveListener;
    private OnLayoutListener mLayoutListener;
    private int mGap;
    private int mGapPosition;
    private ObjectAnimator mGapAnimator;

    // after drag animation velocity in pixels/sec
    private static final float MIN_VELOCITY = 1500; //最小的滑動
    private AnimatorSet mAnimator;

    private float mFlingVelocity;
    private boolean mNeedsScroll;
    private int mScrollPosition;

    DecelerateInterpolator mCubic;
    int mPullValue;




他裝載數據的操做是setAdapter函數調用handleDataChanged函數實現的: 佈局


//裝載多窗口數據
    void handleDataChanged(int newscroll) {
        int scroll = getScrollValue(); //是x方向scroll 仍是y
        if (mGapAnimator != null) {
            mGapAnimator.cancel();//取消動畫
        }
        mContentView.removeAllViews();
        for (int i = 0; i < mAdapter.getCount(); i++) {
            View v = mAdapter.getView(i, null, mContentView);//從adapter中拿到view 添加到linearlayout上listview等其實也是這樣實現的
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            lp.gravity = (mHorizontal ? Gravity.CENTER_VERTICAL : Gravity.CENTER_HORIZONTAL);
            mContentView.addView(v, lp);//添加tabview到那個mContentView . 居中顯示
            if (mGapPosition > INVALID_POSITION){
                adjustViewGap(v, i);
            }
        }
        if (newscroll > INVALID_POSITION) {
            newscroll = Math.min(mAdapter.getCount() - 1, newscroll);//newscroll 是從0 開始到 adapter.count的
            mNeedsScroll = true;
            mScrollPosition = newscroll;
            requestLayout();
        } else {
            setScrollValue(scroll); //滑動到頂部/左邊
        }
    }




好 大致的UI就差很少這些了, 下面是其動畫的實現: post

其動畫分爲如下幾個: 動畫

1.點擊多窗口按鈕 的時候, 整個瀏覽器窗口會縮小到多窗口列表, 而後顯示出其餘的窗口標籤供做者選擇 ui

2.點擊多窗口列表任何一個窗口    其餘的多窗口標籤會消失 , 

整個窗口會擴到到整個屏幕

3.在多窗口列表中左右滑動任何一個窗口, 整個窗口會漸變和移動 直到刪除


4.其實這個"listview"還有回彈功能, 效果是使小窗口的間距縮小,不過效果不是很明顯, 應該有點小bug


那就從第一個動畫開始分析:

這個動畫是在PhoneUI::showNavScreen()函數實現的, 其實就是一個animator動畫:

//點擊按鈕顯示多窗口列表
    void showNavScreen() {
        mUiController.setBlockEvents(true); //攔截多窗口外的其餘操做
        if (mNavScreen == null) {
            mNavScreen = new NavScreen(mActivity, mUiController, this);
            mCustomViewContainer.addView(mNavScreen, COVER_SCREEN_PARAMS);
        } else {
            mNavScreen.setVisibility(View.VISIBLE);
            mNavScreen.setAlpha(1f);
            mNavScreen.refreshAdapter();
        }
        mActiveTab.capture();
        if (mAnimScreen == null) {
            //這是動畫的視圖 ,多標籤窗口切換的動畫師phoneui來實現的而不是 navscreen ,也就是說我點擊一個tab 剩下的看到的實際上是
            //真正的web窗口
            mAnimScreen = new AnimScreen(mActivity);
        } else {
            mAnimScreen.mMain.setAlpha(1f);
            mAnimScreen.mTitle.setAlpha(1f);
            mAnimScreen.setScaleFactor(1f);
        }
        //設置動畫須要截圖的view
        mAnimScreen.set(getTitleBar(), getWebView());
        if (mAnimScreen.mMain.getParent() == null) {
            //若是animscreen 的main沒有父親, 說明是執行了 全屏模式
            mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS); //把須要作動畫的view添加到整個佈局的上層
        }
        mCustomViewContainer.setVisibility(View.VISIBLE);
        mCustomViewContainer.bringToFront();//把這個view放到頂層
        mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(),
                mContentView.getHeight()); //動畫的寬度和contentview同樣大
        int fromLeft = 0;
        int fromTop = getTitleBar().getHeight();
        int fromRight = mContentView.getWidth();
        int fromBottom = mContentView.getHeight();
        int width = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_width);
        int height = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_height);
        int ntth = mActivity.getResources().getDimensionPixelSize(R.dimen.nav_tab_titleheight);
        int toLeft = (mContentView.getWidth() - width) / 2;
        int toTop = ((fromBottom - (ntth + height)) / 2 + ntth);
        int toRight = toLeft + width;
        int toBottom = toTop + height;
        float scaleFactor = width / (float) mContentView.getWidth();
        detachTab(mActiveTab);
        mContentView.setVisibility(View.GONE);
        AnimatorSet set1 = new AnimatorSet();
        AnimatorSet inanim = new AnimatorSet();
        //使用上下左右的位置 使得  tab的運動軌跡 從整個屏幕 位置縮小到屏幕的中心 ,不管當前tab在哪裏, 不過軌跡是同樣的
        ObjectAnimator tx = ObjectAnimator.ofInt(mAnimScreen.mContent, "left",
                fromLeft, toLeft);
        ObjectAnimator ty = ObjectAnimator.ofInt(mAnimScreen.mContent, "top",
                fromTop, toTop);
        ObjectAnimator tr = ObjectAnimator.ofInt(mAnimScreen.mContent, "right",
                fromRight, toRight);
        ObjectAnimator tb = ObjectAnimator.ofInt(mAnimScreen.mContent, "bottom",
                fromBottom, toBottom);
        ObjectAnimator title = ObjectAnimator.ofFloat(mAnimScreen.mTitle, "alpha",
                1f, 0f);
        ObjectAnimator sx = ObjectAnimator.ofFloat(mAnimScreen, "scaleFactor",
                1f, scaleFactor);
       
        ObjectAnimator blend1 = ObjectAnimator.ofFloat(mAnimScreen.mMain,
                "alpha", 1f, 0f);
        blend1.setDuration(100);

        inanim.playTogether(tx, ty, tr, tb, sx, title);
        inanim.setDuration(200);
        set1.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator anim) {
                mCustomViewContainer.removeView(mAnimScreen.mMain);//把作動畫的view刪除
                finishAnimationIn();
                mUiController.setBlockEvents(false);
            }
        });
        set1.playSequentially(inanim, blend1);//inanim播放ok後播放 blend1 也就是先縮放而後在透明 
        set1.start();
    }



這裏咱們可能要問了AnimScreen這個東西是什麼呢?原來,爲了提升動畫的效率,實際上是經過把webview的內容繪製到 Imageview 上, 須要切換的時候就把這個imageview添加到webview上面,而後作動畫. 看看AnimScreen代碼就明白了:



/*
     *其實動畫是使用兩個imageview在作, 這兩個imageview 分別繪製了titlebar和webview 
     */
    static class AnimScreen {

        private View mMain;
        private ImageView mTitle;
        private ImageView mContent;
        private float mScale;
        private Bitmap mTitleBarBitmap;
        private Bitmap mContentBitmap;

        public AnimScreen(Context ctx) {
            mMain = LayoutInflater.from(ctx).inflate(R.layout.anim_screen,
                    null);
            mTitle = (ImageView) mMain.findViewById(R.id.title);
            mContent = (ImageView) mMain.findViewById(R.id.content);
            mContent.setScaleType(ImageView.ScaleType.MATRIX);
            mContent.setImageMatrix(new Matrix());
            mScale = 1.0f;
            setScaleFactor(getScaleFactor());
        }

        /**
         * 包titilebar和webview的截圖畫到動畫的view上
         * @param tbar
         * @param web
         */
        public void set(TitleBar tbar, WebView web) {
            if (tbar == null || web == null) {
                return;
            }
            if (tbar.getWidth() > 0 && tbar.getEmbeddedHeight() > 0) {
                if (mTitleBarBitmap == null
                        || mTitleBarBitmap.getWidth() != tbar.getWidth()
                        || mTitleBarBitmap.getHeight() != tbar.getEmbeddedHeight()) {
                    mTitleBarBitmap = safeCreateBitmap(tbar.getWidth(),
                            tbar.getEmbeddedHeight());
                }
                if (mTitleBarBitmap != null) {
                    Canvas c = new Canvas(mTitleBarBitmap);
                    tbar.draw(c);
                    c.setBitmap(null);
                }
            } else {
                mTitleBarBitmap = null;
            }
            mTitle.setImageBitmap(mTitleBarBitmap);
            
            mTitle.setVisibility(View.VISIBLE);
            int h = web.getHeight() - tbar.getEmbeddedHeight();
            if (mContentBitmap == null
                    || mContentBitmap.getWidth() != web.getWidth()
                    || mContentBitmap.getHeight() != h) {
                mContentBitmap = safeCreateBitmap(web.getWidth(), h);
            }
            if (mContentBitmap != null) {
                Canvas c = new Canvas(mContentBitmap);
                int tx = web.getScrollX();
                int ty = web.getScrollY();
                c.translate(-tx, -ty - tbar.getEmbeddedHeight());
                web.draw(c);
                c.setBitmap(null);
            }
            mContent.setImageBitmap(mContentBitmap);
        }

        private Bitmap safeCreateBitmap(int width, int height) {
            if (width <= 0 || height <= 0) {
                Log.w(LOGTAG, "safeCreateBitmap failed! width: " + width
                        + ", height: " + height);
                return null;
            }
            return Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        }

        /*
         * 這個版本至顯示content
         */
        public void set(Bitmap image) {
            mTitle.setVisibility(View.GONE);
            mContent.setImageBitmap(image);
        }

        private void setScaleFactor(float sf) {
            mScale = sf;
            Matrix m = new Matrix();
            m.postScale(sf,sf);
            mContent.setImageMatrix(m);
        }

        private float getScaleFactor() {
            return mScale;
        }

    }


知道了第一個動畫如何實現, 第二個動畫就好理解了, 正好是第一個動畫的反過來, 不過此次動畫的軌跡可能不同, 由於用戶可能點擊的是上面或者最底下的tab:固然, 經過navScreen就能夠拿到選擇tab的位置:整個操做調用的地方仍是比較多的好比選擇tab 新建tab等都會調用到這個和動畫.


//隱藏多窗口切換 動畫基本同上面顯示多標籤
    void hideNavScreen(int position, boolean animate) {
        if (!showingNavScreen()) return;
        final Tab tab = mUiController.getTabControl().getTab(position);
        if ((tab == null) || !animate) {//彷佛還有別的能夠打開tab的方式可是還不是很清楚在哪裏 
            if (tab != null) {
                setActiveTab(tab);
            } else if (mTabControl.getTabCount() > 0) {
                // use a fallback tab
                setActiveTab(mTabControl.getCurrentTab());
            }
            mContentView.setVisibility(View.VISIBLE);
            finishAnimateOut();
            return;
        }
        NavTabView tabview = (NavTabView) mNavScreen.getTabView(position);
        if (tabview == null) {
            if (mTabControl.getTabCount() > 0) {
                // use a fallback tab
                setActiveTab(mTabControl.getCurrentTab());
            }
            mContentView.setVisibility(View.VISIBLE);
            finishAnimateOut();
            return;
        }
        mUiController.setBlockEvents(true);
        mUiController.setActiveTab(tab);
        mContentView.setVisibility(View.VISIBLE);
        if (mAnimScreen == null) {
            mAnimScreen = new AnimScreen(mActivity);
        }
        mAnimScreen.set(tab.getScreenshot());
        mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS); //全屏模式
        mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(),
                mContentView.getHeight());
        mNavScreen.mScroller.finishScroller();
        ImageView target = tabview.mImage;
        int toLeft = 0;
        int toTop = getTitleBar().getHeight();
        int toRight = mContentView.getWidth();
        int width = target.getDrawable().getIntrinsicWidth();
        int height = target.getDrawable().getIntrinsicHeight();
        int fromLeft = tabview.getLeft() + target.getLeft() - mNavScreen.mScroller.getScrollX();
        int fromTop = tabview.getTop() + target.getTop() - mNavScreen.mScroller.getScrollY();//target就是選擇的tab tab的頂部位置 爲了給人以 從原來位置擴大到整個屏幕的感受
        int fromRight = fromLeft + width;
        int fromBottom = fromTop + height;
        float scaleFactor = mContentView.getWidth() / (float) width;
        int toBottom = toTop + (int) (height * scaleFactor);
        mAnimScreen.mContent.setLeft(fromLeft);
        mAnimScreen.mContent.setTop(fromTop);
        mAnimScreen.mContent.setRight(fromRight);
        mAnimScreen.mContent.setBottom(fromBottom);
        mAnimScreen.setScaleFactor(1f);
        AnimatorSet set1 = new AnimatorSet();
        ObjectAnimator fade2 = ObjectAnimator.ofFloat(mAnimScreen.mMain, "alpha", 0f, 1f);
        ObjectAnimator fade1 = ObjectAnimator.ofFloat(mNavScreen, "alpha", 1f, 0f);
        set1.playTogether(fade1, fade2);
        set1.setDuration(100);
        //使用上下左右的位置 使得  tab的運動軌跡 從原來位置擴展到整個屏幕,不管整個tab在哪裏
        AnimatorSet set2 = new AnimatorSet();
        ObjectAnimator l = ObjectAnimator.ofInt(mAnimScreen.mContent, "left",
                fromLeft, toLeft);
        ObjectAnimator t = ObjectAnimator.ofInt(mAnimScreen.mContent, "top",
                fromTop, toTop);
        ObjectAnimator r = ObjectAnimator.ofInt(mAnimScreen.mContent, "right",
                fromRight, toRight);
        ObjectAnimator b = ObjectAnimator.ofInt(mAnimScreen.mContent, "bottom",
                fromBottom, toBottom);
        ObjectAnimator scale = ObjectAnimator.ofFloat(mAnimScreen, "scaleFactor",
                1f, scaleFactor);
        ObjectAnimator otheralpha = ObjectAnimator.ofFloat(mCustomViewContainer, "alpha", 1f, 0f);
        otheralpha.setDuration(100);
        set2.playTogether(l, t, r, b, scale);
        set2.setDuration(200);
        AnimatorSet combo = new AnimatorSet();
        combo.playSequentially(set1, set2, otheralpha);
        combo.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator anim) {
                mCustomViewContainer.removeView(mAnimScreen.mMain);//動畫結束的時候把動畫view 隱藏
                finishAnimateOut();//讓當前窗口漸變消失
                mUiController.setBlockEvents(false);
            }
        });
        combo.start();
    }


對於第三個動畫, 左右滑動刪除的動畫, 其入口有二

a.  Scrollview的onTouchEvent事件中調用的NavTabScroller::onOrthoDragFinished()函數, 其實最後仍是調用到animateOut函數

/*這是scrollview回調的一個函數,做用是 在用戶左右滑動 tab以後 判斷是否刪除這個tab*/
    @Override
    protected void onOrthoDragFinished(View downView) {
        if (mAnimator != null) return;
        if (mIsOrthoDragged && downView != null) {
            // offset
            float diff = mHorizontal ? downView.getTranslationY() : downView.getTranslationX();
            if (Math.abs(diff) > (mHorizontal ? downView.getHeight() : downView.getWidth()) / 2) {
                // remove it 達到了刪除tab的調節,開始刪除
                animateOut(downView, Math.signum(diff) * mFlingVelocity, diff);
            } else {
                // snap back 沒有達到條件,就讓view回來
                offsetView(downView, 0);
            }
        }
    }

在用戶按住小tab移動的時候會執行offsetView函數:


private void offsetView(View v, float distance) {
        v.setAlpha(getAlpha(v, distance));
        //setTranslationY 這個功能應該只有3.0之後才支持 讓view左右滑動
        if (mHorizontal) {
            v.setTranslationY(distance);
        } else {
            v.setTranslationX(distance);
        }
    }





b另外一種調用動畫的方式比較簡單了,其實就是直接調用animateOut函數:


看一下這個函數到底作了什麼吧:

   1.須要刪除窗口的平移和alpha漸變

   2.刪除窗口後,其餘窗口的上移,這是比較複雜的一個邏輯 ,大致是經過改變mGap這個參數實現,動畫也是使用了animator:


/*刪除 tab 動畫 (左右滑動刪除 )的顯示*/
    private void animateOut(final View v, float velocity, float start) {
        if ((v == null) || (mAnimator != null)) return; //有其餘動畫就不要執行這個動畫
        final int position = mContentView.indexOfChild(v);
        int target = 0;
        if (velocity < 0) {//動畫結束的位置
            target = mHorizontal ? -getHeight() :  -getWidth();
        } else {
            target = mHorizontal ? getHeight() : getWidth();
        }
        int distance = target - (mHorizontal ? v.getTop() : v.getLeft());
        long duration = (long) (Math.abs(distance) * 1000 / Math.abs(velocity));//動畫持續時間
        int scroll = 0;
        int translate = 0;
        int gap = mHorizontal ? v.getWidth() : v.getHeight();
        int centerView = getViewCenter(v);//獲取view的中心
        int centerScreen = getScreenCenter();//獲取屏幕的中心
        int newpos = INVALID_POSITION;
        if (centerView < centerScreen - gap / 2) {
            // top view刪除的是上面的view
            scroll = - (centerScreen - centerView - gap);
            translate = (position > 0) ? gap : 0;
            newpos = position;
        } else if (centerView > centerScreen + gap / 2) {
            // bottom view 刪除的是底部的view
            scroll = - (centerScreen + gap - centerView);
            if (position < mAdapter.getCount() - 1) {
                translate = -gap;
            }
        } else {
            // center view 刪除的是中間的view
            scroll = - (centerScreen - centerView);
            if (position < mAdapter.getCount() - 1) {
                translate = -gap;
            } else {
                scroll -= gap;
            }
        }
        mGapPosition = position;
        final int pos = newpos;
        ObjectAnimator trans = ObjectAnimator.ofFloat(v,
                (mHorizontal ? TRANSLATION_Y : TRANSLATION_X), start, target); //控制待刪除view的水平 移動
        ObjectAnimator alpha = ObjectAnimator.ofFloat(v, ALPHA, getAlpha(v,start),//控制待刪除view的透明變化
                getAlpha(v,target));
        AnimatorSet set1 = new AnimatorSet();
        set1.playTogether(trans, alpha);
        set1.setDuration(duration);
        mAnimator = new AnimatorSet();
        ObjectAnimator trans2 = null;
        ObjectAnimator scroll1 = null;
        if (scroll != 0) {
            if (mHorizontal) {//調整scrollview的scroll位置
                scroll1 = ObjectAnimator.ofInt(this, "scrollX", getScrollX(), getScrollX() + scroll);
            } else {
                scroll1 = ObjectAnimator.ofInt(this, "scrollY", getScrollY(), getScrollY() + scroll);
            }
        }
        if (translate != 0) {
            trans2 = ObjectAnimator.ofInt(this, "gap", 0, translate); //刪除view會留下一個空白,須要讓上面的view補充上 這裏gap是 負值,由於view少了,座標也就小了
        }
        final int duration2 = 200;
        if (scroll1 != null) {
            if (trans2 != null) {
                AnimatorSet set2 = new AnimatorSet();
                set2.playTogether(scroll1, trans2);
                set2.setDuration(duration2);
                mAnimator.playSequentially(set1, set2);
            } else {
                scroll1.setDuration(duration2);
                mAnimator.playSequentially(set1, scroll1);
            }
        } else {
            if (trans2 != null) {
                trans2.setDuration(duration2);
                mAnimator.playSequentially(set1, trans2);
            }
        }
        mAnimator.addListener(new AnimatorListenerAdapter() {
            public void onAnimationEnd(Animator a) {
                if (mRemoveListener !=  null) {
                    mRemoveListener.onRemovePosition(position);//通知移除tab
                    mAnimator = null;
                    mGapPosition = INVALID_POSITION;
                    mGap = 0;
                    handleDataChanged(pos);
                }
            }
        });
        mAnimator.start();
    }

至於切換就簡單了,是在controller::setActiveTab()函數進行處理.

相關文章
相關標籤/搜索