LinearLayout 的侧滑删除

        在日常的开发中,大家很熟悉并常见的一种侧滑删除大概就是listview的侧滑删除了,对于listview的侧滑删除很好实现,但是如果是一个linearlayout的布局呢?在最近的项目中就遇到了这样的问题,整体的页面并不是一个列表只有一条数据,那样我们就不必再用listview了,为了节约内存资源,相信很多小伙们很少遇到这样的问题,所以准备撸一波代码,分享一下。

 首先感谢Android-->实现可滑动删除的Layout 这篇博客,很多东西都是在这篇博客的基础上改善的

    Android有比较成熟的开源项项目SwipeListview来实现列表的滑动删除功能

 接着来看看SwipeLayout的具体用法。

    1.SwipeLayout所需布局container_swipelayout.xml

 

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
     style="@style/hh_fi_wr"
       android:orientation="horizontal">

    <LinearLayout
        android:id="@+id/view_content"
       style="@style/hh_fi_wr"
        android:orientation="horizontal" >
    </LinearLayout>

    <RelativeLayout
        android:id="@+id/view_right"
        android:layout_width="80dp"
        android:layout_height="match_parent"
        android:clickable="true" >
    </RelativeLayout>

</merge>
主要的思想就是把SwipeLayout的布局分为两个部分,view_content用于加载正常的内容区域有,view_right用于加载右边侧滑的布局。其他的布局也还是类似的想法

下面我们来看SwipeLayout的代码实现,逻辑也不复杂


package com.huahansoft.medicaldoctor.view.SwipeLayout;

import android.content.Context;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Scroller;

import com.huahansoft.medicaldoctor.R;

/**
 * 
 * 类描述:
 * 类传参:
 * Creat byLyb on 2018/5/29 11:16
 */
public class SwipeLayout extends LinearLayout {
    private static final String TAG = "SwipeLayout";

    private Context mContext;

    private LinearLayout mContentView;

    private RelativeLayout mRightView;

    private Scroller mScroller;
    private OnSlideListener mOnSlideListener;
    private int mHolderWidth = 80;//此处是右边布局的宽度
    private int mLastX = 0;
    private int mLastY = 0;
    private static final int TAN = 2;
    private int mSlideState = 0;
    public interface OnSlideListener {
        int SLIDE_STATUS_OFF = 0;
        int SLIDE_STATUS_START_SCROLL = 1;
        int SLIDE_STATUS_ON = 2;
        void onSlide(View view, int status);
    }

    public SwipeLayout(Context context) {
        super(context);
        initView();
    }

