Android 6.0 Launcher3 增加屏幕切换动画

来源:互联网 发布:天刀彭于晏捏脸数据 编辑:程序博客网 时间:2024/05/18 13:43

本文是在Android 6.0的系统上增加的Launcher3屏幕切换动画功能。实际效果如下:
这里写图片描述
这里写图片描述

功能分析

下面我们来详细介绍下怎么实现这个功能:
先来看一张图,对于这个功能的修改有个大致了解,然后一一分析之。
这里写图片描述
我们由上到下的顺序分析这个修改的作用。
res和values目录下的修改就不分析,相信大家都可以看明白是什么意图。layout/overview_panel.xml用于实现切换动画的按钮布局,也不多说了。主要看下src目录下java文件的修改。

DeviceProfile.java

在DeviceProfile.java中我们需要修改layout函数,因为它会去是设置overview_panel的大小,如果我们不去修改的话,整个overview_panel布局宽度就会限制在两个或三个按钮的宽度之间,这样UI效果不是很好,所以我们需要修改其大小,接下来看下怎么修改,在layout函数中我们可以找到如下代码:

// Layout the Overview ModeViewGroup overviewMode = launcher.getOverviewPanel();if (overviewMode != null) {    int overviewButtonBarHeight = getOverviewModeButtonBarHeight();    lp = (FrameLayout.LayoutParams) overviewMode.getLayoutParams();    lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;    int visibleChildCount = getVisibleChildCount(overviewMode);    int totalItemWidth = visibleChildCount * overviewModeBarItemWidthPx;    int maxWidth = totalItemWidth + (visibleChildCount-1) * overviewModeBarSpacerWidthPx;//add by steven zhang 20170105//  lp.width = Math.min(availableWidthPx, maxWidth);    lp.width = (int) (availableWidthPx * 0.6);//  lp.height = overviewButtonBarHeight;    overviewMode.setLayoutParams(lp);    if (lp.width > totalItemWidth && visibleChildCount > 1) {        // We have enough space. Lets add some margin too.        int margin = (lp.width - totalItemWidth) / (visibleChildCount-1);        View lastChild = null;        // Set margin of all visible children except the last visible child        for (int i = 0; i < visibleChildCount; i++) {            if (lastChild != null) {                MarginLayoutParams clp = (MarginLayoutParams) lastChild.getLayoutParams();                if (isLayoutRtl) {                    clp.leftMargin = margin;                } else {                    clp.rightMargin = margin;                }                lastChild.setLayoutParams(clp);                lastChild = null;            }            View thisChild = overviewMode.getChildAt(i);            if (thisChild.getVisibility() != View.GONE) {                lastChild = thisChild;            }        }    }}

上面是修改后的代码,修改前的是注释那部分,可以看到lp.width和lp.height都会被设置大小,而lp.width会取最小值,所以我们只需要将其设置为availableWidthPx的60%即可,当然这个可以根据实际需求修改。

Launcher.java

Launcher.java是launcher默认启动的activity,因此我们需要在其中设置切换动画的默认值,同时还要将其保存到文件中,以便下次开机启动时,设置为对应的切换动画。下面我们来看下实际的代码实现。

//add by steven zhang 20170105static final String PAGEVIEWANIMATION_TYPE = "launcher.pageview_animation_type";@Overrideprotected void onCreate(Bundle savedInstanceState) {    ...    setContentView(R.layout.launcher);    //add by steven zhang 20170105    //在activity启动的时候获取默认切换动画并设置    int type = mSharedPrefs.getInt(PAGEVIEWANIMATION_TYPE, 0);    PageViewAnimation.getInstance().setPageViewAnime(type);    ...}//在setupView中初始化切换动画的UIprivate void setupViews() {    ...    //add by steven zhang 20170105    final ViewGroup pageAnimViewGroup = (ViewGroup) findViewById(R.id.id_pageainm_layout);    final int count = pageAnimViewGroup.getChildCount();    for (int i = 0; i < count; i++) {        TextView child = (TextView) pageAnimViewGroup.getChildAt(i);        //设置当前切换动画按钮哪个为选中状态        setAnimPageFocusDot(PageViewAnimation.getInstance().getPageViewAnime(), i, child);        child.setId(i);        child.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                int id = v.getId();                //设置切换动画类型                PageViewAnimation.getInstance().setPageViewAnime(id);                //保存切换动画类型到文件                setPageViewAnimaType(id);                //重置焦点                for (int j = 0; j < count; j++) {                    TextView child = (TextView) pageAnimViewGroup.getChildAt(j);                    setAnimPageFocusDot(id, j, child);                }            }        });        child.setOnTouchListener(getHapticFeedbackTouchListener());    }    mOverviewPanel.setAlpha(0f);    ...}/** * add by steven zhang 20170105 * 设置页面切换动画 */private void setPageViewAnimaType(int type) {    SharedPreferences.Editor editor = mSharedPrefs.edit();    editor.putInt(PAGEVIEWANIMATION_TYPE, type);    editor.apply();}/** * add by steven zhang 20170105 * 设置切换动画焦点 * @param selected * @param index * @param child */private void setAnimPageFocusDot(int selected, int index, TextView child) {    Drawable drawable = getResources().getDrawable(R.drawable.focus_dot);    Drawable[] drawables = child.getCompoundDrawables();    child.setCompoundDrawables(null, drawables[1], null, null);    if (selected == index) {        drawable.setBounds(0, 0, 10, 10);        child.setCompoundDrawables(null, drawables[1], null, drawable);    }}

