• SlidingMenu addIgnoreView() 无效的bug解决方法


    ## 感谢大佬:https://blog.csdn.net/fuchaosz/article/details/51513288

    1 简介

    最近在做侧滑的时候用到了SlidingMenu,在MainActivity中有个轮播图,用ViewPager实现的,结果发现ViewPager不能滑动了,ViewPager的滑动事件和SlidingMenu冲突了,然后自然想到调用Slidingmenu的addIgnoreView()方法,然而却发现并没有什么卵用,滑动事件还是冲突,于是研究了一下源码,发现是SlidingMenu的bug,然后修改后解决问题,遂著此文以记之。

    2 Bug详细介绍

    主界面上,如果有个ViewPager,那么侧滑菜单和ViewPager的滑动事件会冲突,也就是说向右滑动,这时候ViewPager是不翻页的,而是调出了左边的侧滑菜单。怎么办呢,一般解决办法是将调用

    SlidingMenu.addIgnoreView(viewPager)
    

    但是,如果这个ViewPager嵌套在一个ViewGroup中,那么上面这个方法就是失效了,看下面demo。

    3 Bug示例

    layout/activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical"
        >
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="20dp"
            android:text="滑动区域"
            />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="100dp"
            >
    
            <android.support.v4.view.ViewPager
                android:id="@+id/vp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">
            </android.support.v4.view.ViewPager>
        </LinearLayout>
    
    </LinearLayout>
    

    侧滑菜单布局: layout/menu_left.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:orientation="vertical"
            android:background="@android:color/holo_blue_light"
        >
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="30dp"
            android:text="left menu item_1"
            android:textSize="25sp"
            />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="30dp"
            android:text="left menu item_2"
            android:textSize="25sp"
            />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="30dp"
            android:text="left menu item_3"
            android:textSize="25sp"
            />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="30dp"
            android:text="left menu item_4"
            android:textSize="25sp"
            />
    
    </LinearLayout>
    

    MainActiviy.java:

    public class MainActivity extends Activity {
    
        private MyAdapter myAdapter;
        private SlidingMenu menu;
        private ViewPager vp;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            this.vp = (ViewPager) findViewById(R.id.vp);
            this.init();
            this.initMenu();
        }
    
        private void init() {
            //create views
            List<View> views = new ArrayList<>();
            for (int i = 0; i < 3; i++) {
                TextView tv = new TextView(this);
                tv.setText(i + "");
                switch (i) {
                    case 0:
                        tv.setBackgroundColor(Color.RED);
                        break;
                    case 1:
                        tv.setBackgroundColor(Color.GREEN);
                        break;
                    case 2:
                        tv.setBackgroundColor(Color.BLUE);
                        break;
                }
    
                tv.setGravity(Gravity.CENTER);
                tv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
                views.add(tv);
            }
            //create myadapert
            this.myAdapter = new MyAdapter(this, views);
            //set adapter for viewpager
            vp.setAdapter(myAdapter);
        }
    
        //init slidingmenu
        private void initMenu() {
            menu = new SlidingMenu(this);
            menu.setMode(SlidingMenu.LEFT);
            menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
            menu.setShadowWidthRes(R.dimen.shadow_width);
            menu.setBehindOffset(200);
            menu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);
            //set the left menu view
            menu.setMenu(R.layout.menu_left);
            menu.addIgnoredView(vp);
        }
    
        class MyAdapter extends PagerAdapter {
    
            Context context;
            List<View> views;
    
            public MyAdapter(Context context, List<View> views) {
                this.context = context;
                this.views = views;
            }
    
            @Override
            public int getCount() {
                return views == null ? 0 : views.size();
            }
    
            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view == object;
            }
    
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                container.addView(views.get(position));
                return views.get(position);
            }
    
            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeView(views.get(position));
            }
        }
    }
    

    运行结果如下:
    在这里插入图片描述
    在MainActivity中已经添加了menu.addIgnoredView(vp)但是滑动viewPager左边空白区域,即下面图片的A区域,无法滑出侧滑菜单,此时A区域已经不属于viewPager了,正确的应该是可以滑出侧滑菜单的,所以这里是bug:
    在这里插入图片描述

    4 Bug原因

    定位到SlidingMenu的源码中CustomViewAbove类的isInIgnoredView()方法:

     private boolean isInIgnoredView(MotionEvent ev) {
            Rect rect = new Rect();
            for (View v : mIgnoredViews) {
                v.getHitRect(rect);
                Log.d(TAG, String.format("rect=(%d,%d,%d,%d)", rect.left, rect.top, rect.right, rect.bottom));
                Log.d(TAG, String.format("touch(%d,%d)", (int) ev.getX(), (int) ev.getY()));
                if (rect.contains((int) ev.getX(), (int) ev.getY()))
                    return true;
            }
            return false;
        }
    

    添加两行打印,看看点击A区域之后,打印的日志:
    在这里插入图片描述
    从日志可以看出,明明点击的A区域在viewPager的外面,也就是说touch point的坐标应该在rect范围外面,但是打印出的日志却显示touch的点在rect内部,因此这个isInIgnoredView()返回true,导致事件被SlidingMenu拦截了,从而导致ViewPager接收不到事件,所以addIgnoreView()无效。
    好了,可以明确原因是出在获取view的显示区域矩形出错,通过demo可以很明显的看出viewpager的区域不可能是从(0,0)开始的。
    所以,bug出在v.getHitRect(rect),getHitRect()获取的坐标区域是相对于父view的.即viewpager相对于它的父ViewGroup,本例中的LinearLayout的坐标,由于没有padding,margin等参数,所以是从(0,0)开始的。
    MotionEvent的touch point坐标是相对于整个屏幕的,所以两者当然不匹配,也就造成touch point始终在viewPager区域内了。

    5 Bug解决

    找到bug出错的原因是获取view的区域错误,那么改正就简单了,将SlidingMenu的源码中CustomViewAbove类的isInIgnoredView()方法中的

    v.getHitRect(rect)
    

    改为:

     v.getGlobalVisibleRect(rect)
    

    getHitRect()获取的坐标是子view在父view中的坐标
    getGlobalVisibleRect 获取的是view在整个屏幕的坐标

    修改后的isInIgnoredView()方法如下:

    private boolean isInIgnoredView(MotionEvent ev) {
            Rect rect = new Rect();
            for (View v : mIgnoredViews) {
                //v.getHitRect(rect);
                //这里稍微做了修改,v.getHitRect只能获取相对于父控件的位置,如果v嵌套在一个viewGroup中,
                // 那么添加这个v到mIgnoredViews中将不会游任何效果,例如:LinearLayout嵌套一个ViewerPager,将ViewPager加入mIgnoredViews后,依然无法接受到滑动事件
                //所以这里改为v.getGlobalVisibleRect,获取v在整个屏幕的坐标,而MotionEvent的坐标也是相对于整个屏幕来测量的
                v.getGlobalVisibleRect(rect);
                if (rect.contains((int)ev.getX(), (int)ev.getY())) return true;
            }
            return false;
        }
    

    6 小结

    这个bug我已经提到github上SlidingMenu的issue中去了,小有成就感,哈哈。附上链接:

    https://github.com/jfeinstein10/SlidingMenu/issues/751

    7 bug demo下载地址

    本文的bug示例已经上传了,下载地址:

    http://download.csdn.net/detail/fuchaosz/9549168

  • 相关阅读:
    Redis
    Redis入门
    C#编程--语句(分支语句)
    C#编程--运算符
    C#编程--输入和输出
    C#编程进制转换
    C#语言课程11月10日
    C#语言课程11月9日
    C#语言课程11月7日
    C#语言课程11月6日
  • 原文地址:https://www.cnblogs.com/tfxz/p/12621621.html
Copyright © 2020-2023  润新知