    public SwipeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    private void initView() {
        mContext = getContext();
        mScroller = new Scroller(mContext);
        setOrientation(LinearLayout.HORIZONTAL);
        View.inflate(mContext, R.layout.container_swipelayout, this);
        mContentView = (LinearLayout) findViewById(R.id.view_content);
        mRightView = (RelativeLayout)findViewById(R.id.view_right);
        mHolderWidth = Math.round(TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, mHolderWidth, getResources()
                        .getDisplayMetrics()));
    }

    //将View加入到mContentView中
    public void setContentView(View view) {
        mContentView.addView(view);
    }

    //将View加入到mRightView中
    public void setRightView(View v) {
        mRightView.addView(v);
    }

    public void setOnSlideListener(OnSlideListener onSlideListener) {
        mOnSlideListener = onSlideListener;
    }

    //将当前状态设置为关闭
    public void shrink() {
        if (getScrollX() != 0) {
            this.smoothScrollTo(0, 0);
        }
    }

    //如果其子View存在消耗点击事件的View,那么SwipeLayout的onTouchEvent不会被执行,
    // 因为在ACTION_MOVE的时候返回true,执行其onTouchEvent方法
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }
                if (mOnSlideListener != null) {
                    mOnSlideListener.onSlide(this,
                            OnSlideListener.SLIDE_STATUS_START_SCROLL);
                    mSlideState = OnSlideListener.SLIDE_STATUS_START_SCROLL;
                }
                //这里需要记录mLastX,mLastY的值,不然当SwipeLayout已经处于开启状态时,
                // 用于再次滑动SwipeLayout时,会先立即复原到关闭状态,用户体验不太好
                mLastX = (int)ev.getX();
                mLastY = (int)ev.getY();
                return false;
            case MotionEvent.ACTION_MOVE:
                //返回值为true表示本次触摸事件由自己执行,即执行SwipeLayout的onTouchEvent方法
                int deltaX = x - mLastX;
                int deltaY = y - mLastY;
                //这里作用是来比较X、Y轴的滑动距离,如果X轴的滑动距离小于两倍的Y轴滑动距离,则不执行SwipeLayout的滑动事件
                if (Math.abs(deltaX) < Math.abs(deltaY) * TAN) {
                    return false;
                }
                //如果返回true,则子控件的事件几乎不会被触发
                return false;
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();
        int scrollX = getScrollX();
        switch (event.getAction()) {

            case MotionEvent.ACTION_MOVE: {
                int deltaX = x - mLastX;
                //如果SwipeLayout是在譬如ScrollView、ListView这种可以上下滑动的View中
                //那么当用户的手指滑出SwipeLayout的边界,那么将会触发器ACTION_CANCEL事件
                //如果此情形发生,那么SwipeLayout将会处于停止状态,无法复原。
                //增加下面这句代码,就是告诉父控件,不要cancel我的事件,我的事件我继续处理。
                getParent().requestDisallowInterceptTouchEvent(true);
                int newScrollX = scrollX - deltaX;
                if (deltaX != 0) {
                    if (newScrollX < 0) {
                        //最小的滑动距离为0
                        newScrollX = 0;
                    } else if (newScrollX > mHolderWidth) {
                        //最大的滑动距离就是mRightView的宽度
                        newScrollX = mHolderWidth;
                    }
                    this.scrollTo(newScrollX, 0);
                }
                break;
            }
            case MotionEvent.ACTION_UP: {

                int newScrollX = 0;
                //如果已滑动的距离满足下面条件,则SwipeLayout直接滑动到最大距离,不然滑动到最小距离0
                if (scrollX - mHolderWidth * 0.75 > 0) {
                    newScrollX = mHolderWidth;
                }
                this.smoothScrollTo(newScrollX, 0);
                if (mOnSlideListener != null) {
                    if (newScrollX == 0){
                        mOnSlideListener.onSlide(this, OnSlideListener.SLIDE_STATUS_OFF);
                        mSlideState = OnSlideListener.SLIDE_STATUS_OFF;
                    }
                    else {
                        mOnSlideListener.onSlide(this, OnSlideListener.SLIDE_STATUS_ON);
                        mSlideState = OnSlideListener.SLIDE_STATUS_ON;
                    }
                }
                getParent().requestDisallowInterceptTouchEvent(false);

            }
            default:
                break;
        }
        mLastX = x;
        mLastY = y;
        return true;
    }

    //获取当前SwipeLayout的滑动状态
    public int getSideState(){
        return mSlideState;
    }

    private void smoothScrollTo(int destX, int destY) {
        // 缓慢滚动到指定位置
        int scrollX = getScrollX();
        int delta = destX - scrollX;
        mScroller.startScroll(scrollX, 0, delta, 0, Math.abs(delta) * 3);
        invalidate();
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }

}

一切准备就绪,最后来看看具体怎么用SwipeLayout

在布局中直接引用这个SwipeLayout,然后在主函数中

        View contentView = LayoutInflater.from(this).inflate(R.layout.view_outpatient_stop_show, null);
        showContentTextView = (TextView) contentView.findViewById(R.id.tv_tip_content);
        showTimeTextView = (TextView) contentView.findViewById(R.id.tv_tip_time);

        View right = LayoutInflater.from(this).inflate(R.layout.right_swipe, null);
        deleteTextView = (TextView) right.findViewById(R.id.tv_right_dele);

        swipeLayout.setContentView(contentView);
        swipeLayout.setRightView(right);

好啦!一个完美的侧滑删除就实现了....

猜你喜欢

转载自blog.csdn.net/APPLYB/article/details/80701659