Android功能总结:仿照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源码:

View Code
  1 package com.yao_guet.test;
  2  
  3  import Android.content.Context;
  4  
  5  import android.graphics.Canvas;
  6  
  7  import android.util.AttributeSet;
  8  
  9  import android.util.Log;
 10  
 11  import android.view.MotionEvent;
 12  
 13  import android.view.VelocityTracker;
 14  
 15  import android.view.View;
 16  
 17  import android.view.ViewConfiguration;
 18  
 19  import android.view.ViewGroup;
 20  
 21  import android.widget.Scroller;
 22  
 23     /**
 24   
 25     * 仿Launcher中的WorkSapce,可以左右滑动切换屏幕的类
 26   
 27     * @author Yao.GUET
 28   
 29     * blog: http://blog.csdn.NET/Yao_GUET
 30   * date: 2011-05-04
 31   
 32     */
 33  
 34    public class ScrollLayout extends ViewGroup {
 35      
 36        private static final String TAG = "ScrollLayout";
 37      
 38        private Scroller mScroller;
 39      
 40        private VelocityTracker mVelocityTracker;
 41      
 42        private int mCurScreen;
 43      
 44        private int mDefaultScreen = 0;
 45      
 46        private static final int TOUCH_STATE_REST = 0;
 47      
 48        private static final int TOUCH_STATE_SCROLLING = 1;
 49      
 50        private static final int SNAP_VELOCITY = 600;
 51      
 52        private int mTouchState = TOUCH_STATE_REST;
 53      
 54        private int mTouchSlop;
 55      
 56        private float mLastMotionX;
 57      
 58        private float mLastMotionY;
 59      
 60        public ScrollLayout(Context context, AttributeSet attrs) {
 61          
 62            this(context, attrs, 0);
 63          
 64            // TODO Auto-generated constructor stub
 65          
 66        }
 67      
 68        public ScrollLayout(Context context, AttributeSet attrs, int defStyle) {
 69          
 70            super(context, attrs, defStyle);
 71          
 72            // TODO Auto-generated constructor stub
 73          
 74            mScroller = new Scroller(context);
 75          
 76            mCurScreen = mDefaultScreen;
 77          
 78            mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
 79          
 80        }
 81      
 82        @Override
 83      
 84        protected void onLayout(boolean changed, int l, int t, int r, int b) {
 85          
 86            // TODO Auto-generated method stub
 87          
 88            if (changed) {
 89              
 90                int childLeft = 0;
 91              
 92                final int childCount = getChildCount();
 93              
 94                for (int i=0; i< i++)>
 95                  
 96                    final View childView = getChildAt(i);
 97              
 98                if (childView.getVisibility() != View.GONE) {
 99                  
100                    final int childWidth = childView.getMeasuredWidth();
101                  
102                    childView.layout(childLeft, 0,
103                      
104                        childLeft+childWidth, childView.getMeasuredHeight());
105                  
106                    childLeft += childWidth;
107                  
108                }
109              
110            }
111          
112        }
113      
114    }
115  
116    @Override
117  
118    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
119  Log.e(TAG, "onMeasure");
120  
121    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
122  
123    final int width = MeasureSpec.getSize(widthMeasureSpec);
124  
125    final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
126  
127    if (widthMode != MeasureSpec.EXACTLY) {
128      
129        throw new IllegalStateException("ScrollLayout only canmCurScreen run at EXACTLY mode!");
130      
131    }
132  
133    final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
134  
135    if (heightMode != MeasureSpec.EXACTLY) {
136      
137        throw new IllegalStateException("ScrollLayout only can run at EXACTLY mode!");
138      
139    }
140  
141    // The children are given the same width and height as the scrollLayout
142  
143    final int count = getChildCount();
144  
145    for (int i = 0; i < count; i++) {
146      
147        getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
148      
149    }
150  
151    // Log.e(TAG, "moving to screen "+mCurScreen);
152  
153    scrollTo(mCurScreen * width, 0);
154  
155    }
156  
157     /**
158   
159     * According to the position of current layout
160   
161     * scroll to the destination page.
162   
163     */
164  
165    public void snapToDestination() {
166      
167        final int screenWidth = getWidth();
168      
169        final int destScreen = (getScrollX()+ screenWidth/2)/screenWidth;
170      
171        snapToScreen(destScreen);
172      
173    }
174  
175    public void snapToScreen(int whichScreen) {
176      
177        // get the valid layout page
178      
179        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount()-1));
180      
181        if (getScrollX() != (whichScreen*getWidth())) {
182          
183            final int delta = whichScreen*getWidth()-getScrollX();
184          
185            mScroller.startScroll(getScrollX(), 0,
186              
187                delta, 0, Math.abs(delta)*2);
188          
189            mCurScreen = whichScreen;
190          
191            invalidate(); // Redraw the layout
192          
193        }
194      
195    }
196  
197    public void setToScreen(int whichScreen) {
198      
199        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount()-1));
200      mCurScreen = whichScreen;
201      
202        scrollTo(whichScreen*getWidth(), 0);
203      
204    }
205  
206    public int getCurScreen() {
207      
208        return mCurScreen;
209      
210    }
211  
212    @Override
213  
214    public void computeScroll() {
215      
216        // TODO Auto-generated method stub
217      
218        if (mScroller.computeScrollOffset()) {
219          
220            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
221          
222            postInvalidate();
223          
224        }
225      
226    }
227  
228    @Override
229  
230    public boolean onTouchEvent(MotionEvent event) {
231      
232        // TODO Auto-generated method stub
233      
234        if (mVelocityTracker == null) {
235          
236            mVelocityTracker = VelocityTracker.obtain();
237          
238        }
239      
240        mVelocityTracker.addMovement(event);
241      
242        final int action = event.getAction();
243      
244        final float x = event.getX();
245      
246        final float y = event.getY();
247      
248        switch (action) {
249          
250            case MotionEvent.ACTION_DOWN:
251              
252                Log.e(TAG, "event down!");
253              
254                if (!mScroller.isFinished()){
255                  
256                    mScroller.abortAnimation();
257                  
258                }
259              
260                mLastMotionX = x;
261              
262                break;
263          
264            case MotionEvent.ACTION_MOVE:
265              
266                int deltaX = (int)(mLastMotionX - x);
267              
268                mLastMotionX = x;
269              
270                scrollBy(deltaX, 0);
271              
272                break;
273          
274            case MotionEvent.ACTION_UP:
275              
276                Log.e(TAG, "event : up");
277              
278                // if (mTouchState == TOUCH_STATE_SCROLLING) {
279              
280                final VelocityTracker velocityTracker = mVelocityTracker;
281              
282                velocityTracker.computeCurrentVelocity(1000);
283              
284                int velocityX = (int) velocityTracker.getXVelocity();
285              
286                Log.e(TAG, "velocityX:"+velocityX);
287              
288                if (velocityX > SNAP_VELOCITY && mCurScreen > 0) {
289                  
290                    // Fling enough to move left
291                  
292                    Log.e(TAG, "snap left");
293                  
294                    snapToScreen(mCurScreen - 1);
295                  
296                } else if (velocityX < -SNAP_VELOCITY
297                  
298                    && mCurScreen < getChildCount() - 1) {
299                  // Fling enough to move right
300                  
301                    Log.e(TAG, "snap right");
302                  
303                    snapToScreen(mCurScreen + 1);
304                  
305                } else {
306                  
307                    snapToDestination();
308                  
309                }
310              
311                if (mVelocityTracker != null) {
312                  
313                    mVelocityTracker.recycle();
314                  
315                    mVelocityTracker = null;
316                  
317                }
318              
319                // }
320              
321                mTouchState = TOUCH_STATE_REST;
322              
323                break;
324          
325            case MotionEvent.ACTION_CANCEL:
326              
327                mTouchState = TOUCH_STATE_REST;
328              
329                break;
330          
331        }
332      
333        return true;
334      
335    }
336  
337    @Override
338  
339    public boolean onInterceptTouchEvent(MotionEvent ev) {
340      
341        // TODO Auto-generated method stub
342      
343        Log.e(TAG, "onInterceptTouchEvent-slop:"+mTouchSlop);
344      
345        final int action = ev.getAction();
346      
347        if ((action == MotionEvent.ACTION_MOVE) &&
348          
349            (mTouchState != TOUCH_STATE_REST)) {
350          
351            return true;
352          
353        }
354      
355        final float x = ev.getX();
356      
357        final float y = ev.getY();
358      
359        switch (action) {
360          
361            case MotionEvent.ACTION_MOVE:
362              
363                final int xDiff = (int)Math.abs(mLastMotionX-x);
364              
365                if (xDiff>mTouchSlop) {
366                  
367                    mTouchState = TOUCH_STATE_SCROLLING;
368                  
369                }
370              
371                break;
372          
373            case MotionEvent.ACTION_DOWN:
374              
375                mLastMotionX = x;
376              
377                mLastMotionY = y;
378              
379                mTouchState = mScroller.isFinished()? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;
380              
381                break;
382          
383            case MotionEvent.ACTION_CANCEL:
384              
385            case MotionEvent.ACTION_UP:
386              
387                mTouchState = TOUCH_STATE_REST;
388              
389                break;
390          
391        }
392      
393        return mTouchState != TOUCH_STATE_REST;
394      
395    }
396      
397    }
398              }
399  }

 

