美文网首页
侧滑删除菜单

侧滑删除菜单

作者: GeekGray | 来源:发表于2018-10-02 22:53 被阅读5次

    阅读原文

    侧滑删除菜单

    1.正常初始化显示item的布局

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.slidingmenu.MainActivity">
    
        <ListView
            android:id="@+id/lv_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </RelativeLayout>
    

    item_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <com.example.slidingmenu.SlideLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="60dp">
    
        <include android:id="@+id/item_content" layout="@layout/item_content"/>
        <include android:id="@+id/item_menu" layout="@layout/item_menu"/>
    
    </com.example.slidingmenu.SlideLayout>
    

    item_menu.xml

    <?xml version="1.0" encoding="utf-8"?>
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="60dp"
        android:background="#22000000"
        android:gravity="center"
        android:text="Delete"
        android:textColor="#ff0000"
        android:textSize="25sp">
    
    </TextView>
    

    item_content.xml

    <?xml version="1.0" encoding="utf-8"?>
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:background="#44000000"
        android:gravity="center"
        android:text="Content"
        android:textColor="#000000"
        android:textSize="25sp">
    
    </TextView>
    

    2.正常初始化显示item的代码实现

    初始化控件

        private View contentView;
        private View menuView;
    
        /**
         * 当布局文件加载完成的时候回调这个方法
         */
        @Override
        protected void onFinishInflate()
        {
            super.onFinishInflate();
            contentView = getChildAt(0);
            menuView = getChildAt(1);
        }
    

    得到content和menu的宽高

        /**
         * Content的宽
         */
        private int contentWidth;
        private int menuWidth;
        private int viewHeight;// 他们的高都是相同的
    

    在测量方法里,得到各个控件的高和宽

        /**
         * 在测量方法里,得到各个控件的高和宽
         *
         * @param widthMeasureSpec
         * @param heightMeasureSpec
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            contentWidth = contentView.getMeasuredWidth();
            menuWidth = menuView.getMeasuredWidth();
            viewHeight = getMeasuredHeight();
        }
    

    计算位置,onLayout参数,为左上角的坐标和右下角的坐标

    image
    @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom)
        {
            super.onLayout(changed, left, top, right, bottom);
            // 指定菜单的位置
            menuView.layout(contentWidth, 0, contentWidth + menuWidth, viewHeight);
        }
    

    3.通过手势拖动打开或者关闭menu

    1.在SildeLayout中重写onTouchEvent(),按下的时候记录初始坐标startX,Y,

    2.在move的时候记录结束的坐标endX,Y,然后计算X轴的偏移量distacneX=endX-startX;通过Scrollto()方法对内容进行整体移动,而Scrollto()第一个参数为动态改变,第二个参数不变化,即int toScrollX = (int) (getScrollX() - distanceX);

    3.屏蔽非法值

    // 4.屏蔽非法值
                    if (toScrollX < 0)
                    {
                        toScrollX = 0;
                    }
                    else if (toScrollX > menuWidth)
                    {
                        toScrollX = menuWidth;
                    }
    

    4.最后在move中对startX,Y重新赋值

    startX = event.getX();
    startY = event.getY();
    

    5.具体代码

        private float startX;
        private float startY;
        private float downX;// 只赋值一次
        private float downY;
    
    @Override
        public boolean onTouchEvent(MotionEvent event)
        {
            super.onTouchEvent(event);
            switch (event.getAction())
            {
            case MotionEvent.ACTION_DOWN:
                // 1.按下记录坐标
                downX = startX = event.getX();
                downY = startY = event.getY();
                Log.e(TAG, "SlideLayout-onTouchEvent-ACTION_DOWN");
                break;
    
            case MotionEvent.ACTION_MOVE:
                Log.e(TAG, "SlideLayout-onTouchEvent-ACTION_MOVE");
                // 2.记录结束值
                float endX = event.getX();
                float endY = event.getY();
                // 3.计算偏移量
                float distanceX = endX - startX;
    
                int toScrollX = (int) (getScrollX() - distanceX);
    
                // 4.屏蔽非法值
                if (toScrollX < 0)
                {
                    toScrollX = 0;
                }
                else if (toScrollX > menuWidth)
                {
                    toScrollX = menuWidth;
                }
    
                scrollTo(toScrollX, getScrollY());
                startX = event.getX();
                startY = event.getY();
                // 在X轴和Y轴滑动的距离
                float DX = Math.abs(endX - downX);
                float DY = Math.abs(endY - downY);
                if (DX > DY && DX > 0)
                {
                    // 水平方向滑动
                    // 响应侧滑
                    // 反拦截-事件给SlideLayout
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                break;
    
            case MotionEvent.ACTION_UP:
                Log.e(TAG, "SlideLayout-onTouchEvent-ACTION_UP");
                int totalScrollX = getScrollX();// 偏移量
                if (totalScrollX < menuWidth / 2)
                {
                    // 关闭Menu
                    closeMenu();
                }
                else
                {
                    // 打开Menu
                    openMenu();
                }
                break;
    
            }
            return true;
        }
    

    4.up时判断是平滑的打开还是关闭

    int totalScrollX = getScrollX();// 偏移量
                    if (totalScrollX < menuWidth / 2)
                    {
                        // 关闭Menu
                        closeMenu();
                    }
                    else
                    {
                        // 打开Menu
                        openMenu();
                    }
    
    
        /**
         * 打开menu
         */
        public void openMenu()
        {
            // --->menuWidth
            int distanceX = menuWidth - getScrollX();
            scroller.startScroll(getScrollX(), getScrollY(), distanceX, getScrollY());
            invalidate();// 强制刷新
            if (onStateChangeListenter != null)
            {
                onStateChangeListenter.onOpen(this);
            }
        }
    
        /**
         * 关闭menu
         */
        public void closeMenu()
        {
            // --->0
            int distanceX = 0 - getScrollX();
            scroller.startScroll(getScrollX(), getScrollY(), distanceX, getScrollY());
            invalidate();// 强制刷新
            if (onStateChangeListenter != null)
            {
                onStateChangeListenter.onClose(this);
            }
        }
    

    5.在ListView中显示侧滑item

    1.初始化listview

        private ListView lv_main;
    
        private ArrayList<MyBean> myBeans;
    
        private MyAdapter myAdapter;
    
        private SlideLayout slideLayout;
    
    private void initView()
        {
            lv_main = (ListView) findViewById(R.id.lv_main);
        }
    

    2.准备数据设置适配器

    准备一个bean类,并提供一个带参的构造器,传递参数

    /**
     * 
     * @author: Hashub.NG
     * @description: 
     * @update: 2018年8月1日 下午4:44:07
     */
    public class MyBean
    {
        private String name;
    
        public MyBean(String name)
        {
            this.name = name;
        }
    
        public String getName()
        {
            return name;
        }
    
        public void setName(String name)
        {
            this.name = name;
        }
    }
    

    准备数据并设置适配器

    private void initData()
        {
            myBeans = new ArrayList<MyBean>();
            for (int i = 0; i < 100; i++)
            {
                myBeans.add(new MyBean("Content" + i));
            }
            myAdapter = new MyAdapter();
            lv_main.setAdapter(myAdapter);
        }
    

    适配器

    class MyAdapter extends BaseAdapter
        {
    
            @Override
            public int getCount()
            {
                return myBeans == null ? 0 : myBeans.size();
            }
    
            @Override
            public Object getItem(int position)
            {
                return null;
            }
    
            @Override
            public long getItemId(int position)
            {
                return 0;
            }
    
            @Override
            public View getView(final int position, View convertView, ViewGroup parent)
            {
                ViewHolder viewHolder;
                if (convertView == null)
                {
                    convertView = View.inflate(MainActivity.this, R.layout.item_main, null);
                    viewHolder = new ViewHolder();
                    viewHolder.item_content = (TextView) convertView.findViewById(R.id.item_content);
                    viewHolder.item_menu = (TextView) convertView.findViewById(R.id.item_menu);
                    convertView.setTag(viewHolder);
                }
                else
                {
                    viewHolder = (ViewHolder) convertView.getTag();
                }
    
                // 根据位置得到内容
                final MyBean myBean = myBeans.get(position);
                viewHolder.item_content.setText(myBean.getName());
                viewHolder.item_content.setOnClickListener(new View.OnClickListener()
                {
    
                    @Override
                    public void onClick(View v)
                    {
                        MyBean myBean1 = myBeans.get(position);
                        Toast.makeText(MainActivity.this, myBean1.getName(), Toast.LENGTH_SHORT).show();
                    }
                });
    
                viewHolder.item_menu.setOnClickListener(new View.OnClickListener()
                {
    
                    @Override
                    public void onClick(View v)
                    {
                        SlideLayout slideLayout = (SlideLayout) v.getParent();
                        slideLayout.closeMenu();
                        myBeans.remove(myBean);
                        notifyDataSetChanged();
                    }
                });
    
                SlideLayout slideLayout = (SlideLayout) convertView;
                slideLayout.setOnStateChangeListenter(new MyOnStateChangeListenter());
                return convertView;
            }
    
        }
    
    
    
    static class ViewHolder
        {
            TextView item_content;
            TextView item_menu;
        }
    

    6.解决item滑动后不能自动打开和关闭

    原因: ListView拦截事件并消费事件,导致up事件丢失

    解决方法1:自定义一个listview返回一个false,传递事件给子view消费

    解决方法2:在子view中请求发拦截,让父层把事件传递给自己,假如左右滑动距离大于8px,请求拦截

    在SildeLayout的onTouchEvent()中

    down的时候记录坐标
    // 1.按下记录坐标
                downX = startX = event.getX();
                downY = startY = event.getY();
    

    在move中计算距离并判断以及反拦截让自己处理处理

    image

    SlideLayout是ListView的下一层视图,所以反拦截-事件给SlideLayout

    // 在X轴和Y轴滑动的距离
                float DX = Math.abs(endX - downX);
                float DY = Math.abs(endY - downY);
                if (DX > DY && DX > 0)
                {
                    // 水平方向滑动
                    // 响应侧滑
                    // 反拦截-事件给SlideLayout
                    getParent().requestDisallowInterceptTouchEvent(true);//请求拦截父层事件,即把父层的拦截事件干掉
                }
    

    7.解决内容视图设置点击事件时不能滑动item

    image

    contentView把事件消费掉了,导致滑动无效,父层视图把子view的事件拦截即可,一般情况下,反拦截的优先级别高于拦截,此处子View没有反拦截,故可以父层拦截子view的事件。

    在SlideLayout中拦截事件,但是不能全部拦截,滑动的时候才拦截,否则点击事件就不生效了。

    /**
         * true:拦截孩子的事件,但会执行当前控件的onTouchEvent()方法 false:不拦截孩子的事件,事件继续传递
         * 
         * @param event
         * @return
         */
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev)
        {
            boolean intercept = false;
            switch (ev.getAction())
            {
            case MotionEvent.ACTION_DOWN:
                // 1.按下记录坐标
                downX = startX = ev.getX();
                Log.e(TAG, "SlideLayout-onTouchEvent-ACTION_DOWN");
                if (onStateChangeListenter != null)
                {
                    onStateChangeListenter.onDown(this);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                Log.e(TAG, "SlideLayout-onTouchEvent-ACTION_MOVE");
                // 2.记录结束值
                float endX = ev.getX();
                float endY = ev.getY();
                // 3.计算偏移量
                float distanceX = endX - startX;
    
                startX = ev.getX();
                // 在X轴和Y轴滑动的距离
                float DX = Math.abs(endX - downX);
                if (DX > 8)
                {
                    intercept = true;
                }
                break;
    
            case MotionEvent.ACTION_UP:
                break;
            }
            return intercept;
        }
    

    在适配器中设置点击事件

    viewHolder.item_content.setOnClickListener(new View.OnClickListener()
                {
    
                    @Override
                    public void onClick(View v)
                    {
                        MyBean myBean1 = myBeans.get(position);
                        Toast.makeText(MainActivity.this, myBean1.getName(), Toast.LENGTH_SHORT).show();
                    }
                });
    

    8.限制只能打开一个item

    设置menu的点击事件

                viewHolder.item_menu.setOnClickListener(new View.OnClickListener()
                {
    
                    @Override
                    public void onClick(View v)
                    {
                        SlideLayout slideLayout = (SlideLayout) v.getParent();
                        slideLayout.closeMenu();
                        myBeans.remove(myBean);
                        notifyDataSetChanged();
                    }
                });
    

    SlideLayout写接口监听状态变化

    /**
         * 监听SlideLayout状态的改变
         */
        public interface OnStateChangeListenter
        {
            void onClose(SlideLayout layout);
    
            void onDown(SlideLayout layout);
    
            void onOpen(SlideLayout layout);
        }
    
        /**
         * 设置SlideLayout状态的监听
         * 
         * @param onStateChangeListenter
         */
        public void setOnStateChangeListenter(OnStateChangeListenter onStateChangeListenter)
        {
            this.onStateChangeListenter = onStateChangeListenter;
        }
    

    MainActivity接口回调

    slideLayout.setOnStateChangeListenter(new MyOnStateChangeListenter());
    
    
    class MyOnStateChangeListenter implements SlideLayout.OnStateChangeListenter
        {
    
            @Override
            public void onClose(SlideLayout layout)
            {
                if (slideLayout == layout)
                {
                    slideLayout = null;
                }
            }
    
            @Override
            public void onDown(SlideLayout layout)
            {
                if (slideLayout != null && slideLayout != layout)
                {
                    slideLayout.closeMenu();
                }
            }
    
            @Override
            public void onOpen(SlideLayout layout)
            {
                slideLayout = layout;
            }
    
        }
    

    相关文章

      网友评论

          本文标题:侧滑删除菜单

          本文链接:https://www.haomeiwen.com/subject/ceoaoftx.html