如何处理上recyclerView刷卡拆卸的是否正确? [英] How to handle swipe-to-remove on recyclerView correctly?

查看:139
本文介绍了如何处理上recyclerView刷卡拆卸的是否正确?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图让刷卡删除回收站视图的项目,但由于某些原因,它并不总是很好地发挥,显示出空的空间,而不是卡。

I'm trying to allow to swipe to remove items of the recycler view, but for some reason it doesn't always play nicely, showing empty spaces instead of the cards.

我做了code同时处理和急张移动的项目,触发刷卡的动画,当刷卡动画结束,该项目是从数据中删除,并通知过的适配器。

I've made the code handle both flinging and moving the item, to trigger the animation of the swiping, and when the swiping animation ends, the item is removed from the dataset and notifies the adapter too.

也许是因为我是新来RecyclerView,但我找不到什么遗漏。

Maybe it's because I'm new to RecyclerView, but I can't find what's missing.

 public class MainActivity extends ActionBarActivity
    {
    private RecyclerView mRecyclerView;
    private LinearLayoutManager mLayoutManager;
    private MyAdapter mAdapter;
    private static final int DATA_COUNT=100;
    private ArrayList<String> mDataSet;

    @Override
    protected void onCreate(final Bundle savedInstanceState)
      {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      mRecyclerView=(RecyclerView)findViewById(R.id.my_recycler_view);
      mRecyclerView.setHasFixedSize(true);
      mLayoutManager=new LinearLayoutManager(this);
  // TODO in case we use GridLayoutManager, consider using this: http://stackoverflow.com/q/26869312/878126
      mRecyclerView.setLayoutManager(mLayoutManager);
      mDataSet=new ArrayList<String>(DATA_COUNT);
      for(int i=0;i<DATA_COUNT;++i)
        mDataSet.add(Integer.toString(i));
      mAdapter=new MyAdapter(mDataSet);
      mRecyclerView.setAdapter(mAdapter);
      }

    // ///////////////////////////////////////////////////////////////
  // MyAdapter//
  // ///////////
    public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
      {
      private final ArrayList<String> mDataset;

      public class ItemViewType
        {
        private static final int HEADER=0, ITEM=1;
        }

      public MyAdapter(final ArrayList<String> myDataset)
        {
        mDataset=myDataset;
        }

      @Override
      public RecyclerView.ViewHolder onCreateViewHolder(final ViewGroup parent,final int viewType)
        {
        final RecyclerView.ViewHolder holder;
        final View rootView;
        switch(viewType)
          {
          case ItemViewType.HEADER:
            rootView=LayoutInflater.from(parent.getContext()).inflate(R.layout.header,parent,false);
            holder=new HeaderViewHoler(rootView);
            break;
          case ItemViewType.ITEM:
            rootView=LayoutInflater.from(parent.getContext()).inflate(R.layout.card,parent,false);
            holder=new ItemViewHolder(rootView);
            rootView.setAlpha(1);
            rootView.setTranslationX(0);
            rootView.setTranslationY(0);
            handleSwiping(rootView,holder);
            break;
          default:
            holder=null;
            break;
          }
        return holder;
        }

      private void handleSwiping(final View rootView,final RecyclerView.ViewHolder holder)
        {
        final GestureDetectorCompat gestureDetector=new GestureDetectorCompat(rootView.getContext(),
            new GestureDetector.OnGestureListener()
            {
            ...      
            @Override
            public boolean onFling(final MotionEvent e1,final MotionEvent e2,final float velocityX,
                                   final float velocityY)
              {
              final int viewSwipeThreshold=rootView.getWidth()/4;
              if(velocityX<-viewSwipeThreshold)
                {
                onSwipe(rootView,holder.getPosition(),false);
                return true;
                }
              else if(velocityX>viewSwipeThreshold)
                {
                onSwipe(rootView,holder.getPosition(),true);
                return true;
                }
              return false;
              }
            });
        rootView.setOnTouchListener(new View.OnTouchListener()
        {
        private final float originalX=0;
        private final float originalY=0;
        private float startMoveX=0;
        private float startMoveY=0;

        @Override
        public boolean onTouch(final View view,final MotionEvent event)
          {
          final int viewSwipeHorizontalThreshold=rootView.getWidth()/3;
          final int viewSwipeVerticalThreshold=view.getContext().getResources()
              .getDimensionPixelSize(R.dimen.vertical_swipe_threshold);
          if(gestureDetector.onTouchEvent(event))
            return true;
          final float x=event.getRawX(), y=event.getRawY();
          final float deltaX=x-startMoveX, deltaY=y-startMoveY;
          switch(event.getAction()&MotionEvent.ACTION_MASK)
            {
            case MotionEvent.ACTION_DOWN:
              startMoveX=x;
              startMoveY=y;
              break;
            case MotionEvent.ACTION_UP:
              if(Math.abs(deltaX)<viewSwipeHorizontalThreshold)
                {
                rootView.animate().translationX(originalX).translationY(originalY).alpha(1).start();
                if(Math.abs(deltaY)<viewSwipeHorizontalThreshold)
                  rootView.performClick();
                }
              else if(deltaX<0)
                onSwipe(rootView,holder.getPosition(),true);
              else
                onSwipe(rootView,holder.getPosition(),false);
              break;
            case MotionEvent.ACTION_CANCEL:
              if(Math.abs(deltaX)<viewSwipeHorizontalThreshold
                  ||Math.abs(deltaY)<viewSwipeVerticalThreshold)
                rootView.animate().translationX(originalX).translationY(originalY).alpha(1).start();
              else if(deltaX<0)
                onSwipe(rootView,holder.getPosition(),true);
              else
                onSwipe(rootView,holder.getPosition(),false);
              break;
            case MotionEvent.ACTION_POINTER_DOWN:
              break;
            case MotionEvent.ACTION_POINTER_UP:
              break;
            case MotionEvent.ACTION_MOVE:
              rootView.setAlpha(Math.max(Math.min((255-Math.abs(deltaX))/255f,1.0f),0.1f));
              rootView.setTranslationX(deltaX);
              break;
            }
          return true;
          }
        });

        }

      @Override
      public void onBindViewHolder(final RecyclerView.ViewHolder holder,final int position)
        {
        final int itemViewType=getItemViewType(position);
        final View rootView=holder.itemView;
        rootView.setAlpha(1);
        rootView.setTranslationX(0);
        rootView.setTranslationY(0);
        }

      private void onSwipe(final View rootView,final int position,final boolean isToLeft)
        {
        ViewPropertyAnimator animator;
        if(isToLeft)
          animator=rootView.animate().translationX(-rootView.getWidth());
        else
          animator=rootView.animate().translationX(rootView.getWidth());
        animator.setListener(new Animator.AnimatorListener()
        {
        @Override
        public void onAnimationStart(Animator animation)
          {
          }

        @Override
        public void onAnimationEnd(Animator animation)
          {
          rootView.setAlpha(1);
          mDataset.remove(position);
          notifyItemRemoved(position);
          }

        @Override
        public void onAnimationCancel(Animator animation)
          {
          }

        @Override
        public void onAnimationRepeat(Animator animation)
          {
          }
        });
        animator.start();
        }

      @Override
      public int getItemCount()
        {
        return mDataset.size()+1;
        }

      @Override
      public int getItemViewType(final int position)
        {
        return position==0?ItemViewType.HEADER:ItemViewType.ITEM;
        }
      }

  // ///////////////////////////////////////
  // HeaderViewHoler //
  // //////////////////

    public static class HeaderViewHoler extends RecyclerView.ViewHolder
      {
      public TextView mTextView;

      public HeaderViewHoler(final View v)
        {
        super(v);
        }
      }

    // ///////////////////////////////////////
  // ItemViewHolder //
  // /////////////////
    public static class ItemViewHolder extends RecyclerView.ViewHolder
      {

      public ItemViewHolder(final View rootView)
        {
        super(rootView);
        rootView.setAlpha(1);
        rootView.setTranslationX(0);
        rootView.setTranslationY(0);
        }
      }
    }

