zoukankan      html  css  js  c++  java
  • 防微信左滑删除的效果

    package com.loaderman.swiperecycleviewdemo;
    
    import android.content.Context;
    import android.support.annotation.Nullable;
    import android.support.v7.widget.RecyclerView;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewConfiguration;
    
    
    public class SwipeRecycleView extends RecyclerView {
        private SwipeMenuLayout mLastMenuLayout;
        private int mLastTouchPosition;
        protected int mScaleTouchSlop;
    
        public SwipeRecycleView(Context context) {
            this(context, null);
        }
    
        public SwipeRecycleView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public SwipeRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            mScaleTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        }
    
        private int mLastX, mLastY;
        private int mDownX, mDownY;
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent event) {
            boolean isIntercepted = super.onInterceptTouchEvent(event);
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mLastX = (int) event.getX();
                    mLastY = (int) event.getY();
                    mDownX = (int) event.getX();
                    mDownY = (int) event.getY();
                    isIntercepted = false;
                    //根据MotionEvent的X Y值得到子View
                    View view = findChildViewUnder(mLastX, mLastY);
                    if (view == null) return false;
                    //点击的子View所在的位置
                    final int touchPos = getChildAdapterPosition(view);
                    if (touchPos != mLastTouchPosition && mLastMenuLayout != null
                            && mLastMenuLayout.currentState != SwipeMenuLayout.STATE_CLOSED) {
                        if (mLastMenuLayout.isMenuOpen()) {
                            //如果之前的菜单栏处于打开状态,则关闭它
                            mLastMenuLayout.smoothToCloseMenu();
                        }
                        isIntercepted = true;
                    } else {
                        //根据点击位置获得相应的子View
                        ViewHolder holder = findViewHolderForAdapterPosition(touchPos);
                        if (holder != null) {
                            View childView = holder.itemView;
                            if (childView != null && childView instanceof SwipeMenuLayout) {
                                mLastMenuLayout = (SwipeMenuLayout) childView;
                                mLastTouchPosition = touchPos;
                            }
                        }
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    int dx = (int) (mDownX - event.getX());
                    int dy = (int) (mDownY - event.getY());
                    if (Math.abs(dx) > mScaleTouchSlop && Math.abs(dx) > Math.abs(dy)
                            || (mLastMenuLayout != null && mLastMenuLayout.currentState != SwipeMenuLayout.STATE_CLOSED)) {
                        //如果X轴偏移量大于Y轴偏移量 或者上一个打开的菜单还没有关闭 则禁止RecycleView滑动 RecycleView不去拦截事件
                        return false;
                    }
                    break;
            }
            return isIntercepted;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent e) {
            switch (e.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    //若某个Item的菜单还没有关闭,则RecycleView不能滑动
                    if (!mLastMenuLayout.isMenuClosed()) {
                        return false;
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                case MotionEvent.ACTION_UP:
                    if (mLastMenuLayout != null && mLastMenuLayout.isMenuOpen()) {
                        mLastMenuLayout.smoothToCloseMenu();
                    }
                    break;
            }
            return super.onTouchEvent(e);
        }
    
    }
    
    package com.loaderman.swiperecycleviewdemo;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewConfiguration;
    import android.widget.LinearLayout;
    import android.widget.OverScroller;
    
    
    public class SwipeMenuLayout extends LinearLayout {
        public static final int STATE_CLOSED = 0;//关闭状态
        public static final int STATE_OPEN = 1;//打开状态
        public static final int STATE_MOVING_LEFT = 2;//左滑将要打开状态
        public static final int STATE_MOVING_RIGHT = 3;//右滑将要关闭状态
    
        public int currentState = 0;
        private int menuWidth;//菜单总长度
        private OverScroller mScroller;
        private int mScaledTouchSlop;
        private int mRightId;//右边隐藏菜单id
        private View rightMenuView;//右边的菜单按钮
        private int mLastX, mLastY;
        private int mDownX, mDownY;
    
        public SwipeMenuLayout(Context context) {
            this(context, null);
        }
    
        public SwipeMenuLayout(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public SwipeMenuLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mScroller = new OverScroller(context);
            ViewConfiguration configuration = ViewConfiguration.get(getContext());
            mScaledTouchSlop = configuration.getScaledTouchSlop();
            configuration.getScaledMaximumFlingVelocity();
            configuration.getScaledMinimumFlingVelocity();
            //获取右边菜单id
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SwipeMenuLayout);
            mRightId = typedArray.getResourceId(R.styleable.SwipeMenuLayout_right_id, 0);
            typedArray.recycle();
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            measureChildren(widthMeasureSpec, heightMeasureSpec);
            setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
            if (mRightId != 0) {
                rightMenuView = findViewById(mRightId);
            }
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            menuWidth = rightMenuView.getMeasuredWidth();
            super.onLayout(changed, l, t, r, b);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mDownX = (int) event.getX();
                    mDownY = (int) event.getY();
                    mLastX = (int) event.getX();
                    break;
                case MotionEvent.ACTION_MOVE:
                    int dx = (int) (mDownX - event.getX());
                    int dy = (int) (mDownY - event.getY());
                    //如果Y轴偏移量大于X轴偏移量 不再滑动
                    if (Math.abs(dy) > Math.abs(dx)) return false;
    
                    int deltaX = (int) (mLastX - event.getX());
                    if (deltaX > 0) {
                        //向左滑动
                        currentState = STATE_MOVING_LEFT;
                        if (deltaX >= menuWidth || getScrollX() + deltaX >= menuWidth) {
                            //右边缘检测
                            scrollTo(menuWidth, 0);
                            currentState = STATE_OPEN;
                            break;
                        }
                    } else if (deltaX < 0) {
                        //向右滑动
                        currentState = STATE_MOVING_RIGHT;
                        if (deltaX + getScrollX() <= 0) {
                            //左边缘检测
                            scrollTo(0, 0);
                            currentState = STATE_CLOSED;
                            break;
                        }
                    }
                    scrollBy(deltaX, 0);
                    mLastX = (int) event.getX();
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    if (currentState == STATE_MOVING_LEFT) {
                        //左滑打开
                        mScroller.startScroll(getScrollX(), 0, menuWidth - getScrollX(), 0, 300);
                        invalidate();
                    } else if (currentState == STATE_MOVING_RIGHT || currentState == STATE_OPEN) {
                        //右滑关闭
                        smoothToCloseMenu();
                    }
                    //如果小于滑动距离并且菜单是关闭状态 此时Item可以有点击事件
                    int deltx = (int) (mDownX - event.getX());
                    return !(Math.abs(deltx) < mScaledTouchSlop && isMenuClosed()) || super.onTouchEvent(event);
            }
            return super.onTouchEvent(event);
        }
    
        @Override
        public void computeScroll() {
            if (mScroller.computeScrollOffset()) {
                // Get current x and y positions
                int currX = mScroller.getCurrX();
                int currY = mScroller.getCurrY();
                scrollTo(currX, currY);
                postInvalidate();
            }
            if (isMenuOpen()) {
                currentState = STATE_OPEN;
            } else if (isMenuClosed()) {
                currentState = STATE_CLOSED;
            }
        }
    
        /**
         * 判断menu此时的状态
         *
         * @return true 打开状态 false 处于关闭状态
         */
        public boolean isMenuOpen() {
            return getScrollX() >= menuWidth;
        }
    
        /**
         * 判断menu此时的状态
         *
         * @return true 关闭状态 false 未关闭状态
         */
        public boolean isMenuClosed() {
            return getScrollX() <= 0;
        }
    
        /**
         * 关闭菜单
         */
        public void smoothToCloseMenu() {
            mScroller.startScroll(getScrollX(), 0, -getScrollX(), 0, 300);
            invalidate();
        }
    }
    
    package com.loaderman.swiperecycleviewdemo;
    
    import android.content.Context;
    import android.support.v7.widget.RecyclerView;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.TextView;
    import android.widget.Toast;
    
    
    public class SwipeAdapter extends RecyclerView.Adapter<SwipeAdapter.SwipeHolder> {
        private Context mContext;
    
        public SwipeAdapter(Context mContext) {
            this.mContext = mContext;
        }
    
        @Override
        public SwipeHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.swipe_menu_item, parent, false);
            return new SwipeHolder(view);
        }
    
        @Override
        public void onBindViewHolder(final SwipeHolder holder, final int position) {
            holder.tv_content.setText("这是第" + (position + 1) + "条数据");
            holder.tv_to_unread.setVisibility(position % 2 == 0 ? View.VISIBLE : View.GONE);
            holder.tv_to_top.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (holder.swipe_menu.isMenuOpen()) {
                        holder.swipe_menu.smoothToCloseMenu();
                    }
                    Toast.makeText(mContext, "置顶", Toast.LENGTH_SHORT).show();
                }
            });
            holder.tv_to_unread.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (holder.swipe_menu.isMenuOpen()) {
                        holder.swipe_menu.smoothToCloseMenu();
                    }
                    Toast.makeText(mContext, "标为未读", Toast.LENGTH_SHORT).show();
                }
            });
            holder.tv_to_delete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (holder.swipe_menu.isMenuOpen()) {
                        holder.swipe_menu.smoothToCloseMenu();
                    }
                    Toast.makeText(mContext, "删除", Toast.LENGTH_SHORT).show();
                }
            });
            holder.swipe_menu.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(mContext, "这是第" + (position + 1) + "条数据", Toast.LENGTH_SHORT).show();
                }
            });
        }
    
        @Override
        public int getItemCount() {
            return 30;
        }
    
        public class SwipeHolder extends RecyclerView.ViewHolder {
            private TextView tv_to_top, tv_to_unread, tv_to_delete, tv_content;
            private SwipeMenuLayout swipe_menu;
    
            public SwipeHolder(View itemView) {
                super(itemView);
                swipe_menu = (SwipeMenuLayout) itemView.findViewById(R.id.swipe_menu);
                tv_to_top = (TextView) itemView.findViewById(R.id.tv_to_top);
                tv_to_unread = (TextView) itemView.findViewById(R.id.tv_to_unread);
                tv_to_delete = (TextView) itemView.findViewById(R.id.tv_to_delete);
                tv_content = (TextView) itemView.findViewById(R.id.tv_content);
            }
        }
    }
    
    package com.loaderman.swiperecycleviewdemo;
    
    import android.graphics.Rect;
    import android.support.v7.widget.RecyclerView;
    import android.view.View;
    
    
    public class MyDividerDecoration extends RecyclerView.ItemDecoration {
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
    //        super.getItemOffsets(outRect, view, parent, state);
            outRect.set(0, 0, 0, 2);
        }
    }
    
    package com.loaderman.swiperecycleviewdemo;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.support.v7.widget.LinearLayoutManager;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            SwipeRecycleView swipe_recycleview = (SwipeRecycleView) findViewById(R.id.swipe_recycleview);
            swipe_recycleview.setLayoutManager(new LinearLayoutManager(this));
            swipe_recycleview.addItemDecoration(new MyDividerDecoration());
            SwipeAdapter swipeAdapter = new SwipeAdapter(this);
            swipe_recycleview.setAdapter(swipeAdapter);
        }
    }
    

     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:id="@+id/activity_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.loaderman.swiperecycleviewdemo.MainActivity">
    
        <com.loaderman.swiperecycleviewdemo.SwipeRecycleView
            android:id="@+id/swipe_recycleview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </RelativeLayout>
    

     swipe_menu_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <com.loaderman.swiperecycleviewdemo.SwipeMenuLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/swipe_menu"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:layout_centerInParent="true"
        android:background="@color/white"
        android:orientation="horizontal"
        app:content_id="@+id/ll_layout"
        app:right_id="@+id/ll_right_menu">
    
        <LinearLayout
            android:id="@+id/ll_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">
    
            <TextView
                android:id="@+id/tv_content"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="20dp"
                android:gravity="center_vertical"
                android:text="HelloWorld"
                android:textSize="16sp" />
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="right"
                android:layout_marginLeft="20dp"
                android:layout_marginRight="20dp"
                android:gravity="center_vertical|end"
                android:text="左滑←←←"
                android:textSize="16sp" />
        </LinearLayout>
    
        <LinearLayout
            android:id="@+id/ll_right_menu"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal">
    
            <TextView
                android:id="@+id/tv_to_top"
                android:layout_width="90dp"
                android:layout_height="match_parent"
                android:background="@color/gray_holo_light"
                android:gravity="center"
                android:text="置顶"
                android:textColor="@color/white"
                android:textSize="16sp" />
    
            <TextView
                android:id="@+id/tv_to_unread"
                android:layout_width="90dp"
                android:layout_height="match_parent"
                android:background="@color/yellow"
                android:gravity="center"
                android:text="标为未读"
                android:textColor="@color/white"
                android:textSize="16sp" />
    
            <TextView
                android:id="@+id/tv_to_delete"
                android:layout_width="90dp"
                android:layout_height="match_parent"
                android:background="@color/red_f"
                android:gravity="center"
                android:text="删除"
                android:textColor="@color/white"
                android:textSize="16sp" />
        </LinearLayout>
    </com.loaderman.swiperecycleviewdemo.SwipeMenuLayout>
    

     attrs.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="SwipeMenuLayout">
            <!-- format="reference"意为参考某一资源ID -->
            <attr name="content_id" format="reference" />
            <attr name="right_id" format="reference" />
        </declare-styleable>
    </resources>
    

     color.xml

       <color name="white">#fff</color>
        <color name="red_f">#ff3c00</color>
        <item name="gray_holo_light" type="color">#ffd0d0d0</item>
        <color name="yellow">#c0ffbd21</color>
    

     效果图:

  • 相关阅读:
    八皇后问题
    Catalan数与出栈顺序个数,Java编程模拟
    推荐系统中的协同过滤
    集成学习
    背包问题
    逆波兰表达式
    [leetcode]775. Global and Local Inversions
    [LeetCode]Minimum Moves to Equal Array Elements1,2
    链接属性
    常用表格属性
  • 原文地址:https://www.cnblogs.com/loaderman/p/7027150.html
Copyright © 2011-2022 走看看