Android功能总结:仿照Launcher的Workspace实现左右滑动切换

简介:       对于Launcher的桌面滑动大家应该都比较熟悉了,最好的体验应该是可以随着手指的滑动而显示不同位置的桌面, 比一般用ViewFlinger+动画所实现的手势切换页面感觉良好多了~~~~ 分析了一下Launcher中的WorkSpace,里面有太多的代码我们用不上了(拖拽,长按,,,),把里面的冗余代码去掉得到实现滑动切换屏幕所必需的。
 

 

 


对于Launcher的桌面滑动大家应该都比较熟悉了,最好的体验应该是可以随着手指的滑动而显示不同位置的桌面,

比一般用ViewFlinger+动画所实现的手势切换页面感觉良好多了~~~~

分析了一下Launcher中的WorkSpace,里面有太多的代码我们用不上了(拖拽,长按,,,),把里面的冗余代码去掉得到实现滑动切换屏幕所必需的。。。。

 

 

新建一个ScrollLayout类,继承自ViewGroup。

重写onMeasure和onLayout两个方法:

其中onMeasure方法中,得到ScrollLayout的布局方式(一般使用FILL_PARENT),然后再枚举其中所有的子view,设置它们的布局(FILL_PARENT),这样在ScrollLayout之中的每一个子view即为充满屏幕可以滑动显示的其中一页。

在onLayout方法中,横向画出每一个子view,这样所得到的view的高与屏幕高一致,宽度为getChildCount()-1个屏幕宽度的view。

添加一个Scroller来平滑过渡各个页面之间的切换,

重写onInterceptTouchEvent和onTouchEvent来响应手指按下划动时所需要捕获的消息,例如划动的速度,划动的距离等。再配合使用scrollBy (int x, int y)方法得到慢速滑动小距离的时候,所需要显示的内容。最后当手指起来时,根据划动的速度与跨度来判断是向左滑动一页还是向右滑动一页,确保每次用户操作结束之后显示的都是整体的一个子view.

ScrollLayout源码:

