观察qqminihd界面,发现其界面能够左右滑动来实现两侧菜单效果。
自定义Layout:ScrollLayout.java
直接贴出代码:
1 package grimbo.android.demo.slidingmenu;
2
3 import android.content.Context;
4 import android.util.AttributeSet;
5 import android.util.Log;
6 import android.view.GestureDetector;
7 import android.view.GestureDetector.OnGestureListener;
8 import android.view.MotionEvent;
9 import android.view.View;
10 import android.view.ViewConfiguration;
11 import android.view.animation.AnimationUtils;
12 import android.widget.LinearLayout;
13 import android.widget.Scroller;
14
15 public class ScrollLayout extends LinearLayout {
16
17 // private static final String TAG = "scroller";
18
19 private Scroller scroller;
20
21 private int currentScreenIndex;
22
23 private GestureDetector gestureDetector;
24
25 // 设置一个标志位,防止底层的onTouch事件重复处理UP事件
26 private boolean fling;
27
28 /**
29 * 菜单栏的宽度
30 */
31 int menuWidth=80;
32
33 /**
34 * 显示左边菜单
35 * 否则显示右边菜单
36 */
37 private boolean showLeft=true;
38
39 /**
40 * 滚出边界监听器
41 */
42 private OnScrollSideChangedListener scrollSideChangedListener;
43
44 public Scroller getScroller() {
45 return scroller;
46 }
47
48 public OnScrollSideChangedListener getScrollSideChangedListener() {
49 return scrollSideChangedListener;
50 }
51
52 public void setScrollSideChangedListener(
53 OnScrollSideChangedListener scrollSideChangedListener) {
54 this.scrollSideChangedListener = scrollSideChangedListener;
55 }
56
57 public ScrollLayout(Context context, AttributeSet attrs) {
58 super(context, attrs);
59 initView(context);
60 }
61
62 public ScrollLayout(Context context) {
63 super(context);
64 initView(context);
65 }
66
67 private void initView(final Context context) {
68 this.scroller = new Scroller(context,AnimationUtils.loadInterpolator(context,
69 android.R.anim.overshoot_interpolator));
70
71 this.gestureDetector = new GestureDetector(new OnGestureListener() {
72
73 @Override
74 public boolean onSingleTapUp(MotionEvent e) {
75 return false;
76 }
77
78 @Override
79 public void onShowPress(MotionEvent e) {
80 }
81
82 @Override
83 public boolean onScroll(MotionEvent e1, MotionEvent e2,
84 float distanceX, float distanceY) {
85
86 {// 防止向第一页之前移动
87 if(1==currentScreenIndex)
88 {
89 int screenLeft=getWidth()-menuWidth;
90 if(showLeft && getScrollX()>screenLeft)
91 {
92 showLeft=false;
93 // Log.e("TAG","显示右边菜单栏");
94 if(null!=scrollSideChangedListener)
95 scrollSideChangedListener.onScrollSideChanged(ScrollLayout.this, showLeft);
96 }
97 else if(!showLeft && getScrollX()<screenLeft)
98 {
99 showLeft=true;
100 // Log.e("TAG","显示左边菜单栏");
101 if(null!=scrollSideChangedListener)
102 scrollSideChangedListener.onScrollSideChanged(ScrollLayout.this, showLeft);
103 }
104 }
105
106 fling = true;
107 scrollBy((int) distanceX, 0);
108 // Log.d("TAG", "on scroll>>>>>>>>>>>>>>>>>移动<<<<<<<<<<<<<<>>>");
109 }
110 return true;
111 }
112
113 @Override
114 public void onLongPress(MotionEvent e) {
115 }
116
117 @Override
118 public boolean onFling(MotionEvent e1, MotionEvent e2,
119 float velocityX, float velocityY) {
120
121 if (Math.abs(velocityX) > ViewConfiguration.get(context)
122 .getScaledMinimumFlingVelocity())
123 {// 判断是否达到最小轻松速度,取绝对值的
124 fling = true;
125 snapToDestination();
126 // Log.d(TAG, "on scroll>>>>>>>>>>>>>>>>>滑动<<<<<<<<<<<<<<>>>");
127 }
128
129 return true;
130 }
131
132 @Override
133 public boolean onDown(MotionEvent e) {
134 return false;
135 }
136 });
137
138 }
139 //每一个屏的边界值
140 //0----[getWidth()-20]----[2*getWidth()-20]-----[3*getWidth()-40]
141
142
143 @Override
144 protected void onLayout(boolean changed, int left, int top, int right,
145 int bottom) {
146 /**
147 * 设置布局,将子视图顺序横屏排列
148 */
149 super.onLayout(changed, left, top, right, bottom);
150 int move=getWidth()-menuWidth;
151 for (int i = 0; i < getChildCount(); i++)
152 {
153 View child = getChildAt(i);
154 // child.setVisibility(View.VISIBLE);
155 //移动一定的距离
156 child.layout(child.getLeft()+move,child.getTop(),child.getRight()+move,child.getBottom());
157 }
158 }
159
160 @Override
161 public void computeScroll() {
162 if (scroller.computeScrollOffset()) {
163 // Log.d(TAG, ">>>>>>>>>>computeScroll>>>>>"+scroller.getCurrX());
164 scrollTo(scroller.getCurrX(), 0);
165 postInvalidate();
166 }
167 }
168
169 @Override
170 public boolean onTouchEvent(MotionEvent event) {
171
172 float x2s=getScrollX()+event.getX();
173
174 if(x2s<getWidth()-menuWidth || x2s>2*getWidth()-menuWidth)
175 {//动作在区域外面
176 if(!fling)//没有在滑动
177 {
178 // Log.d(TAG, "on scroll>>>>>>>>>>>>>>>>>动作在区域外面 没有在滑动<<<<<<<<<<<<<<>>>");
179 return false;
180 }
181 else if(MotionEvent.ACTION_UP!=event.getAction())
182 {//否则如果也不是抬起手势,则强制模拟抬起
183 snapToDestination();
184 fling = false;
185 // Log.d(TAG, "on scroll>>>>>>>>>>>>>>>>>动作在区域外面 在滑动 也不是抬起手势<<<<<<<<<<<<<<>>>");
186 return false;
187 }
188 // Log.e(TAG, "on scroll>>>>>>>>>>>>>>>>>动作在区域外面 在滑动 是抬起手势<<<<<<<<<<<<<<>>>");
189 }
190
191 gestureDetector.onTouchEvent(event);
192
193 switch (event.getAction()) {
194 case MotionEvent.ACTION_DOWN:
195 break;
196 case MotionEvent.ACTION_MOVE:
197 break;
198 case MotionEvent.ACTION_UP:
199 // Log.d(TAG, ">>ACTION_UP:>>>>>>>> MotionEvent.ACTION_UP>>>>>");
200 // if (!fling)
201 {
202 snapToDestination();
203 }
204 fling = false;
205 break;
206 default:
207 break;
208 }
209 return true;
210 }
211
212 /**
213 * 切换到指定屏
214 *
215 * @param whichScreen
216 */
217 public void scrollToScreen(int whichScreen) {
218 if (getFocusedChild() != null && whichScreen != currentScreenIndex
219 && getFocusedChild() == getChildAt(currentScreenIndex)) {
220 getFocusedChild().clearFocus();
221 }
222 int delta = 0;
223
224 if(whichScreen==0)
225 delta= - getScrollX();
226 else if(whichScreen==1)
227 delta= getWidth()-menuWidth- getScrollX();
228 else if(whichScreen==2)
229 delta= 2*(getWidth()-menuWidth)- getScrollX();
230 else
231 return;
232 // delta = whichScreen * getWidth() - getScrollX();
233
234 scroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2);
235 invalidate();
236
237 currentScreenIndex = whichScreen;
238 }
239
240 /**
241 * 根据当前x坐标位置确定切换到第几屏
242 */
243 private void snapToDestination() {
244
245 if(getScrollX()<(getWidth()-menuWidth)/2)
246 scrollToScreen(0);
247 else if(getScrollX()<(getWidth()-menuWidth+getWidth()/2))
248 scrollToScreen(1);
249 else
250 scrollToScreen(2);
251 }
252
253 public interface OnScrollSideChangedListener
254 {
255 public void onScrollSideChanged(View v,boolean leftSide);
256 }
257 }
接下来,在定义activity里面的布局my_layout.xml:
1 <?xml version="1.0" encoding="utf-8"?>
2 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res/grimbo.android.demo.slidingmenu"
4 android:id="@+id/FrameLayout1"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent" >
7 <LinearLayout
8 android:layout_width="match_parent"
9 android:layout_height="match_parent"
10 android:id="@+id/left_menu"
11 android:background="#333"
12 android:orientation="vertical" >
13
14 <Button
15 android:layout_width="200dp"
16 android:layout_height="wrap_content"
17 android:text="左菜单一" />
18 <Button
19 android:layout_width="200dp"
20 android:layout_height="wrap_content"
21 android:text="左菜单二" />
22 </LinearLayout>
23
24 <LinearLayout
25 android:id="@+id/right_menu"
26 android:layout_width="match_parent"
27 android:layout_height="match_parent"
28 android:background="#666"
29 android:orientation="horizontal" >
30 <LinearLayout
31 android:layout_width="wrap_content"
32 android:layout_height="wrap_content"
33 android:layout_weight="1"
34 android:orientation="vertical" >
35 </LinearLayout>
36 <LinearLayout
37 android:layout_width="200dp"
38 android:layout_height="wrap_content"
39 android:orientation="vertical" >
40 <Button
41 android:layout_width="match_parent"
42 android:layout_height="wrap_content"
43 android:text="右菜单一" />
44 <Button
45 android:layout_width="match_parent"
46 android:layout_height="wrap_content"
47 android:text="右菜单二" />
48
49 </LinearLayout>
50
51 </LinearLayout>
52 <grimbo.android.demo.slidingmenu.ScrollLayout
53 android:layout_width="match_parent"
54 android:orientation="vertical"
55 android:id="@+id/my_scrollLayout"
56 android:layout_height="match_parent">
57 <LinearLayout
58 android:layout_width="match_parent"
59 android:layout_height="match_parent"
60 android:background="#aaa"
61 android:orientation="vertical" >
62
63
64 <Button
65 android:id="@+id/button1"
66 android:layout_width="match_parent"
67 android:layout_height="wrap_content"
68 android:text="Button Button" />
69
70 <Spinner
71 android:id="@+id/spinner1"
72 android:layout_width="match_parent"
73 android:layout_height="wrap_content" />
74
75 <SeekBar
76 android:id="@+id/seekBar1"
77 android:layout_width="match_parent"
78 android:layout_height="wrap_content" />
79
80 </LinearLayout>
81
82 </grimbo.android.demo.slidingmenu.ScrollLayout>
83
84 </FrameLayout>
最后,在activity里面的onCreate函数里加上:
1 setContentView(R.layout.my_layout); 2 3 final LinearLayout left=(LinearLayout)findViewById(R.id.left_menu); 4 final LinearLayout right=(LinearLayout)findViewById(R.id.right_menu); 5 right.setVisibility(View.GONE); 6 left.setVisibility(View.VISIBLE); 7 8 ScrollLayout mScrollLayout=(ScrollLayout)findViewById(R.id.my_scrollLayout); 9 mScrollLayout.setScrollSideChangedListener(new OnScrollSideChangedListener() { 10 @Override 11 public void onScrollSideChanged(View v, boolean leftSide) { 12 if(leftSide) 13 { 14 right.setVisibility(View.GONE); 15 left.setVisibility(View.VISIBLE); 16 }else 17 { 18 right.setVisibility(View.VISIBLE); 19 left.setVisibility(View.GONE); 20 } 21 } 22 });
大功告成!左右滑动是弹性效果也一并实现~