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)
修改的资源及源码包
- Android 6.0 Launcher3 增加屏幕切换动画
- android屏幕切换动画
- android基础--屏幕切换动画
- Android的屏幕切换动画
- 在Launcher3中增加主题切换功能
- 在Launcher3中增加主题切换功能
- android 为viewPager增加动画切换效果
- Android的Activity屏幕切换动画
- Android的Activity屏幕切换动画
- Android的Activity屏幕切换动画(二)
- Android的Activity屏幕左右切换动画
- Android的Activity屏幕切换动画
- Android的Activity屏幕切换动画
- Android的Activity屏幕切换动画
- Android的Activity屏幕切换动画(一)-左右滑动切换
- Android的Activity屏幕切换动画(一)-左右滑动切换
- Android的Activity屏幕切换动画-左右滑动切换
- Android的Activity屏幕切换动画(一)-左右滑动切换
- 生成二叉树
- 教您使用java爬虫gecco抓取JD全部商品信息(二)
- ./configure详解
- SSM连接ORACLE数据库
- vim简单粗暴的配置
- Android 6.0 Launcher3 增加屏幕切换动画
- Atcoder Xor Sum 1月5日
- 三角形填充和分形练习
- 谈谈如何更有效率的交换友情链接
- ES6之let(理解闭包)和const命令
- Qt Charts 5.7.0 安装教程
- 线程安全单例模式(C++)
- java序列化和反序列化
- [bzoj1911]特别行动队