提取Launcher中的WorkSapce,可以左右滑动切换屏幕页面的类
By:Yao.GUET 转载请注明出处。
http://blog.csdn.net/Yao_GUET
对于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 plaincopy to clipboardprint?
01.package com.yao_guet.test;
02.import android.content.Context;
03.import android.graphics.Canvas;
04.import android.util.AttributeSet;
05.import android.util.Log;
06.import android.view.MotionEvent;
07.import android.view.VelocityTracker;
08.import android.view.View;
09.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.}
测试程序布局:
view plaincopy to clipboardprint?
01.<?xml version="1.0" encoding="utf-8"?>
02.<com.yao_guet.test.ScrollLayout
03. xmlns:android="http://schemas.android.com/apk/res/android"
04. android:id="@+id/ScrollLayoutTest"
05. android:layout_width="fill_parent"
06. android:layout_height="fill_parent">
07.<LinearLayout
08. android:background="#FF00"
09. 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>
源码下载:http://download.csdn.net/source/3246818
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Yao_GUET/archive/2011/05/04/6393962.aspx