[java]  view plain copy
  1. package com.yao_guet.test;      
  2. import Android.content.Context;      
  3. import android.graphics.Canvas;      
  4. import android.util.AttributeSet;      
  5. import android.util.Log;      
  6. import android.view.MotionEvent;      
  7. import android.view.VelocityTracker;      
  8. import android.view.View;      
  9. import android.view.ViewConfiguration;      
  10. import android.view.ViewGroup;      
  11. import android.widget.Scroller;      
  12. /**   
  13.  * 仿Launcher中的WorkSapce,可以左右滑动切换屏幕的类   
  14.  * @author Yao.GUET   
  15.  * blog: http://blog.csdn.NET/Yao_GUET   
  16.  * date: 2011-05-04   
  17.  */      
  18. public class ScrollLayout extends ViewGroup {      
  19.     private static final String TAG = "ScrollLayout";      
  20.     private Scroller mScroller;      
  21.     private VelocityTracker mVelocityTracker;      
  22.           
  23.     private int mCurScreen;      
  24.     private int mDefaultScreen = 0;      
  25.           
  26.     private static final int TOUCH_STATE_REST = 0;      
  27.     private static final int TOUCH_STATE_SCROLLING = 1;      
  28.           
  29.     private static final int SNAP_VELOCITY = 600;      
  30.           
  31.     private int mTouchState = TOUCH_STATE_REST;      
  32.     private int mTouchSlop;      
  33.     private float mLastMotionX;      
  34.     private float mLastMotionY;      
  35.     public ScrollLayout(Context context, AttributeSet attrs) {      
  36.         this(context, attrs, 0);      
  37.         // TODO Auto-generated constructor stub      
  38.     }      
  39.     public ScrollLayout(Context context, AttributeSet attrs, int defStyle) {      
  40.         super(context, attrs, defStyle);      
  41.         // TODO Auto-generated constructor stub      
  42.         mScroller = new Scroller(context);      
  43.               
  44.         mCurScreen = mDefaultScreen;      
  45.         mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();      
  46.     }      
  47.     @Override      
  48.     protected void onLayout(boolean changed, int l, int t, int r, int b) {      
  49.         // TODO Auto-generated method stub      
  50.         if (changed) {      
  51.             int childLeft = 0;      
  52.             final int childCount = getChildCount();      
  53.                   
  54.             for (int i=0; i<childCount; i++) {      
  55.                 final View childView = getChildAt(i);      
  56.                 if (childView.getVisibility() != View.GONE) {      
  57.                     final int childWidth = childView.getMeasuredWidth();      
  58.                     childView.layout(childLeft, 0,       
  59.                             childLeft+childWidth, childView.getMeasuredHeight());      
  60.                     childLeft += childWidth;      
  61.                 }      
  62.             }      
  63.         }      
  64.     }      
  65.     @Override        
  66.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {         
  67.         Log.e(TAG, "onMeasure");      
  68.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);         
  69.         
  70.         final int width = MeasureSpec.getSize(widthMeasureSpec);         
  71.         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);         
  72.         if (widthMode != MeasureSpec.EXACTLY) {         
  73.             throw new IllegalStateException("ScrollLayout only canmCurScreen run at EXACTLY mode!");       
  74.         }         
  75.         
  76.         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);         
  77.         if (heightMode != MeasureSpec.EXACTLY) {         
  78.             throw new IllegalStateException("ScrollLayout only can run at EXACTLY mode!");      
  79.         }         
  80.         
  81.         // The children are given the same width and height as the scrollLayout         
  82.         final int count = getChildCount();         
  83.         for (int i = 0; i < count; i++) {         
  84.             getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);         
  85.         }         
  86.         // Log.e(TAG, "moving to screen "+mCurScreen);         
  87.         scrollTo(mCurScreen * width, 0);               
  88.     }        
  89.           
  90.     /**   
  91.      * According to the position of current layout   
  92.      * scroll to the destination page.   
  93.      */      
  94.     public void snapToDestination() {      
  95.         final int screenWidth = getWidth();      
  96.         final int destScreen = (getScrollX()+ screenWidth/2)/screenWidth;      
  97.         snapToScreen(destScreen);      
  98.     }      
  99.           
  100.     public void snapToScreen(int whichScreen) {      
  101.         // get the valid layout page      
  102.         whichScreen = Math.max(0, Math.min(whichScreen, getChildCount()-1));      
  103.         if (getScrollX() != (whichScreen*getWidth())) {      
  104.                   
  105.             final int delta = whichScreen*getWidth()-getScrollX();      
  106.             mScroller.startScroll(getScrollX(), 0,       
  107.                     delta, 0, Math.abs(delta)*2);      
  108.             mCurScreen = whichScreen;      
  109.             invalidate();       // Redraw the layout      
  110.         }      
  111.     }      
  112.           
  113.     public void setToScreen(int whichScreen) {      
  114.         whichScreen = Math.max(0, Math.min(whichScreen, getChildCount()-1));      
  115.         mCurScreen = whichScreen;      
  116.         scrollTo(whichScreen*getWidth(), 0);      
  117.     }      
  118.           
  119.     public int getCurScreen() {      
  120.         return mCurScreen;      
  121.     }      
  122.           
  123.     @Override      
  124.     public void computeScroll() {      
  125.         // TODO Auto-generated method stub      
  126.         if (mScroller.computeScrollOffset()) {      
  127.             scrollTo(mScroller.getCurrX(), mScroller.getCurrY());      
  128.             postInvalidate();      
  129.         }      
  130.     }      
  131.     @Override      
  132.     public boolean onTouchEvent(MotionEvent event) {      
  133.         // TODO Auto-generated method stub      
  134.               
  135.         if (mVelocityTracker == null) {      
  136.             mVelocityTracker = VelocityTracker.obtain();      
  137.         }      
  138.         mVelocityTracker.addMovement(event);      
  139.               
  140.         final int action = event.getAction();      
  141.         final float x = event.getX();      
  142.         final float y = event.getY();      
  143.               
  144.         switch (action) {      
  145.         case MotionEvent.ACTION_DOWN:      
  146.             Log.e(TAG, "event down!");      
  147.             if (!mScroller.isFinished()){      
  148.                 mScroller.abortAnimation();      
  149.             }      
  150.             mLastMotionX = x;      
  151.             break;      
  152.                   
  153.         case MotionEvent.ACTION_MOVE:      
  154.             int deltaX = (int)(mLastMotionX - x);      
  155.             mLastMotionX = x;      
  156.                   
  157.             scrollBy(deltaX, 0);      
  158.             break;      
  159.                   
  160.         case MotionEvent.ACTION_UP:      
  161.             Log.e(TAG, "event : up");         
  162.             // if (mTouchState == TOUCH_STATE_SCROLLING) {         
  163.             final VelocityTracker velocityTracker = mVelocityTracker;         
  164.             velocityTracker.computeCurrentVelocity(1000);         
  165.             int velocityX = (int) velocityTracker.getXVelocity();         
  166.             Log.e(TAG, "velocityX:"+velocityX);       
  167.                   
  168.             if (velocityX > SNAP_VELOCITY && mCurScreen > 0) {         
  169.                 // Fling enough to move left         
  170.                 Log.e(TAG, "snap left");      
  171.                 snapToScreen(mCurScreen - 1);         
  172.             } else if (velocityX < -SNAP_VELOCITY         
  173.                     && mCurScreen < getChildCount() - 1) {         
  174.                 // Fling enough to move right         
  175.                 Log.e(TAG, "snap right");      
  176.                 snapToScreen(mCurScreen + 1);         
  177.             } else {         
  178.                 snapToDestination();         
  179.             }         
  180.             if (mVelocityTracker != null) {         
  181.                 mVelocityTracker.recycle();         
  182.                 mVelocityTracker = null;         
  183.             }         
  184.             // }         
  185.             mTouchState = TOUCH_STATE_REST;         
  186.             break;      
  187.         case MotionEvent.ACTION_CANCEL:      
  188.             mTouchState = TOUCH_STATE_REST;      
  189.             break;      
  190.         }      
  191.               
  192.         return true;      
  193.     }      
  194.     @Override      
  195.     public boolean onInterceptTouchEvent(MotionEvent ev) {      
  196.         // TODO Auto-generated method stub      
  197.         Log.e(TAG, "onInterceptTouchEvent-slop:"+mTouchSlop);      
  198.               
  199.         final int action = ev.getAction();      
  200.         if ((action == MotionEvent.ACTION_MOVE) &&       
  201.                 (mTouchState != TOUCH_STATE_REST)) {      
  202.             return true;      
  203.         }      
  204.               
  205.         final float x = ev.getX();      
  206.         final float y = ev.getY();      
  207.               
  208.         switch (action) {      
  209.         case MotionEvent.ACTION_MOVE:      
  210.             final int xDiff = (int)Math.abs(mLastMotionX-x);      
  211.             if (xDiff>mTouchSlop) {      
  212.                 mTouchState = TOUCH_STATE_SCROLLING;      
  213.                       
  214.             }      
  215.             break;      
  216.                   
  217.         case MotionEvent.ACTION_DOWN:      
  218.             mLastMotionX = x;      
  219.             mLastMotionY = y;      
  220.             mTouchState = mScroller.isFinished()? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;      
  221.             break;      
  222.                   
  223.         case MotionEvent.ACTION_CANCEL:      
  224.         case MotionEvent.ACTION_UP:      
  225.             mTouchState = TOUCH_STATE_REST;      
  226.             break;      
  227.         }      
  228.               
  229.         return mTouchState != TOUCH_STATE_REST;      
  230.     }      
  231.           
  232. }      
 

 

 

