android 滑动菜单SlidingMenu实现

首先我们看下面视图:

这种效果大家都不陌生,网上好多都说是仿人人网的,估计人家牛逼出来的早吧,我也参考了一一些例子,实现起来有三种方法,我下面简单介绍下:

方法一:其实就是对GestureDetector手势的应用及布局文件的设计.

布局文件main.xml 采用RelativeLayout布局.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <LinearLayout
        android:id="@+id/layout_right"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginLeft="50dp"
        android:orientation="vertical" >
        <AbsoluteLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@color/grey21"
            android:padding="10dp" >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="设置"
                android:textColor="@android:color/background_light"
                android:textSize="20sp" />
        </AbsoluteLayout>
        <ListView
            android:id="@+id/lv_set"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_weight="1" >
        </ListView>
    </LinearLayout>
    <LinearLayout
        android:id="@+id/layout_left"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@color/white"
        android:orientation="vertical" >
        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/nav_bg" >
            <ImageView
                android:id="@+id/iv_set"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_alignParentTop="true"
                android:src="@drawable/nav_setting" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:text="我"
                android:textColor="@android:color/background_light"
                android:textSize="20sp" />
        </RelativeLayout>
        <ImageView
            android:id="@+id/iv_set"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:scaleType="fitXY"
            android:src="@drawable/bg_guide_5" />
    </LinearLayout>
</RelativeLayout>

layout_right:这个大布局文件,layout_left:距离左边50dp像素.(我们要移动的是layout_left).

看到这个图我想大家都很清晰了吧,其实:我们就是把layout_left这个布局控件整理向左移动,至于移动多少,就要看layout_right有多宽了。layout_left移动到距离左边的边距就是layout_right的宽及-MAX_WIDTH.相信大家都理解.

布局文件就介绍到这里,下面看代码.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/***
     * 初始化view
     */
    void InitView() {
        layout_left = (LinearLayout) findViewById(R.id.layout_left);
        layout_right = (LinearLayout) findViewById(R.id.layout_right);
        iv_set = (ImageView) findViewById(R.id.iv_set);
        lv_set = (ListView) findViewById(R.id.lv_set);
        lv_set.setAdapter(new ArrayAdapter<String>(this, R.layout.item,
                R.id.tv_item, title));
        lv_set.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                Toast.makeText(MainActivity.this, title[position], 1).show();
            }
        });
        layout_left.setOnTouchListener(this);
        iv_set.setOnTouchListener(this);
        mGestureDetector = new GestureDetector(this);
        // 禁用长按监听
        mGestureDetector.setIsLongpressEnabled(false);
        getMAX_WIDTH();
    }

这里要对手势进行监听,我想大家都知道怎么做,在这里我要说明一个方法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/***
     * 获取移动距离 移动的距离其实就是layout_left的宽度
     */
    void getMAX_WIDTH() {
        ViewTreeObserver viewTreeObserver = layout_left.getViewTreeObserver();
        // 获取控件宽度
        viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                if (!hasMeasured) {
                    window_width = getWindowManager().getDefaultDisplay()
                            .getWidth();
                    RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                            .getLayoutParams();
                    layoutParams.width = window_width;
                    layout_left.setLayoutParams(layoutParams);
                    MAX_WIDTH = layout_right.getWidth();
                    Log.v(TAG, "MAX_WIDTH=" + MAX_WIDTH + "width="
                            + window_width);
                    hasMeasured = true;
                }
                return true;
            }
        });
    }

在这里我们要获取屏幕的宽度,并将屏幕宽度设置给layout_left这个控件,为什么要这么做呢,因为如果不把该控件宽度写死的话,那么系统将认为layout_left会根据不同环境宽度自动适应,也就是说我们通过layout_left.getLayoutParams动态移动该控件的时候,该控件会伸缩而不是移动。描述的有点模糊,大家请看下面示意图就明白了.

我们不为layout_left定义死宽度效果:

getLayoutParams可以很清楚看到,layout_left被向左拉伸了,并不是我们要的效果.

