Android仿QQ左滑删除置顶ListView

最近闲来无事,于是研究了一下qq的左滑删除效果,尝试着实现了一下,先上效果图:

左滑删除置顶

大致思路原理:
- 通过设置margin实现菜单的显示与隐藏
- 监听onTouchEvent,处理滑动事件

上代码

import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.ListView;

/**
 * Created by MooreLi on 2016/8/8.
 */
public class SlideListView extends ListView {
    
    
    private String TAG = getClass().getSimpleName();

    private int mScreenWidth;
    private int mDownX;
    private int mDownY;
    private int mMenuWidth;

    private boolean isMenuShow;
    private boolean isMoving;

    private int mOperatePosition = -1;
    private ViewGroup mPointChild;
    private LinearLayout.LayoutParams mLayoutParams;

    public SlideListView(Context context) {
        super(context);
        getScreenWidth(context);
    }

    public SlideListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        getScreenWidth(context);
    }

    public SlideListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        getScreenWidth(context);
    }

    private void getScreenWidth(Context context) {
        WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics dm = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(dm);
        mScreenWidth = dm.widthPixels;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                performActionDown(ev);
                break;
            case MotionEvent.ACTION_MOVE:
                performActionMove(ev);
                break;
            case MotionEvent.ACTION_UP:
                performActionUp();
                break;
        }
        return super.onTouchEvent(ev);
    }

    private void performActionDown(MotionEvent ev) {
        mDownX = (int) ev.getX();
        mDownY = (int) ev.getY();
        //如果点击的不是同一个item,则关掉正在显示的菜单
        int position = pointToPosition(mDownX, mDownY);
        if (isMenuShow && position != mOperatePosition) {
            turnToNormal();
        }
        mOperatePosition = position;
        mPointChild = (ViewGroup) getChildAt(position - getFirstVisiblePosition());
        if (mPointChild != null) {
            mMenuWidth = mPointChild.getChildAt(1).getLayoutParams().width;
            mLayoutParams = (LinearLayout.LayoutParams) mPointChild.getChildAt(0).getLayoutParams();
            mLayoutParams.width = mScreenWidth;
            setChildLayoutParams();
        }
    }

    private boolean performActionMove(MotionEvent ev) {
        int nowX = (int) ev.getX();
        int nowY = (int) ev.getY();
//        if (isMoving) {
    
    
//            if (Math.abs(nowY - mDownY) > 0) {
    
    
//                Log.e(TAG, "kkkkkkk");
//                onInterceptTouchEvent(ev);
//            }
//        }
        if (Math.abs(nowX - mDownX) > 0) {
            //左滑 显示菜单
            if (nowX < mDownX) {
                if (isMenuShow) {
                    mLayoutParams.leftMargin = -mMenuWidth;
                } else {
                    //计算显示的宽度
                    int scroll = (nowX - mDownX);
                    if (-scroll >= mMenuWidth) {
                        scroll = -mMenuWidth;
                    }
                    mLayoutParams.leftMargin = scroll;
                }
            }
            //右滑 如果菜单显示状态,则关闭菜单
            if (isMenuShow && nowX > mDownX) {
                int scroll = nowX - mDownX;
                if (scroll >= mMenuWidth) {
                    scroll = mMenuWidth;
                }
                mLayoutParams.leftMargin = scroll - mMenuWidth;
            }
            setChildLayoutParams();
            isMoving = true;
            return true;
        }

        return super.onTouchEvent(ev);
    }

    private void performActionUp() {
        //超过一半时,显示菜单,否则隐藏
        if (-mLayoutParams.leftMargin >= mMenuWidth / 2) {
            mLayoutParams.leftMargin = -mMenuWidth;
            setChildLayoutParams();
            isMenuShow = true;
        } else {
            turnToNormal();
        }
        isMoving = false;
    }

    private void setChildLayoutParams(){
        if(mPointChild != null){
            mPointChild.getChildAt(0).setLayoutParams(mLayoutParams);
        }
    }

    /**
     * 正常显示
     */
    public void turnToNormal() {
        mLayoutParams.leftMargin = 0;
        mOperatePosition = -1;
        setChildLayoutParams();
        isMenuShow = false;
    }
}
item的布局要注意,因为在自定义view中写死的是获取第一个子布局为显示内容,所以需要将显示的样式写在一个容器中,将菜单写在另一个容器中,两个平行的关系。
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="wrap_content"
    android:background="#FFFFFF"
    android:orientation="horizontal">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/main_tv_title"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginLeft="10dp"
            android:gravity="center_vertical"
            android:textSize="18sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="180dp"
        android:layout_height="60dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/main_tv_delete"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FF0000"
            android:gravity="center"
            android:text="删除"
            android:textColor="#FFFFFF" />

        <TextView
            android:id="@+id/main_tv_top"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#DFCDBF"
            android:gravity="center"
            android:text="置顶"
            android:textColor="#FFFFFF" />
    </LinearLayout>
</LinearLayout>
最后就是删除操作与置顶操作,这个就比较简单,给按钮添加点击事件即可。我是在adapter中定义实现,记得操作后要将菜单关掉!
上部分代码:
        holder.tvTitle.setText(mInfos.get(position));
        holder.tvDelete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mInfos.remove(position);
                notifyDataSetChanged();
                mListView.turnToNormal();
            }
        });
        holder.tvTop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String temp = mInfos.get(position);
                mInfos.remove(position);
                mInfos.add(0, temp);
                notifyDataSetChanged();
                mListView.turnToNormal();
            }
        });

最后还有一个遗留问题,ListView左右滑动的时候上下也会滑动,这个有待探索与改进,也希望大家提提意见,帮我改进!

猜你喜欢

转载自blog.csdn.net/lizebin_bin/article/details/52161370