测试程序布局:

 

[java]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>      
  2. <com.yao_guet.test.ScrollLayout      
  3.   xmlns:android="http://schemas.android.com/apk/res/android"      
  4.   android:id="@+id/ScrollLayoutTest"      
  5.   android:layout_width="fill_parent"      
  6.   android:layout_height="fill_parent">      
  7. <LinearLayout      
  8.   android:background="#FF00"      
  9.   android:layout_width="fill_parent"      
  10.   android:layout_height="fill_parent"></LinearLayout>      
  11.         
  12. <FrameLayout      
  13.   android:background="#F0F0"      
  14.   android:layout_width="fill_parent"      
  15.   android:layout_height="fill_parent"></FrameLayout>      
  16.         
  17. <FrameLayout      
  18.   android:background="#F00F"      
  19.   android:layout_width="fill_parent"      
  20.   android:layout_height="fill_parent">      
  21.   </FrameLayout>      
  22.         
  23. <LinearLayout      
  24.   android:background="#FF00"      
  25.   android:layout_width="fill_parent"      
  26.   android:layout_height="fill_parent">      
  27.   <Button      
  28.     android:layout_width="wrap_content"      
  29.     android:layout_height="wrap_content"      
  30.     android:text="Button1" />      
  31.   </LinearLayout>      
  32. <LinearLayout      
  33.   android:layout_width="wrap_content"      
  34.   android:layout_height="wrap_content">      
  35.   <Button      
  36.     android:layout_width="wrap_content"      
  37.     android:layout_height="wrap_content"      
  38.     android:text="Button2" />      
  39.   </LinearLayout>      
  40. </com.yao_guet.test.ScrollLayout>   
 