测试程序布局:

View Code
 1 < ?xml version="1.0" encoding="utf-8"?>
 2 
 3   < com.yao_guet.test.ScrollLayout
 4 
 5   xmlns:android="http://schemas.android.com/apk/res/android"
 6 android:id="@+id/ScrollLayoutTest"
 7 
 8   android:layout_width="fill_parent"
 9 
10   android:layout_height="fill_parent">
11 
12   < LinearLayout
13 
14   android:background="#FF00"
15 
16   android:layout_width="fill_parent"
17 
18   android:layout_height="fill_parent">
19 
20   < FrameLayout
21 
22   android:background="#F0F0"
23 
24   android:layout_width="fill_parent"
25 
26   android:layout_height="fill_parent">
27 
28   < FrameLayout
29 
30   android:background="#F00F"
31 
32   android:layout_width="fill_parent"
33 
34   android:layout_height="fill_parent">
35 
36   < /FrameLayout>
37 
38   < LinearLayout
39 
40   android:background="#FF00"
41 
42   android:layout_width="fill_parent"
43 
44   android:layout_height="fill_parent">
45 
46   < Button
47 
48   android:layout_width="wrap_content"
49 
50   android:layout_height="wrap_content"
51 
52   android:text="Button1" />
53 
54   < /LinearLayout>
55 
56   < LinearLayout
57 
58   android:layout_width="wrap_content"
59 
60   android:layout_height="wrap_content">
61 
62   < Button
63 
64   android:layout_width="wrap_content"
65 
66   android:layout_height="wrap_content"
67 
68   android:text="Button2" />
69 
70   < /LinearLayout>
71 
72   < /com.yao_guet.test.ScrollLayout>

 

 

http://www.cnmsdn.com/html/201106/1308775819ID9981_6.html

 

posted @ 2012-05-26 14:45  miai7  阅读(531)  评论(0编辑  收藏  举报