问题

什么是错在我做了什么?为什么有时会工作得很好,有时却没有?

The question

What is wrong in what I did? How come it sometimes works well and sometimes doesn't?

有可能的刷卡到删除处理一个更好的解决方案?

Is there maybe a better solution for the swipe-to-remove handling?

推荐答案

您不能访问位置参数回调,因为RecyclerView不会重新绑定一个ViewHolder只是因为它的位置已经改变。删除项目同时修改下面的所有项目的位置,使所有这些项目的位置的引用都将被废弃。

You cannot access the position parameter in the callback because RecyclerView will not rebind a ViewHolder just because its position has changed. Removing an item changes the position of all items below it so all of your position references for those items will be obsolete.

相反,你可以使用 ViewHolder#为getPosition 来获得最新的位置在用户操作的时间。

Instead, you can use ViewHolder#getPosition to get the up to date position at the time of the user action.

除此之外,不添加在onBind手势监听器和监听器联系,相反,当您创建ViewHolder添加。这样一来,你会避免每次一个项目是反弹创建一个新对象。

In addition to that, do not add the gesture listener and touch listener in onBind, instead, add them when you create the ViewHolder. This way, you'll avoid creating a new object each time an item is rebound.

更新您的评论。修改建议:

@Override
    public RecyclerView.ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
        RecyclerView.ViewHolder holder = null;
        View rootView;
        switch (viewType) {
        case ItemViewType.HEADER:
            rootView = LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false);
            holder = new HeaderViewHoler(rootView);
            break;
        case ItemViewType.ITEM:
            rootView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card, parent, false);
            holder = new ItemViewHolder(rootView);
            //initialize gesture detector and touch listener, replace position with getPosiiton
        }
        return holder;
    }

这篇关于如何处理上recyclerView刷卡拆卸的是否正确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