【问题标题】:Disable Swipe for position in RecyclerView using ItemTouchHelper.SimpleCallback使用 ItemTouchHelper.SimpleCallback 禁用在 RecyclerView 中的位置滑动
【发布时间】:2015-06-08 15:22:43
【问题描述】:

我正在使用 recyclerview 22.2.0 和辅助类 ItemTouchHelper.SimpleCallback 来启用列表中的 swipe-to-dismiss 选项。但由于我上面有一种标题,我需要禁用适配器第一个位置的滑动行为。由于 RecyclerView.Adapter 没有 isEnabled() 方法,我尝试通过 isEnabled() 方法禁用视图交互strong>isFocusable() 在 ViewHolder 创建本身,但没有成功。我尝试将滑动阈值调整为完整值,例如 SimpleCallback 的方法 getSwipeThreshold() 中的 0f ot 1f,但也没有成功。

我的一些代码片段可以帮助你帮助我。

我的活动:

@Override
protected void onCreate(Bundle bundle) {
    //... initialization
    ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0,
            ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {

        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                          RecyclerView.ViewHolder target) {
            return false;
        }

        @Override
        public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
            if (viewHolder instanceof CartAdapter.MyViewHolder) return 1f;
            return super.getSwipeThreshold(viewHolder);
        }

        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {

        }
    };

    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
    itemTouchHelper.attachToRecyclerView(recyclerView);
}

我有一个带有 两种 视图类型的通用适配器。在我想禁用滑动的 ViewHolder 中,我做了:

public static class MyViewHolder extends RecyclerView.ViewHolder {
    public ViewGroup mContainer;

    public MyViewHolder(View v) {
        super(v);
        v.setFocusable(false);
        v.setEnabled(false);
        mContainer = (ViewGroup) v.findViewById(R.id.container);      
    }
}