还有一种解决办法就是我们在配置文件中直接把layout_left宽度写死,不过这样不利于开发,因为分辨率的问题.因此就用ViewTreeObserver进行对layout_left设置宽度. ViewTreeObserver,这个类主要用于对布局文件的监听.强烈建议同学们参考这篇文章 android ViewTreeObserver详细讲解,相信让你对ViewTreeObserver有更一步的了解.

其他的就是对GestureDetector手势的应用,下面我把代码贴出来:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
package com.jj.slidingmenu;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.view.Window;
import android.view.View.OnTouchListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import android.widget.LinearLayout.LayoutParams;
/***
 * 滑动菜单
 * 
 * @author jjhappyforever...
 * 
 */
public class MainActivity extends Activity implements OnTouchListener,
        GestureDetector.OnGestureListener {
    private boolean hasMeasured = false;// 是否Measured.
    private LinearLayout layout_left;
    private LinearLayout layout_right;
    private ImageView iv_set;
    private ListView lv_set;
    /** 每次自动展开/收缩的范围 */
    private int MAX_WIDTH = 0;
    /** 每次自动展开/收缩的速度 */
    private final static int SPEED = 30;
    private GestureDetector mGestureDetector;// 手势
    private boolean isScrolling = false;
    private float mScrollX; // 滑块滑动距离
    private int window_width;// 屏幕的宽度
    private String TAG = "jj";
    private String title[] = { "待发送队列", "同步分享设置", "编辑我的资料", "找朋友", "告诉朋友",
            "节省流量", "推送设置", "版本更新", "意见反馈", "积分兑换", "精品应用", "常见问题", "退出当前帐号" };
    /***
     * 初始化view
     */
    void InitView() {
        layout_left = (LinearLayout) findViewById(R.id.layout_left);
        layout_right = (LinearLayout) findViewById(R.id.layout_right);
        iv_set = (ImageView) findViewById(R.id.iv_set);
        lv_set = (ListView) findViewById(R.id.lv_set);
        lv_set.setAdapter(new ArrayAdapter<String>(this, R.layout.item,
                R.id.tv_item, title));
        lv_set.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                Toast.makeText(MainActivity.this, title[position], 1).show();
            }
        });
        layout_left.setOnTouchListener(this);
        iv_set.setOnTouchListener(this);
        mGestureDetector = new GestureDetector(this);
        // 禁用长按监听
        mGestureDetector.setIsLongpressEnabled(false);
        getMAX_WIDTH();
    }
    /***
     * 获取移动距离 移动的距离其实就是layout_left的宽度
     */
    void getMAX_WIDTH() {
        ViewTreeObserver viewTreeObserver = layout_left.getViewTreeObserver();
        // 获取控件宽度
        viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                if (!hasMeasured) {
                    window_width = getWindowManager().getDefaultDisplay()
                            .getWidth();
                    RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                            .getLayoutParams();
                    // layoutParams.width = window_width;
                    layout_left.setLayoutParams(layoutParams);
                    MAX_WIDTH = layout_right.getWidth();
                    Log.v(TAG, "MAX_WIDTH=" + MAX_WIDTH + "width="
                            + window_width);
                    hasMeasured = true;
                }
                return true;
            }
        });
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.main);
        InitView();
    }
    // 返回键
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (KeyEvent.KEYCODE_BACK == keyCode && event.getRepeatCount() == 0) {
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                    .getLayoutParams();
            if (layoutParams.leftMargin < 0) {
                new AsynMove().execute(SPEED);
                return false;
            }
        }
        return super.onKeyDown(keyCode, event);
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // 松开的时候要判断,如果不到半屏幕位子则缩回去,
        if (MotionEvent.ACTION_UP == event.getAction() && isScrolling == true) {
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                    .getLayoutParams();
            // 缩回去
            if (layoutParams.leftMargin < -window_width / 2) {
                new AsynMove().execute(-SPEED);
            } else {
                new AsynMove().execute(SPEED);
            }
        }
        return mGestureDetector.onTouchEvent(event);
    }
    @Override
    public boolean onDown(MotionEvent e) {
        mScrollX = 0;
        isScrolling = false;
        // 将之改为true,不然事件不会向下传递.
        return true;
    }
    @Override
    public void onShowPress(MotionEvent e) {
    }
    /***
     * 点击松开执行
     */
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                .getLayoutParams();
        // 左移动
        if (layoutParams.leftMargin >= 0) {
            new AsynMove().execute(-SPEED);
        } else {
            // 右移动
            new AsynMove().execute(SPEED);
        }
        return true;
    }
    /***
     * e1 是起点,e2是终点,如果distanceX=e1.x-e2.x>0说明向左滑动。反之亦如此.
     */
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
            float distanceY) {
        isScrolling = true;
        mScrollX += distanceX;// distanceX:向左为正,右为负
        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                .getLayoutParams();
        layoutParams.leftMargin -= mScrollX;
        if (layoutParams.leftMargin >= 0) {
            isScrolling = false;// 拖过头了不需要再执行AsynMove了
            layoutParams.leftMargin = 0;
        } else if (layoutParams.leftMargin <= -MAX_WIDTH) {
            // 拖过头了不需要再执行AsynMove了
            isScrolling = false;
            layoutParams.leftMargin = -MAX_WIDTH;
        }
        layout_left.setLayoutParams(layoutParams);
        return false;
    }
    @Override
    public void onLongPress(MotionEvent e) {
    }
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
            float velocityY) {
        return false;
    }
    class AsynMove extends AsyncTask<Integer, Integer, Void> {
        @Override
        protected Void doInBackground(Integer... params) {
            int times = 0;
            if (MAX_WIDTH % Math.abs(params[0]) == 0)// 整除
                times = MAX_WIDTH / Math.abs(params[0]);
            else
                times = MAX_WIDTH / Math.abs(params[0]) + 1;// 有余数
            for (int i = 0; i < times; i++) {
                publishProgress(params[0]);
                try {
                    Thread.sleep(Math.abs(params[0]));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
        /**
         * update UI
         */
        @Override
        protected void onProgressUpdate(Integer... values) {
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) layout_left
                    .getLayoutParams();
            // 右移动
            if (values[0] > 0) {
                layoutParams.leftMargin = Math.min(layoutParams.leftMargin
                        + values[0], 0);
                Log.v(TAG, "移动右" + layoutParams.rightMargin);
            } else {
                // 左移动
                layoutParams.leftMargin = Math.max(layoutParams.leftMargin
                        + values[0], -MAX_WIDTH);
                Log.v(TAG, "移动左" + layoutParams.rightMargin);
            }
            layout_left.setLayoutParams(layoutParams);
        }
    }
}

上面代码注释已经很明确,相信大家都看的明白,我就不过多解释了。

效果图:截屏出来有点卡,不过在手机虚拟机上是不卡的.

源码下载

怎么样,看着还行吧,我们在看下面一个示例:

简单说明一下,当你滑动的时候左边会跟着右边一起滑动,这个效果比上面那个酷吧,上面那个有点死板,其实实现起来也比较容易,只需要把我们上面那个稍微修改下,对layout_right也进行时时更新,这样就实现了这个效果了,如果上面那个理解了,这个很轻松就解决了,在这里我又遇到一个问题:此时的listview的item监听不到手势,意思就是我左右滑动listview他没有进行滑动。

本人对touch众多事件监听拦截等熟悉度不够,因此这里我用到自己写的方法,也许比较麻烦,如果有更好的解决办法,请大家一定要分享哦,再次 thanks for you 了.

具体解决办法:我们重写listview,对此listview进行手势监听,我们自定义一个接口来实现,具体代码如下:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package com.jj.slidingmenu;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.GestureDetector.OnGestureListener;
import android.view.View;
import android.widget.ListView;
import android.widget.Toast;
public class MyListView extends ListView implements OnGestureListener {
    private GestureDetector gd;
    // 事件状态
    public static final char FLING_CLICK = 0;
    public static final char FLING_LEFT = 1;
    public static final char FLING_RIGHT = 2;
    public static char flingState = FLING_CLICK;
    private float distanceX;// 水平滑动的距离
    private MyListViewFling myListViewFling;
    public static boolean isClick = false;// 是否可以点击
    public void setMyListViewFling(MyListViewFling myListViewFling) {
        this.myListViewFling = myListViewFling;
    }
    public float getDistanceX() {
        return distanceX;
    }
    public char getFlingState() {
        return flingState;
    }
    private Context context;
    public MyListView(Context context) {
        super(context);
    }
    public MyListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        gd = new GestureDetector(this);
    }
    /**
     * 覆写此方法,以解决ListView滑动被屏蔽问题
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        myListViewFling.doFlingOver(event);// 回调执行完毕.
        this.gd.onTouchEvent(event);
        return super.dispatchTouchEvent(event);
    }
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        /***
         * 当移动的时候
         */
        if (ev.getAction() == MotionEvent.ACTION_DOWN)
            isClick = true;
        if (ev.getAction() == MotionEvent.ACTION_MOVE)
            isClick = false;
        return super.onTouchEvent(ev);
    }
    @Override
    public boolean onDown(MotionEvent e) {
        int position = pointToPosition((int) e.getX(), (int) e.getY());
        if (position != ListView.INVALID_POSITION) {
            View child = getChildAt(position - getFirstVisiblePosition());
        }
        return true;
    }
    @Override
    public void onShowPress(MotionEvent e) {
    }
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
            float distanceY) {
        // 左滑动
        if (distanceX > 0) {
            flingState = FLING_RIGHT;
            Log.v("jj", "左distanceX=" + distanceX);
            myListViewFling.doFlingLeft(distanceX);// 回调
            // 右滑动.
        } else if (distanceX < 0) {
            flingState = FLING_LEFT;
            Log.v("jj", "右distanceX=" + distanceX);
            myListViewFling.doFlingRight(distanceX);// 回调
        }
        return false;
    }
    /***
     * 上下文菜单
     */
    @Override
    public void onLongPress(MotionEvent e) {
        // System.out.println("Listview long press");
        // int position = pointToPosition((int) e.getX(), (int) e.getY());
        // if (position != ListView.INVALID_POSITION) {
        // View child = getChildAt(position - getFirstVisiblePosition());
        // if (child != null) {
        // showContextMenuForChild(child);
        // this.requestFocusFromTouch();
        // }
        //
        // }
    }
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
            float velocityY) {
        return false;
    }
    /***
     * 回调接口
     * 
     * @author jjhappyforever...
     * 
     */
    interface MyListViewFling {
        void doFlingLeft(float distanceX);// 左滑动执行
        void doFlingRight(float distanceX);// 右滑动执行
        void doFlingOver(MotionEvent event);// 拖拽松开时执行
    }
}