上面的代码中,有详细的注释,就不过多分析了,在Launcher.java主要做的事情,就是初始化切换动画的类型及其UI。

PageViewAnimation.java

PageViewAnimation.java是具体的屏幕切换实现,里面实现了各种切换效果。

//add by steven zhang 20170105public class PageViewAnimation {    private static final String TAG = "PageViewAnimation";    public static final int PAGEVIEW_ANIMATION_NORMAL               = 0;//经典动画    public static final int PAGEVIEW_ANIMATION_TURNTABLE            = 1;//转盘动画    public static final int PAGEVIEW_ANIMATION_LAYERED              = 2;//层叠动画    public static final int PAGEVIEW_ANIMATION_ROTATE               = 3;//旋转动画    public static final int PAGEVIEW_ANIMATION_PAGETURN             = 4;//翻页动画    public static final int PAGEVIEW_ANIMATION_ROTATEBYLEFTTOPPOINT = 5;//绕左上角旋转的动画    public static final int PAGEVIEW_ANIMATION_ROTATEBYCENTERPOINT  = 6;//绕中心点旋转的动画    public static final int PAGEVIEW_ANIMATION_BLOCKS               = 7;//设置方块动画    private static ZInterpolator mZInterpolator = new ZInterpolator(0.5f);    private static AccelerateInterpolator mAlphaInterpolator = new AccelerateInterpolator(0.9f);    private static DecelerateInterpolator mLeftScreenAlphaInterpolator = new DecelerateInterpolator(4);    private static PageViewAnimation mInstance;    private static float CAMERA_DISTANCE = 6500;    private static float TRANSITION_SCALE_FACTOR = 0.74f;    private static float TRANSITION_PIVOT = 0.65f;    private static float TRANSITION_MAX_ROTATION = 24;    private float mTranslationX = 0f;    private float mScale = 1f;    private float mAlpha = 1f;    private float mRotation = 0f;    private float mRotationY = 0f;    private float mPivotX = 0f;    private float mPivotY = 0f;    private int mAnimaType = PAGEVIEW_ANIMATION_NORMAL;    public static PageViewAnimation getInstance() {        if (mInstance == null) {            synchronized (PageViewAnimation.class) {                if (mInstance == null) {                    mInstance = new PageViewAnimation();                }            }        }        return mInstance;    }    public void setPageViewAnime(int type) {        mAnimaType = type;    }    public int getPageViewAnime() {        return mAnimaType;    }    public void pageViewAnime(float scrollProgress, int i, int count, float density, View v) {        resetAttr(v);        switch (mAnimaType) {        case PAGEVIEW_ANIMATION_TURNTABLE:            mRotation = -TRANSITION_MAX_ROTATION * scrollProgress;            mPivotX = v.getMeasuredWidth() * 0.5f;            mPivotY = v.getMeasuredHeight();            break;        case PAGEVIEW_ANIMATION_LAYERED:            {                float minScrollProgress = Math.min(0, scrollProgress);                float interpolatedProgress;                mTranslationX = minScrollProgress * v.getMeasuredWidth();                interpolatedProgress = mZInterpolator.getInterpolation(Math.abs(minScrollProgress));                mScale = (1 - interpolatedProgress) + interpolatedProgress * TRANSITION_SCALE_FACTOR;                if ((scrollProgress < 0)) {                    mAlpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));                } else {                    mAlpha = mLeftScreenAlphaInterpolator.getInterpolation(1 - scrollProgress);                }            }            break;        case PAGEVIEW_ANIMATION_ROTATE:            mPivotX = v.getMeasuredWidth() * 0.5f;            mPivotY = v.getMeasuredHeight();            mRotationY = -90 * scrollProgress;            mTranslationX = scrollProgress * v.getMeasuredWidth();            mAlpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));            break;        case PAGEVIEW_ANIMATION_PAGETURN:            mPivotX = 0.0f;            mPivotY = 0.0f;            mRotationY = -90 * scrollProgress;            mTranslationX = scrollProgress * v.getMeasuredWidth();            mAlpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));            break;        case PAGEVIEW_ANIMATION_ROTATEBYLEFTTOPPOINT:            mPivotX = 0.0f;            mPivotY = 0.0f;            mRotation = -90 * scrollProgress;            mTranslationX = scrollProgress * v.getMeasuredWidth();            mAlpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));            break;        case PAGEVIEW_ANIMATION_ROTATEBYCENTERPOINT:            mPivotX = v.getMeasuredWidth() * 0.5f;            mPivotY = v.getMeasuredHeight() * 0.5f;            mRotation = -90 * scrollProgress;            mTranslationX = scrollProgress * v.getMeasuredWidth();            mAlpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));            break;        case PAGEVIEW_ANIMATION_BLOCKS:            if (scrollProgress < 0) {                mPivotX = 0.0f;            } else {                mPivotX = v.getMeasuredWidth();            }            mRotationY = -90 * scrollProgress;            break;        case PAGEVIEW_ANIMATION_NORMAL:        default:            break;        }        overScrollAnimation(scrollProgress, i, count, density, v);        setViewAttr(v);        showOrHideView(v);    }    /**     * 设置转盘动画     *      * @param scrollProgress     * @param view     */    public void setTurntableAnim(float scrollProgress, int i, int count, float density, View v) {        resetAttr(v);        mRotation = -TRANSITION_MAX_ROTATION * scrollProgress;        mPivotX = v.getMeasuredWidth() * 0.5f;        mPivotY = v.getMeasuredHeight();        overScrollAnimation(scrollProgress, i, count, density, v);        setViewAttr(v);        showOrHideView(v);    }    /**     * 设置层叠动画     *      * @param scrollProgress     * @param density     * @param v     */    public void setLayeredAnim(float scrollProgress, int i, int count, float density, View v) {        resetAttr(v);        float minScrollProgress = Math.min(0, scrollProgress);        float interpolatedProgress;        mTranslationX = minScrollProgress * v.getMeasuredWidth();        interpolatedProgress = mZInterpolator.getInterpolation(Math.abs(minScrollProgress));        mScale = (1 - interpolatedProgress) + interpolatedProgress * TRANSITION_SCALE_FACTOR;        if ((scrollProgress < 0)) {            mAlpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));        } else {            mAlpha = mLeftScreenAlphaInterpolator.getInterpolation(1 - scrollProgress);        }        overScrollAnimation(scrollProgress, i, count, density, v);        setViewAttr(v);        showOrHideView(v);    }    /**     * 经典模式,水平左出右进     * @param scrollProgress     * @param i     * @param count     * @param density     * @param v     */    public void setNormalAnim(float scrollProgress, int i, int count, float density, View v) {        resetAttr(v);        overScrollAnimation(scrollProgress, i, count, density, v);        setViewAttr(v);        showOrHideView(v);    }    /**     * 设置旋转动画     * @param scrollProgress     * @param i     * @param count     * @param density     * @param v     */    public void  setRotateAnim(float scrollProgress, int i, int count, float density, View v) {        resetAttr(v);        mPivotX = v.getMeasuredWidth() * 0.5f;        mPivotY = v.getMeasuredHeight();        mRotationY = -90 * scrollProgress;        mTranslationX = scrollProgress * v.getMeasuredWidth();        mAlpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));        overScrollAnimation(scrollProgress, i, count, density, v);        setViewAttr(v);        showOrHideView(v);    }    /**     * 设置翻页动画     * @param scrollProgress     * @param i     * @param count     * @param density     * @param v     */    public void setPageTurnAnim(float scrollProgress, int i, int count, float density, View v) {        resetAttr(v);        mPivotX = 0.0f;        mPivotY = 0.0f;        mRotationY = -90 * scrollProgress;        mTranslationX = scrollProgress * v.getMeasuredWidth();        mAlpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));        overScrollAnimation(scrollProgress, i, count, density, v);        setViewAttr(v);        showOrHideView(v);    }    /**     * 设置以左上角为中心点的旋转     * @param scrollProgress     * @param i     * @param count     * @param density     * @param v     */    public void setRotateByLeftTopPointAnim(float scrollProgress, int i, int count, float density, View v) {        resetAttr(v);        mPivotX = 0.0f;        mPivotY = 0.0f;        mRotation = -90 * scrollProgress;        mTranslationX = scrollProgress * v.getMeasuredWidth();        mAlpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));        overScrollAnimation(scrollProgress, i, count, density, v);        setViewAttr(v);        showOrHideView(v);    }    /**     * 设置以正中心为中心点的旋转     * @param scrollProgress     * @param i     * @param count     * @param density     * @param v     */    public void setRotateByCenterPointAnim(float scrollProgress, int i, int count, float density, View v) {        resetAttr(v);        mPivotX = v.getMeasuredWidth() * 0.5f;        mPivotY = v.getMeasuredHeight() * 0.5f;        mRotation = -90 * scrollProgress;        mTranslationX = scrollProgress * v.getMeasuredWidth();        mAlpha = mAlphaInterpolator.getInterpolation(1 - Math.abs(scrollProgress));        overScrollAnimation(scrollProgress, i, count, density, v);        setViewAttr(v);        showOrHideView(v);    }    /**     * 设置方块动画的旋转     * @param scrollProgress     * @param i     * @param count     * @param density     * @param v     */    public void setBlocksAnim(float scrollProgress, int i, int count, float density, View v) {        resetAttr(v);        if (scrollProgress < 0) {            mPivotX = 0.0f;        } else {            mPivotX = v.getMeasuredWidth();        }        mRotationY = -90 * scrollProgress;        overScrollAnimation(scrollProgress, i, count, density, v);        setViewAttr(v);        showOrHideView(v);    }    /**     * 设置View的属性     * @param v     */    private void setViewAttr(View v) {        v.setPivotY(mPivotY);        v.setPivotX(mPivotX);        v.setRotation(mRotation);        v.setRotationY(mRotationY);        v.setTranslationX(mTranslationX);        v.setScaleX(mScale);        v.setScaleY(mScale);        v.setAlpha(mAlpha);    }    /**     * 根据alpha的值来判断是否显示view     *      * @param alpha     * @param v     */    private void showOrHideView(View v) {        if (mAlpha == 0) {            v.setVisibility(View.INVISIBLE);        } else if (v.getVisibility() != View.VISIBLE) {            v.setVisibility(View.VISIBLE);        }    }    /**     * 重置属性     */    private void resetAttr(View v) {        mTranslationX = 0f;        mScale = 1f;        mAlpha = 1f;        mRotation = 0f;        mRotationY = 0f;        mPivotX = v.getMeasuredWidth() * 0.5f;        mPivotY = v.getMeasuredHeight() * 0.5f;    }    /**     * 设置pageView左右两端时的动画     *      * @param scrollProgress     * @param i     * @param count     * @param density     * @param v     */    public void overScrollAnimation(float scrollProgress, int i,            int count, float density, View v) {        float xPivot = TRANSITION_PIVOT;        boolean isOverscrollingFirstPage = scrollProgress < 0;        boolean isOverscrollingLastPage = scrollProgress > 0;        int pageWidth = v.getMeasuredWidth();        int pageHeight = v.getMeasuredHeight();        v.setCameraDistance(density * CAMERA_DISTANCE);        if (i == 0 && isOverscrollingFirstPage) {            mPivotX = xPivot * pageWidth;            mPivotY = pageHeight / 2.0f;            mRotation = 0f;            mRotationY = -TRANSITION_MAX_ROTATION * scrollProgress;            mScale = 1.0f;            mAlpha = 1.0f;            mTranslationX = 0f;        } else if (i == count - 1 && isOverscrollingLastPage) {            mPivotX = xPivot * pageWidth;            mPivotY = pageHeight / 2.0f;            mRotation = 0f;            mRotationY = -TRANSITION_MAX_ROTATION * scrollProgress;            mScale = 1.0f;            mAlpha = 1.0f;            mTranslationX = 0f;        }    }    private static class ZInterpolator implements TimeInterpolator {        private float focalLength;        public ZInterpolator(float foc) {            focalLength = foc;        }        public float getInterpolation(float input) {            return (1.0f - focalLength / (focalLength + input)) /                    (1.0f - focalLength / (focalLength + 1.0f));        }    }}

Workspace.java

Workspace.java就是监听屏幕滑动时的位移变化,然后通过PageViewAnimation类,实现真正的动画切换效果。

protected void screenScrolled(int screenCenter) {    ...     //add by steven zhang 20170105    for (int i = 0; i < getChildCount(); i++) {        View v = getPageAt(i);        if (v != null) {             float scrollProgress = getScrollProgress(screenCenter, v, i);             //根据滑动位置设置每个屏幕的动画效果             PageViewAnimation.getInstance().pageViewAnime(scrollProgress, i, getChildCount(), mDensity, v);         }    }    ...}

总结

通过增加屏幕切换的功能,我们可以了解到增加这个需求可以分为三步:
1.初始化类型及UI(Launcher.java)
2.实现具体的需求(PageViewAnimation.java)
3.监听数据变化(Workspace.java)

修改的资源及源码包

0 0
原创粉丝点击