相关文章
|
6月前
|
Android开发
Android Launcher研究(二)-----------Launcher为何物,究竟是干什么
Android Launcher研究(二)-----------Launcher为何物,究竟是干什么
191 2
|
1月前
|
Android开发
Android开发表情emoji功能开发
本文介绍了一种在Android应用中实现emoji表情功能的方法,通过将图片与表情字符对应,实现在`TextView`中的正常显示。示例代码展示了如何使用自定义适配器加载emoji表情,并在编辑框中输入或删除表情。项目包含完整的源码结构,可作为开发参考。视频演示和源码详情见文章内链接。
68 4
Android开发表情emoji功能开发
|
24天前
|
安全 Android开发 iOS开发
Android vs iOS:探索移动操作系统的设计与功能差异###
【10月更文挑战第20天】 本文深入分析了Android和iOS两个主流移动操作系统在设计哲学、用户体验、技术架构等方面的显著差异。通过对比,揭示了这两种系统各自的独特优势与局限性,并探讨了它们如何塑造了我们的数字生活方式。无论你是开发者还是普通用户,理解这些差异都有助于更好地选择和使用你的移动设备。 ###
46 3
|
6月前
|
Android开发
Android 如何将定制的Launcher成为系统中唯一的Launcher
Android 如何将定制的Launcher成为系统中唯一的Launcher
224 2
|
3月前
|
编解码 测试技术 Android开发
Android经典实战之用 CameraX 库实现高质量的照片和视频拍摄功能
本文详细介绍了如何利用CameraX库实现高质量的照片及视频拍摄功能,包括添加依赖、初始化、权限请求、配置预览与捕获等关键步骤。此外,还特别针对不同分辨率和帧率的视频拍摄提供了性能优化策略,确保应用既高效又稳定。
315 1
Android经典实战之用 CameraX 库实现高质量的照片和视频拍摄功能
|
2月前
|
Android开发 开发者
Android平台无纸化同屏如何实现实时录像功能
Android平台无纸化同屏,如果需要本地录像的话,实现难度不大,只要复用之前开发的录像模块的就可以,对我们来说,同屏采集这块,只是数据源不同而已,如果是自采集的其他数据,我们一样可以编码录像。
|
3月前
|
图形学 Android开发
小功能⭐️Unity调用Android常用事件
小功能⭐️Unity调用Android常用事件
|
3月前
|
Android开发
Android使用ViewPager做无限轮播,人为滑动时停止
Android使用ViewPager做无限轮播,人为滑动时停止
77 2
|
5月前
|
数据库 Android开发 数据安全/隐私保护
在 Android Studio 中结合使用 SQLite 数据库实现简单的注册和登录功能
在 Android Studio 中结合使用 SQLite 数据库实现简单的注册和登录功能
228 2
|
5月前
|
Android开发
Android中如何快速的实现RecycleView的拖动重排序功能
使用`ItemTouchHelper`和自定义`Callback`,在`RecyclerView`中实现拖动排序功能。定义`ItemTouchHelperAdapter`接口,`Adapter`实现它以处理`onItemMove`方法。`SimpleItemTouchHelperCallback`设置拖动标志,如`LEFT`或`RIGHT`(水平拖动),并绑定到`RecyclerView`以启用拖动。完成这些步骤后,即可实现拖放排序。关注公众号“AntDream”获取更多内容。
112 3