而在MainActivity.java里面实现该接口,我这么一说,我想有的同学们都明白了,具体实现起来代码有点多,我把代码上传到网上,大家可以下载后用心看,我想大家都能够明白的.(在这里我鄙视一下自己,肯定通过对手势监听拦截实现对listview的左右滑动,但是自己学业不经,再次再说一下,如有好的解决方案,请一定要分享我一下哦.)

另外有一个问题:当listivew超出一屏的时候,此时的listview滑动的时候可以上下左右一起滑动,在此没有解决这个问题,如有解决请分享我哦.

效果图:

源码下载

补充说明:**上面这个例子有点小BUG,就是右边菜单过长的话,我不仅可以上下滑动,同时也可以左右滑动,这点肯定不是我们想要的效果,其实下面已经解决了这个问题,就是我们自定义一个布局文件,在布局文件中进行对Touch事件监听.效果比上面好的多,至于网上别的样式,我想大家都应该可以效仿实现,这里就不一一讲解了,关键:大家要明白原理,遇到问题知道怎么处理,话费时间长没关系,只要可以搞定.(网上有的朋友说这个有重影,有的布局会变形,其实和我们的布局有关,因为我们用的是AbsoluteLayout布局,但是只要你懂得怎么用,那些问题都不是问题.)**

