自定义控件-侧滑菜单

自定义侧滑删除菜单


话不多说。先放效果图,源码仅供参考,出现bug,请留言告知

这里写图片描述

*- 继承FramLayout
- 构造方法中调用ViewDragHelper
- 转发事件,处理事件
- 重写ViewDragHelper中的方法
- 回调接口
- 导入到ListView中*


1.首先构造函数串联起来,并在三个属性的构造中调用ViewDragHelper帮助类。以及初始化布局

public SlideClean(Context context) {
        this(context, null);
    }

    public SlideClean(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SlideClean(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mViewDragHelper = ViewDragHelper.create(this, mcallback);
    }
 /**
     * 初始化导入Inflate完成
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        rightView = getChildAt(0);
        mainView = getChildAt(1);
        mRangeView = rightView.findViewById(R.id.tv);
    }

    /**
     * get measue size
     *
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //获取测量的数值
        mainHeight = mainView.getMeasuredHeight();
        mainWidht = mainView.getMeasuredWidth();
        meaWidth = mRangeView.getMeasuredWidth();
    }

    /**
     * override Layout
     *
     * @param changed
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        setLayout();
    }

    /**
     * 根据矩形设定布局
     */
    private void setLayout() {
        Rect mainRect = getMainRect();
        mainView.layout(mainRect.left, mainRect.top, mainRect.right, mainRect.bottom);
        Rect rightRect = getRightRect(mainRect);
        rightView.layout(rightRect.left, rightRect.top, rightRect.right, rightRect.bottom);
    }

    /**
     * 根据主背景矩形获取右背景矩形
     *
     * @param mainRect
     * @return
     */
    private Rect getRightRect(Rect mainRect) {
        return new Rect(mainRect.right, mainRect.top, mainRect.right + mainWidht, mainRect.bottom);
    }

    /**
     * 获取主背景矩形
     *
     * @return
     */
    private Rect getMainRect() {
        Rect mainRect = new Rect(0, 0, mainWidht, mainHeight);
        return mainRect;
    }

2.需要对事件进行处理,避免拦截,同时能让显示的控件滑动
如果有的朋友发现事件被拦截,或者无法实现效果。可以像我一样简单的在事件中打一下Log,记录事件发生的时刻,已经发生的逻辑关系

/**
     * 转发事件
     *
     * @param ev
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        System.out.println("ssint");
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    /**
     * 请求拦截
     *
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction()== MotionEvent.ACTION_UP) {
        System.out.println("sstouup");
        }if (event.getAction()== MotionEvent.ACTION_DOWN) {
        System.out.println("sstoudown");
        }
        try {
            //抓取多点触摸的异常
            mViewDragHelper.processTouchEvent(event);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

3.事件ViewDragHelper的CallBack回调函数
这里用到的几个方法,已经在代码中备注使用原因和原理
针对callBack回调中的参数,对滑动的状态进行判断。

 private ViewDragHelper.Callback mcallback = new ViewDragHelper.Callback() {

        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return true;
        }

        /**
         * 大于0,拦截可以
         * @param child
         * @return
         */
        @Override
        public int getViewHorizontalDragRange(View child) {
            return mainWidht;
        }

        //重写之后测能滑动
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            finalState = 2;//每次开始滑动之前设定为2;
            if (child == mainView) {

                //点击的是主控件,left是这个控件的左边距
                if (left > 0) {
                    left = 0;
                } else if (left < -meaWidth) {
                    left = -meaWidth;
                }
            } else if (child == rightView) {
                //点击的是右控件,left是这个控件的左边距
                if (left > mainWidht) {
                    left = mainWidht;
                } else if (left < mainWidht - meaWidth) {
                    left = mainWidht - meaWidth;
                }
            }
           // System.out.println(left);
            return left;
        }

        /**
         * 条目被状态被改变
         * @param changedView
         * @param left
         * @param top
         * @param dx
         * @param dy
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);
            //System.out.println(dx + "---" + left);
            if (changedView == mainView) {
                //将mainView的偏移量传递给rightview
                rightView.offsetLeftAndRight(dx);

            } else if (changedView == rightView) {
                //将rightview的偏移量传递给mainView
                mainView.offsetLeftAndRight(dx);
            }
            //requestLayout();//请求重新布局
            dispatchDragEvent();
            invalidate();
        }

        /**
         * 滑动事件被释放
         * @param releasedChild
         * @param xvel
         * @param yvel
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);
          //  System.out.println(xvel);
            int releaseLeft = mainView.getLeft();
            if (releaseLeft < -30) {
                //平滑开启
                mViewDragHelper.smoothSlideViewTo(mainView, -meaWidth, 0);
               // System.out.println(mainView.getLeft()+"-----------------shifangdian");
                finalState = 1;
                if(releaseLeft==-60 &&moOnCleanState!=null){//判断特殊情况
                    moOnCleanState.onOpen(true);
                }
            } else if (releaseLeft >= -meaWidth / 2) {
                //关闭
                mViewDragHelper.smoothSlideViewTo(mainView, 0, 0);
                finalState = 0;
                if(releaseLeft==0 &&moOnCleanState!=null){//判断特殊情况
                    moOnCleanState.onColse(false);
                }
            }
        }
    };

4.同时我这里添加了平滑动画。实现的平滑滑动。避免突兀的滑动。

  /**
     * 更新状态
     */
    private void dispatchDragEvent() {
        int currentLeft = mainView.getLeft();
       // System.out.println(currentLeft+"--------"+finalState);
        if(moOnCleanState != null){//如果设定了监听
            if(finalState==2){
                moOnCleanState.onDrag();
            }else  if(finalState==1 && currentLeft==-60){
                moOnCleanState.onOpen(true);
            }else if(finalState==0&& currentLeft==0){
                moOnCleanState.onColse(false);
            }
        }

    }

    /**
     * 是否完成动画
     */
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mViewDragHelper.continueSettling(true)) {
            //如果没有画完。继续作画
            ViewCompat.postInvalidateOnAnimation(this);
        }
        invalidate();
    }