【问题讨论】:

    标签: android android-recyclerview


    【解决方案1】:

    玩了一会儿之后,我发现SimpleCallback 有一个名为getSwipeDirs() 的方法。因为我在 not swipable 位置有一个特定的 ViewHolder,所以我可以利用 instanceof 来避免滑动。如果不是您的情况,您可以使用 ViewHolder 在 Adapter 中的位置来执行此控制。

    Java

    @Override
    public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        if (viewHolder instanceof CartAdapter.MyViewHolder) return 0;
        return super.getSwipeDirs(recyclerView, viewHolder);
    }
    

    科特林

    override fun getSwipeDirs (recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
        if (viewHolder is CartAdapter.MyViewHolder) return 0
        return super.getSwipeDirs(recyclerView, viewHolder)
    }
    

    【讨论】:

    • 正是我想要的!特别是当official documentation上没有出现这个方法时...
    • 值得一提:如果您只想在某些项目上允许一个方向,然后使用return position == 0 ? ItemTouchHelper.LEFT : super.getSwipeDirs(recyclerView, viewHolder); - 这个即只允许向左滑动。
    • 完美。像魅力一样工作
    • 这是如何工作的?例如,如果我想禁用向右滑动该怎么办?
    【解决方案2】:

    如果有人在使用 ItemTouchHelper.Callback。然后您可以在 getMovementFlags(..) 函数中删除任何相关标志。

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }
    

    这里可以代替 dragFlagsswipeFlags 传递 0 来禁用相应的功能。

    ItemTouchHelper.START 表示在从左到右的区域设置(LTR 应用程序支持)的情况下从左到右滑动,但在从右到左的区域设置(RTL 应用程序支持)的情况下则相反。 ItemTouchHelper.END 表示向START 的相反方向滑动。

    因此您可以根据自己的要求删除任何标志。

    【讨论】:

    • 谢谢!,我使用代码:@Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; // 移动拖动 return makeFlag( ItemTouchHelper.ACTION_STATE_DRAG , dragFlags); // 作为参数,动作拖拽和标志拖拽 }
    • 如果(与 OP 不同)您直接扩展 ItemTouchHelper.Callback,这是首选答案。
    【解决方案3】:

    这里有一个简单的方法来做到这一点,它只取决于被滑动的项目的位置:

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder holder) {
        int position = holder.getAdapterPosition();
        int dragFlags = 0; // whatever your dragFlags need to be
        int swipeFlags = createSwipeFlags(position)
    
        return makeMovementFlags(dragFlags, swipeFlags);
    }
    
    private int createSwipeFlags(int position) {
      return position == 0 ? 0 : ItemTouchHelper.START | ItemTouchHelper.END;
    }
    

    如果您使用SimpleCallback,这也应该有效:

    @Override
    public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder holder) {
        int position = holder.getAdapterPosition();
        return createSwipeFlags(position);
    }
    
    private int createSwipeFlags(int position) {
      return position == 0 ? 0 : super.getSwipeDirs(recyclerView, viewHolder);
    }
    

    如果您想根据项目中的数据禁用刷卡,请使用position 值从适配器获取正在刷卡的项目的数据并相应地禁用。

    如果您已经有不需要刷卡的特定持有人类型,则接受的答案将起作用。但是,创建持有人类型作为头寸的代理是一种麻烦,应该避免。

    【讨论】:

      【解决方案4】:

      有几种方法可以解决这个问题,但如果您只有一个 ViewHolder,但有多个布局,则可以采用这种方法。

      覆盖 getItemViewType 并为其提供一些逻辑,以根据对象中数据的位置或类型确定视图类型(我的对象中有一个 getType 函数)

      @Override
      public int getItemViewType(int position) {
          return data.get(position).getType;
      }
      

      根据 ViewType 在 onCreateView 中返回正确的布局(确保将视图类型传递给 ViewHolder 类。

      @Override
      public AppListItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
          mContext = parent.getContext();
      
          if (viewType == 0){
              return new AppListItemHolder(LayoutInflater.from(mContext).inflate(R.layout.layout, parent, false), viewType);
          else
              return new AppListItemHolder(LayoutInflater.from(mContext).inflate(R.layout.header, parent, false), viewType);
          }
      }
      

      根据视图类型获取不同布局的内容视图 公共静态类 AppListItemHolder 扩展 RecyclerView.ViewHolder {

          public AppListItemHolder (View v, int viewType) {
              super(v);
      
              if (viewType == 0)
                  ... get your views contents
              else
                  ... get other views contents
              }
          }
      }
      

      然后在您的 ItemTouchHelper 中根据 ViewType 更改操作。对我来说,这会禁用 RecyclerView 部分标题的滑动

      @Override
      public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
          if (viewHolder.getItemViewType() == 1) return 0;
              return super.getSwipeDirs(recyclerView, viewHolder);
          }
      }
      

      【讨论】:

      • 好主意,但 getItemViewType 是最终的
      【解决方案5】:

      首先在recyclerView的onCreateViewHolder方法中,为每个viewHolder类型设置tag,如下代码:

      @Override
      public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
          if(ITEM_TYPE_NORMAL == viewType) {
              View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.deposite_card_view, viewGroup, false);
              ItemViewHolder holder = new ItemViewHolder(context, v);
              holder.itemView.setTag("normal");
              return holder;
          } else {
              View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_header, viewGroup, false);
              HeaderViewHolder holder = new HeaderViewHolder(context, v);
              holder.itemView.setTag("header");
              return holder;
          }
      } 
      

      然后在 ItemTouchHelper.Callback 实现中,更新 getMovementFlags 方法,如下所示:

      public class SwipeController extends ItemTouchHelper.Callback {
      
      @Override
      public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
          if("normal".equalsIgnoreCase((String) viewHolder.itemView.getTag())) {
              return makeMovementFlags(0, LEFT | RIGHT);
          } else {
              return 0;
          }
      }
      

      最后附加到recyclerView:

      final SwipeController swipeController = new SwipeController();
      
          ItemTouchHelper itemTouchHelper = new ItemTouchHelper(swipeController);
          itemTouchHelper.attachToRecyclerView(recyclerView);
      

      【讨论】:

        【解决方案6】:

        除了@Rafael Toledo 的回答之外,如果您想根据适配器中对象的位置或数据类型移除特定的滑动手势,例如向左滑动或向右滑动,那么您可以这样做。

        @Override
          public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
               {
                  int position = viewHolder.getAdapterPosition();
                  ConversationDataModel conversationModel = null;
                  conversationModel = mHomeAdapter.getItems().get(position);
                  boolean activeChat = true;
                  if(conversationModel!=null && !conversationModel.isActive())
                   {
                     activeChat = false;
                   }
          return activeChat ? super.getSwipeDirs(recyclerView, viewHolder): ItemTouchHelper.RIGHT;
                }
        

        在我的情况下,在我的 Recyclerview 中,我正在加载聊天对话,并且每个项目都有 RIGHT(用于 ARCHIVE)和 LEFT(用于 EXIT)滑动手势。但如果对话不活跃,那么我需要在 Recycler 视图中禁用特定项目的 RIGHT 滑动。

        所以我正在检查 activeChat 并相应地禁用了 RIGHT 滑动。

        【讨论】:

        • 这是与@M.Kouchi 的标签方法相结合的最接近我的最终解决方案。唯一需要改变的是,我没有返回 ItemTouchHelper.RIGHT,而是返回了 ACTION_STATE_IDLE。
        【解决方案7】:

        可以使用ItemTouchHelper.ACTION_STATE_IDLE禁用它

        ItemTouchHelper.SimpleCallback(
            ItemTouchHelper.UP or ItemTouchHelper.DOWN, //drag directions
            ItemTouchHelper.ACTION_STATE_IDLE //swipe directions
        )
        
        val touchHelperCallback = object : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.ACTION_STATE_IDLE) {
            override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
                (recyclerView.adapter as MyAdapter).onItemMove(viewHolder.adapterPosition, target.adapterPosition)
                return true
            }
        
            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                return
            }
        
        }
        val touchHelper = ItemTouchHelper(touchHelperCallback)
        touchHelper.attachToRecyclerView(recyclerViewX)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-07-25
          • 1970-01-01
          • 2016-11-19
          • 2020-11-10
          • 1970-01-01
          • 1970-01-01
          • 2017-08-31
          • 2021-10-08
          相关资源
          最近更新 更多