Androidはサイドスライド削除コントロールを実現し、Recyclerviewをサポートします.

13039 ワード

効果図
ScreenGif5.gif
  • Recyclerviewをスライドさせると自動的にすべてのmenu
  • を閉じる.
  • 次のmenuをドラッグすると、前のmenu
  • が自動的に閉じる
  • 編集と削除をクリックすると、menu
  • が自動的に閉じます.
    実装手順
    ビューグループをカスタマイズ
    public class SwipeMenu extends ViewGroup
    
        private int downX, moveX, moved;
        private Scroller scroller = new Scroller(getContext());
        private onScrollStateChanged onScrollStateChanged;
        private boolean haveShowRight =false;
    

    書き換えonMeasure
    主に高さの再設定
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            measureChildren(widthMeasureSpec, heightMeasureSpec);
            int width = MeasureSpec.getSize(widthMeasureSpec);
            View child = getChildAt(0);
            int margin =
                    ((MarginLayoutParams) child.getLayoutParams()).topMargin +
                            ((MarginLayoutParams) child.getLayoutParams()).bottomMargin;
            setMeasuredDimension(width, getChildAt(0).getMeasuredHeight() + margin);
        }
    

    onLayoutを書き直す
    1つ目のviewをフルスクリーンに、2つ目のviewをメニューviewに
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            int cCount = getChildCount();
            for (int i = 0; i < cCount; i++) {
                View child = getChildAt(i);
                if (i == 0) {
                    child.layout(l, t, r, b);
                } else if (i == 1) {
                    child.layout(r, t, r + child.getMeasuredWidth(), b);
                }
            }
        }
    

    onInterruptTouchEventの書き換え
    moveが2を超えると判断しmenuをドラッグする意図でブロックする
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    downX = (int) ev.getRawX();
                    break;
                case MotionEvent.ACTION_MOVE:
                    moveX = (int) ev.getRawX();
                    if (moveX - downX > 2) {
                        return true;
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    break;
            }
            return super.onInterceptTouchEvent(ev);
        }
    

    onTouchEventを書き換える
    フレックススライドを処理し、メニューを表示するタイミング、メニューを閉じるタイミングを判断します
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            if(!scroller.isFinished()){
                return false;
            }
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    downX = (int) ev.getRawX();
                    break;
                case MotionEvent.ACTION_MOVE:
                    moveX = (int) ev.getRawX();
                    moved = moveX - downX;
                    if(haveShowRight){
                        moved-=getChildAt(1).getMeasuredWidth();
                    }
                    scrollTo(-moved, 0);
                    if (getScrollX() <= 0) {
                        scrollTo(0, 0);
                    } else if (getScrollX() >= getChildAt(1).getMeasuredWidth()) {
                        scrollTo(getChildAt(1).getMeasuredWidth(), 0);
                    }
                    break;
                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_UP:
                        if(getScrollX()>=getChildAt(1).getMeasuredWidth()/2){
                            haveShowRight = true;
                            smoothScrollTo(getChildAt(1).getMeasuredWidth(),0);
                        }else  {
                            haveShowRight = false;
                            smoothScrollTo(0,0);
                        }
                        onScrollStateChanged.onScrollChanged(haveShowRight);
    
                    break;
    
            }
            return true;
        }
    

    操作Recyclerview
    SwipMenuをバインドするときにスライドイベントをリスニングし、現在閉じていないメニューがあり、他のメニューをスライドするときに前のメニューを閉じ、削除と編集のためにクリックイベントを追加します.
    private SwipeMenu swipeMenu;
            adapter = new CommonAdapter(this, R.layout.item_test2, data) {
                @Override
                protected void convert(final ViewHolder holder, final String s, final int position) {
                    holder.setText(R.id.tv, s);
                    ((SwipeMenu) holder.getView(R.id.vg)).setOnScrollStateChanged(new SwipeMenu.onScrollStateChanged() {
                        @Override
                        public void onScrollChanged(boolean haveShowRight) {
                            if(swipeMenu == holder.getView(R.id.vg)){
                                return;
                            }
                            closeAllMenu();
                           if(haveShowRight){
                               swipeMenu =  holder.getView(R.id.vg);
                           }else {
                               swipeMenu = null;
                           }
                        }
                    });
                    holder.setOnClickListener(R.id.tv_del, new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            closeAllMenu();
                            Toast.makeText(MainActivity.this,"  "+position,Toast.LENGTH_SHORT).show();
                        }
                    });
                    holder.setOnClickListener(R.id.tv_edit, new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            closeAllMenu();
                            Toast.makeText(MainActivity.this,"  "+position,Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            };
    
        private void closeAllMenu() {
            if(swipeMenu !=null){
                swipeMenu.closeMenu();
            }
        }
    

    RecyclerViewスライド状態が変化した場合は、すべてのMenuをオフにします
            recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                    closeAllMenu();
                }
    
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
    
                }
            });
            recyclerView.setAdapter(adapter);
        }
    

    SwipMenuコードアドレス
    更新
    上記のコードは侵入性が強く、RecyclerviewとAdapterの操作が多く必要であり、static SwipMenuを1つ使用して侵入性の小さいviewを実現する
    効果図
    ScreenGif6.gif
    Recyclerviewリスニングスライド状態のコードを削除し、adapterでSwipeMenuリスニングスライド状態を削除し、SwipeMenuでブロックされたイベントのコードを削除します.
    SwipeMenu
    コードが少なく、使いやすい
    package com.administrator.customviewtest.successview;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Scroller;
    
    /**
     * Created by Administrator on 2017/6/27.
     */
    
    public class SwipeMenu extends ViewGroup {
        private int downX, moveX, moved;
        private Scroller scroller = new Scroller(getContext());
        private boolean haveShowRight = false;
        public static SwipeMenu swipeMenu;
    
    
        public SwipeMenu(Context context) {
            super(context);
        }
    
    
        public SwipeMenu(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public SwipeMenu(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            if (swipeMenu != null) {
                swipeMenu.closeMenus();
                swipeMenu = null;
            }
    
        }
    
        //         
        private void smoothScrollTo(int destX, int destY) {
            int scrollX = getScrollX();
            int delta = destX - scrollX;
            //1000ms   destX,        
            scroller.startScroll(scrollX, 0, delta, 0, 100);
            invalidate();
        }
    
        public void closeMenus() {
            smoothScrollTo(0, 0);
            haveShowRight = false;
        }
    
        public static void closeMenu() {
            swipeMenu.closeMenus();
        }
    
        @Override
        public void computeScroll() {
            if (scroller.computeScrollOffset()) {
                scrollTo(scroller.getCurrX(), scroller.getCurrY());
                postInvalidate();
            }
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            if (!scroller.isFinished()) {
                return false;
            }
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    downX = (int) ev.getRawX();
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (swipeMenu != null && swipeMenu == this && haveShowRight) {
                        closeMenu();
                        return true;
                    }
                    moveX = (int) ev.getRawX();
    
                    moved = moveX - downX;
    
                    if (haveShowRight) {
                        moved -= getChildAt(1).getMeasuredWidth();
                    }
                    scrollTo(-moved, 0);
                    if (getScrollX() <= 0) {
                        scrollTo(0, 0);
                    } else if (getScrollX() >= getChildAt(1).getMeasuredWidth()) {
                        scrollTo(getChildAt(1).getMeasuredWidth(), 0);
                    }
                    break;
                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_UP:
                    if (swipeMenu != null) {
                        closeMenu();
                    }
                    if (getScrollX() >= getChildAt(1).getMeasuredWidth() / 2) {
                        haveShowRight = true;
                        swipeMenu = this;
                        smoothScrollTo(getChildAt(1).getMeasuredWidth(), 0);
                    } else {
                        haveShowRight = false;
                        smoothScrollTo(0, 0);
                    }
    
                    break;
    
            }
            return true;
        }
    
        @Override
        public LayoutParams generateLayoutParams(AttributeSet attrs) {
            return new MarginLayoutParams(getContext(), attrs);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            measureChildren(widthMeasureSpec, heightMeasureSpec);
    
            int width = MeasureSpec.getSize(widthMeasureSpec);
            View child = getChildAt(0);
            int margin =
                    ((MarginLayoutParams) child.getLayoutParams()).topMargin +
                            ((MarginLayoutParams) child.getLayoutParams()).bottomMargin;
            setMeasuredDimension(width, getChildAt(0).getMeasuredHeight() + margin);
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            int cCount = getChildCount();
            for (int i = 0; i < cCount; i++) {
                View child = getChildAt(i);
                if (i == 0) {
                    child.layout(l, t, r, b);
                } else if (i == 1) {
                    child.layout(r, t, r + child.getMeasuredWidth(), b);
                }
            }
        }
    }
    

    使用方法
    適切な場所でSwipeMenu.closeMenu();を呼び出すだけでメニューを閉じることができます
    public class MainActivity extends AppCompatActivity {
        private RecyclerView recyclerView;
        private CommonAdapter adapter;
        private List data = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9","10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21");
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            recyclerView = ((RecyclerView) findViewById(R.id.rv));
            recyclerView.setLayoutManager(new LinearLayoutManager(this));
            recyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
            adapter = new CommonAdapter(this, R.layout.item_test2, data) {
                @Override
                protected void convert(final ViewHolder holder, final String s, final int position) {
                    holder.setText(R.id.tv, s);
                    holder.setOnClickListener(R.id.tv_del, new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            SwipeMenu.closeMenu();
                            Toast.makeText(MainActivity.this,"  "+position,Toast.LENGTH_SHORT).show();
                        }
                    });
                    holder.setOnClickListener(R.id.tv_edit, new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            SwipeMenu.closeMenu();
                            Toast.makeText(MainActivity.this,"  "+position,Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            };
            recyclerView.setAdapter(adapter);
        }
    }
    
    

    完全なコード