ItemTouchHelper.SimpleCallbackを使用して、RecyclerViewの位置のスワイプを無効にします


92

recyclerview 22.2.0とヘルパークラスItemTouchHelper.SimpleCallbackを使用して、リストのスワイプして閉じるオプションを有効にしています。ただし、ヘッダーのタイプがあるため、アダプターの最初の位置のスワイプ動作を無効にする必要があります。以下のようRecyclerView.AdapterはありませんISENABLED()メソッドを、私はメソッドを介してビューの相互作用を無効にしようとしたISENABLED()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);
}

そして、私は2つのビュータイプを持つ共通のアダプターを持っています。スワイプを無効にしたい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);      
    }
}

回答:


204

少し遊んだ後、SimpleCallbackgetSwipeDirs()というメソッドがあることを管理しました。スワイプできない位置に特定のViewHolderがあるのでinstanceofを使用してスワイプを回避できます。そうでない場合は、アダプタのViewHolderの位置を使用してこの制御を実行できます。

Java

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

Kotlin

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

1
まさに私が探していたものです!この方法は、上に表示されていない場合は特に公式ドキュメント...
ptitvinou


2
言及する価値がある:特定のアイテムで一方向だけを許可したい場合は、return position == 0 ? ItemTouchHelper.LEFT : super.getSwipeDirs(recyclerView, viewHolder);これを使用します 。つまり、左スワイプのみを許可します。
jean d'arme 2016

完璧です。チャームのように働く
King of Masses 2018年

これはどのように作動しますか?たとえば、右スワイプを無効にしたい場合はどうすればよいですか?
アブ

66

誰かが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; //移動ドラッグreturnmakeFlag(ItemTouchHelper.ACTION_STATE_DRAG、dragFlags); //パラメータ、アクションドラッグ、フラグドラッグとして}
Do Xuan Nguyen

これは、(OPとは異なり)ItemTouchHelper.Callback直接拡張する場合に推奨される回答です。
tir38 2017

23

これを行う簡単な方法は、スワイプするアイテムの位置にのみ依存します。

@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値をのアダプターからデータを取得し、それに応じて無効にします。

スワイプする必要のない特定のホルダータイプがすでにある場合は、受け入れられた回答が機能します。ただし、位置のプロキシとしてホルダータイプを作成することは厄介であり、避ける必要があります。


6

これを行うにはいくつかの方法がありますが、ViewHolderが1つしかないが、レイアウトが複数ある場合は、このアプローチをとることができます。

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);
    }
}

ビュータイプに基づいてさまざまなレイアウトのコンテンツビューを取得しますpublicstatic class AppListItemHolder extends 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は最終的なもの
ティム・

3

最初にonCreateViewHolderメソッドのrecyclerViewで、以下のコードのように、各viewHolderタイプのタグを設定します。

@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);

2

@Rafael Toledoの回答に加えて、Adapterのオブジェクト内のデータの位置またはタイプに基づいて、左スワイプや右スワイプなどの特定のスワイプジェスチャを削除する場合は、次のようにすることができます。

@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でチャットの会話を読み込んでおり、各アイテムに右(アーカイブの場合)と左(終了の場合)のスワイプジェスチャがあります。ただし、会話がアクティブでない場合は、リサイクラービューで特定のアイテムの右スワイプを無効にする必要があります。

だから私はをチェックし、activeChatそれに応じて右スワイプを無効にしました。


2

を使用して無効にすることができます 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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.