5.回调接口,以及回调方式

  * 删除状态监听
     */
    public void setOnCleanStateListener(onCleanState listener) {
        moOnCleanState = listener;
    }

    /**
     * 删除状态监听回调
     */
    public interface onCleanState {
        void onOpen(boolean flag);

        void onColse(boolean flag);

        void onDrag();
    }

6.简单的布局,

6.1Activity中的布局

<?xml version="1.0" encoding="utf-8"?>
<com.oblivion.ui.SlideClean xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:id="@+id/sc_clean"
    tools:context="com.oblivion.slideclean.MainActivity">

    <include layout="@layout/right" />
    <include layout="@layout/main" />

</com.oblivion.ui.SlideClean>

6.2显示的主布局

<?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="60dp"
    android:background="#ffffff"
    android:orientation="horizontal">

    <ImageView
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"
        android:src="@drawable/head" />

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:paddingLeft="10dp"
        android:text="宋江"
        android:textColor="#000000"
        android:textSize="20sp" />


</LinearLayout>

6.3要滑出的菜单的布局

<?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="60dp"
    android:orientation="horizontal">


    <TextView
        android:id="@+id/tv"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:background="#ff0000"
        android:gravity="center"
        android:text="删除"
        android:textColor="#ffffff" />

</LinearLayout>

7.主Activity中调用

package com.oblivion.slideclean;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;

import com.oblivion.ui.SlideClean;
import com.oblivion.utils.ToastUtils;

public class MainActivity extends AppCompatActivity {
private ListView lv_test;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);
        lv_test = (ListView) findViewById(R.id.lv_test);
        lv_test.setAdapter(new SlideCleanAdapter(lv_test));
    }
}

8.ListView适配器中回调

package com.oblivion.slideclean;

import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.oblivion.ui.SlideClean;
import com.oblivion.utils.Cheeses;
import com.oblivion.utils.ToastUtils;

/**
 * Created by oblivion on 2016/10/29.
 */
public class SlideCleanAdapter extends BaseAdapter {
    /**
     * 条目状态为打开时,默认为false
     */
    private boolean isClean = false;
    /**
     * 根据回调得到的boolean类型值,得到是否打开,默认为false
     */
    private boolean currentState = false;
    private ListView v;

    /**
     * 构造函数携带自身View对象过来
     *
     * @param v
     */
    public SlideCleanAdapter(ListView v) {
        this.v = v;
    }

    @Override
    public int getCount() {
        return Cheeses.NAMES.length;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, final ViewGroup parent) {
        final SlideClean view;
        if (convertView == null) {
            view = (SlideClean) View.inflate(parent.getContext(), R.layout.activity_main, null);
        } else {
            view = (SlideClean) convertView;
        }
        TextView tv_name = (TextView) view.findViewById(R.id.tv_name);
        tv_name.setText(Cheeses.NAMES[position]);
        TextView tv = (TextView) view.findViewById(R.id.tv);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isClean) {//如果为打开状态
                    ToastUtils.setToast(parent.getContext(), "清理");
                }
            }
        });
        //设定每个条目的监听
        view.setOnCleanStateListener(new SlideClean.onCleanState() {
            @Override
            public void onOpen(boolean flag) {//滑块为打开状态
                ToastUtils.setToast(parent.getContext(), "open");
                isClean = true;
                currentState = flag;
                view.setOpenState(currentState);
            }

            @Override
            public void onColse(boolean flag) {//滑块关闭状态
                ToastUtils.setToast(parent.getContext(), "close");
                isClean = false;
                currentState = flag;
            }

            @Override
            public void onDrag() {//滑动状态
                ToastUtils.setToast(parent.getContext(), "drag");
            }

        });
        v.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                ToastUtils.setToast(v.getContext(),"wocao");
            }
        });

        return view;
    }
}

gitHub源码地址下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值