刚刚开始学滑动菜单,参考博主jj的android 滑动菜单SlidingMenu的实现
原博客的实现效果(自己的为了简单,UI就没有实现的那么漂亮)
以下是学习心得:
(1)XML 讲解 ,先上代码
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:id="@+id/my_right" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:layout_marginLeft="80dp" > <ListView android:id="@+id/my_list_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout> <LinearLayout android:id="@+id/my_left" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ImageView android:id="@+id/my_image" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitXY" android:src="@drawable/bg_guide_5"/> </LinearLayout> </RelativeLayout>
这个xml的写法也要有要求的,里面定义两个LinearLayout 要滑出显示的菜单的(就是有listview的LinearLayout) 一定要放在上面,不然的话第一个和第二个linearlayout会覆盖层叠的显示出来
(2)java代码讲解
1 程序必须实现两个接口,分别是OnGestureListener,OnTouchListener
public class MyTest extends Activity implements OnGestureListener,OnTouchListener{ private LinearLayout right_layout; //右边的linearlayout private LinearLayout left_layout; private ListView listView; private int SPEED=30;//菜单显示速度 private int SCREEN_WIDTH; //手机屏幕的宽度 private int MAX_WIDTH; //右边linearlayout的宽度 private int mScrollX=0; //右边菜单偏移坐标 private boolean isScrolling=false; private GestureDetector gestureDetector; private String title[] = { "待发送队列", "同步分享设置", "编辑我的资料", "找朋友", "告诉朋友", "节省流量", "推送设置", "版本更新", "意见反馈", "积分兑换", "精品应用", "常见问题", "退出当前帐号" }; boolean hasMeasured=false;
2 在onCreate方法中去掉activity的标题
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.mytest); initView(); }
3 initView()方法 初始化部件 设置监听
public void initView(){ //右边菜单的布局文件 right_layout=(LinearLayout)findViewById(R.id.my_right); //左边打开activity显示的布局文件 left_layout=(LinearLayout)findViewById(R.id.my_left); //获取屏幕的宽度 SCREEN_WIDTH=getWindow().getWindowManager().getDefaultDisplay().getWidth(); System.out.println("SCREEN_WIDTH:"+SCREEN_WIDTH); listView=(ListView)findViewById(R.id.my_list_view); //为listview 简单设置数据 listView.setAdapter(new ArrayAdapter<String>(MyTest.this, android.R.layout.simple_list_item_1, title)); gestureDetector=new GestureDetector(this, this); //设置touch事件的监听 left_layout.setOnTouchListener(this); right_layout.setOnTouchListener(this); //获取右边 布局(right_layout)文件的宽度 getMAX_WIDTH(); }
4 方法getMAX_WIDTH()获取右边布局(right_layout)的宽,作为左边布局移动的距离
public void getMAX_WIDTH() { ViewTreeObserver viewTreeObserver = left_layout.getViewTreeObserver(); // 获取控件宽度 viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() { @Override public boolean onPreDraw() { if (!hasMeasured) { SCREEN_WIDTH = getWindowManager().getDefaultDisplay() .getWidth(); RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) left_layout .getLayoutParams(); layoutParams.width = SCREEN_WIDTH; left_layout.setLayoutParams(layoutParams); MAX_WIDTH = right_layout.getWidth(); Log.v("fighter", "MAX_WIDTH=" + MAX_WIDTH + "width=" + SCREEN_WIDTH); hasMeasured = true; } return true; } }); }
在这里做下笔记:
函数:
16 /**注册一个回调函数,当一个视图树将要绘制时调用这个回调函数。 17 *参数 listener 将要被添加的回调函数 18 *异常 IllegalStateException 如果isAlive() 返回false 19 */ 20 public void addOnPreDrawListener (ViewTreeObserver.OnPreDrawListener listener) 21
使用ViewTreeObserver 监听左边layout 绘图之前调用该方法,所以才可以得到右边layout的宽度,否则在left_layout绘制之后,那么将得不到right_layout的真正宽度,在其他方法中再使用right_layout.getWidth(); 得到的值是0
5 实现OnGestureListener接口
@Override public boolean onDown(MotionEvent arg0) { mScrollX=0; isScrolling = false; return true; } @Override public boolean onFling(MotionEvent event, MotionEvent arg1, float arg2, float arg3) { return false; } @Override public void onLongPress(MotionEvent arg0) { } @Override public boolean onScroll(MotionEvent event0, MotionEvent event1, float distanceX, float distanceY) { isScrolling = true; RelativeLayout.LayoutParams layoutParams=(RelativeLayout.LayoutParams) left_layout.getLayoutParams(); mScrollX += distanceX;// distanceX:向左为正,右为负 layoutParams.leftMargin-=mScrollX; System.out.println("*********************************"); System.out.println(event1.getX() -event0.getX()+"(-------)"+mScrollX+"(-------)"+distanceX); if(layoutParams.leftMargin <= -MAX_WIDTH){ layoutParams.leftMargin=-MAX_WIDTH; isScrolling = false; }else if(layoutParams.leftMargin >=0){ layoutParams.leftMargin=0; isScrolling = false; } left_layout.setLayoutParams(layoutParams); return false; } @Override public void onShowPress(MotionEvent arg0) { } @Override public boolean onSingleTapUp(MotionEvent event) { System.out.println("执行 onSingleTapUp"); RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) left_layout .getLayoutParams(); // 左移动 if (layoutParams.leftMargin >= 0) { new myAscy().execute(-SPEED); } else { // 右移动 new myAscy().execute(SPEED); } return true; }
这里的onScroll方法做下笔记:
一定要使用一个变量mScrollX来保存叠加distanceX的值,不能直接使用distanceX直接和layoutParams.leftMargin 操作,如果不叠加的话,也可以使用event0.getX() -event1.getX() 来代替mScrollX
6 实现AsyncTask 类,理解比较简单就不重复描述了
class myAscy extends AsyncTask<Integer, Integer, Void>{ @Override protected Void doInBackground(Integer... params) { int times=MAX_WIDTH/Math.abs(params[0]); System.out.println("times:"+times+";max_width:"+MAX_WIDTH); for(int i=0;i<times;i++){ publishProgress(params[0]); try { Thread.sleep(Math.abs(params[0])); } catch (InterruptedException e) { e.printStackTrace(); } } return null; } @Override protected void onProgressUpdate(Integer... values) { RelativeLayout.LayoutParams LayoutParams=(RelativeLayout.LayoutParams) left_layout.getLayoutParams(); LayoutParams.width = SCREEN_WIDTH; System.out.println("values"+values[0]); //向右移动 if(values[0] > 0){ LayoutParams.leftMargin=Math.min(LayoutParams.leftMargin+values[0], 0); }else{ LayoutParams.leftMargin=Math.max(LayoutParams.leftMargin+values[0], -MAX_WIDTH); } left_layout.setLayoutParams(LayoutParams); } }
7 实现OnTouchListener接口
@Override public boolean onTouch(View arg0, MotionEvent event) { if(event.getAction() ==MotionEvent.ACTION_UP && isScrolling==true){ RelativeLayout.LayoutParams layoutParams=(RelativeLayout.LayoutParams) left_layout.getLayoutParams(); if(layoutParams.leftMargin < -SCREEN_WIDTH/2){ new myAscy().execute(-SPEED); }else{ new myAscy().execute(SPEED); } } return gestureDetector.onTouchEvent(event); }
这里做下笔记, 当用户执行ACTION_UP事件的时候 一定要 &&上 isScrolling 属性,否则的话菜单可能打不来,或者打开后自动合上,所以isScrolling属性是必须的
总结:
(1)缺陷1:ListView 的左右 不起效果,代码还不够精简,准备继续向原博客大神学习,实现ListView 的左右滑动
(2)缺陷2:显示菜单的时候菜单不是从右边滑出来的,而是靠左边布局文件移动慢慢浮现的,所以下次这个缺陷也要修改好
虽然已把李刚的android疯狂讲义大部分看完,也把大部分代码敲了一遍,但是总觉得还不是那么实在,看来还是得继续实战多一点小程序,练多点