更正后源码下载

由于篇符较长,先说到这里,其实android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu也可以实现.具体参考下一篇文章:android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu

/*********************************************************************************************/

下面介绍下:

android 滑动菜单SlidingMenu之拓展(解决ListView滑动冲突)

百度新闻客户端可以手势左划右划,而操作的对象是一个ListView,大家都知道SlidingMenu里的ListView加手势GestureDetector就是蛋疼的操作,但是百度人家就这么搞,而且做的相当棒,其他的应用我很少见到如此的,不得不说,牛逼有牛逼的道理.

网上我搜查了,没有找到类似的案例,只能自己琢磨了,功夫不负有心人啊,终于实现了,方法比较笨戳,下面我简单讲解下:

实现原理:**Touch事件的拦截与分发.**

在项目中,由于点击不同的菜单要显示不同的内容,所以右边最好弄成活动布局,就是添加一个Linerlayout,动态添加相应布局,这样扩展比较容易.但是这个Linerlayout我们要自己定义,因为我们要拦截一些Touch事件.(实现:当我们上下滑动,ListView上下滑动,当我们左右滑动ListView禁止上下滑动,进行左右滑动)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package com.hytrip.ui.custom;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.widget.LinearLayout;
/***
 * 行程详情的自定义布局
 * 
 * @author zhangjia
 * 
 */
public class JourneyLinearLayout extends LinearLayout {
    private GestureDetector mGestureDetector;
    View.OnTouchListener mGestureListener;
    private boolean isLock = true;
    private OnScrollListener onScrollListener;// 自定义接口
    private boolean b;
    public JourneyLinearLayout(Context context) {
        super(context);
    }
    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.onScrollListener = onScrollListener;
    }
    public JourneyLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mGestureDetector = new GestureDetector(new MySimpleGesture());
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("jj", "dispatchTouchEvent...");
        // 获取手势返回值
        b = mGestureDetector.onTouchEvent(ev);
        // 松开手要执行一些操作。(关闭 or 打开)
        if (ev.getAction() == MotionEvent.ACTION_UP) {
            onScrollListener.doLoosen();
        }
        return super.dispatchTouchEvent(ev);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("jj", "onInterceptTouchEvent...");
        super.onInterceptTouchEvent(ev);
        return b;
    }
    /***
     * 在这里我简单说明一下
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("jj", "onTouchEvent...");
        isLock = false;
        return super.onTouchEvent(event);
    }
    /***
     * 自定义手势执行
     * 
     * @author zhangjia
     * 
     */
    class MySimpleGesture extends SimpleOnGestureListener {
        @Override
        public boolean onDown(MotionEvent e) {
            Log.e("jj", "onDown...");
            isLock = true;
            return super.onDown(e);
        }
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            if (!isLock)
                onScrollListener.doScroll(distanceX);
            // 垂直大于水平
            if (Math.abs(distanceY) > Math.abs(distanceX)) {
                // Log.e("jjj", "ll...垂直...");
                return false;
            } else {
                // Log.e("jjj", "ll...水平...");
                // Log.e("jj", "distanceX===" + distanceX);
                return true;
            }
        }
    }
    /***
     * 自定义接口 实现滑动...
     * 
     * @author zhangjia
     * 
     */
    public interface OnScrollListener {
        void doScroll(float distanceX);// 滑动...
        void doLoosen();// 手指松开后执行...
    }
}

说明1:顺序:dispatchTouchEvent》GestureDetector》onInterceptTouchEvent》onTouchEvent.

说明2:onInterceptTouchEvent 返回true,则拦截孩子touch事件,执行当前OnTouch事件,而返回false,则不执行OnTouch事件,事件传递给孩子执行。。。

因为onInterceptTouchEvent 是用于拦截Touch的,不适用于执行一些操作,所以把注入手势操作方法分发事件dispatchTouchEvent中.

下面是自定义的一个接口(方法1:滑动中。。。方法2:松开自动合拢。。。),用于实现手势移动操作,在SlidingMenuActivity.java中实现其接口.

(写的比较凌乱,但是如果你仔细看的话一定会明白的,弄懂事件的传递对你自定义想实现一些牛叉View会有帮助的.鄙人正在研究中...)

因为是模型,所以样子很丑,不过重要的是实现方法.

弄懂上面那个,下面我们在深入看一下:最上面最后一张图片,我们在滑动中间图片的时候ListView肯定是不要进行左划或者右划,是不是有点头大了,其实分析好了,也不难,我们只要对上面那个自定义类稍微修调一下:我们在滑动左右滑动判断一下,如果是ListView的HeadView,那么我们就不进行手势操作,这样ViewPager就可以左右滑动,而ListView就不会左右滑动了,如果不是HeadView还照常就Ok了,简单吧。

下面是示例图:

左右拖拽图片局域(ListView未受影响) 左右拖拽(非图片)局域

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值