ItemTouchHelper.SimpleCallback kullanarak RecyclerView'da konum için Kaydırmayı devre dışı bırakın


92

Listemde hızlıca kaydır seçeneğini etkinleştirmek için recyclerview 22.2.0 ve yardımcı sınıf ItemTouchHelper.SimpleCallback kullanıyorum . Ancak üzerinde bir tür başlığım olduğundan, adaptörün ilk konumu için kaydırma davranışını devre dışı bırakmam gerekiyor. Şöyle RecyclerView.Adapter bir bulunmamaktadır isEnabled () metodu, I yöntemler vasıtasıyla görünüşüdür etkileşimi devre dışı bırakılmış IsEnabled () ve isFocusable () ViewHolder oluşturulması kendisinde, ancak başarılı olmamıştır. SimpleCallback'in getSwipeThreshold () yönteminde kaydırma eşiğini 0f ot 1f gibi tam bir değere ayarlamaya çalıştım , ancak başarı da yok.

Bana yardım etmenize yardımcı olacak kodumun bazı parçaları.

Faaliyetim:

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

Ve iki görünüm tipine sahip ortak bir adaptörüm var . Gelen ViewHolder ben devre dışı Kaydırma istiyorum, ben yaptım:

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

Yanıtlar:


204

Biraz oynadıktan sonra SimpleCallback'in getSwipeDirs () adında bir metodu olduğunu başardım . Kaydırılamayan konum için belirli bir ViewHolder'ım olduğundan , instanceof olduğundan, kaydırmayı önlemek için yararlanabilirim. Sizin durumunuz bu değilse, Adaptördeki ViewHolder konumunu kullanarak bu kontrolü gerçekleştirebilirsiniz.

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
Tam olarak aradığım şey! Özellikle bu yöntem resmi belgelerde görünmediğinde ...
ptitvinou


2
Bahsetmeye değer: Belirli öğelerde yalnızca bir yöne izin vermek istiyorsanız, o zaman kullanın return position == 0 ? ItemTouchHelper.LEFT : super.getSwipeDirs(recyclerView, viewHolder);- bunu, yani yalnızca sol kaydırmalara izin verin.
jean d'arme

Mükemmel. Cazibe gibi çalışmak
Kitlelerin Kralı

Bu nasıl çalışıyor? Örneğin, sağa kaydırmayı devre dışı bırakmak istersem ne yapmalıyım?
Ab

66

Birisi ItemTouchHelper.Callback kullanıyorsa . Daha sonra getMovementFlags (..) işlevinde ilgili tüm bayrakları kaldırabilirsiniz .

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

Burada dragFlags ve swipeFlags yerine Karşılık gelen özelliği devre dışı bırakmak için 0'ı geçebilirsiniz.

ItemTouchHelper.START , soldan sağa yerel ayar durumunda soldan sağa kaydırmak anlamına gelir (LTR uygulama Desteği), ancak tam tersi bir sağdan sola yerel ayarda (RTL uygulama Desteği). ItemTouchHelper.END , tersi yönde kaydırmak anlamına gelir START.

böylece gereksinimlerinize göre herhangi bir bayrağı kaldırabilirsiniz.


Teşekkür ederim, şu kodu kullanıyorum: @Override public int getMovementFlags (RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; // hareketleri sürükleyin return makeFlag (ItemTouchHelper.ACTION_STATE_DRAG, dragFlags); // parametre olarak, eylem sürükle ve işaretler sürükleme}
Do Xuan Nguyen

ItemTouchHelper.CallbackDoğrudan genişletiyorsanız (OP'nin aksine) bu tercih edilen cevaptır .
tir38

23

Bunu yapmanın, yalnızca kaydırılan öğenin konumuna bağlı olan basit bir yolu:

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

Bu, şunları kullanıyorsanız da çalışmalıdır 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);
}

Öğedeki verilere göre koşullu kaydırmayı devre dışı bırakmak istiyorsanız, kaydırılan öğe positioniçin bağdaştırıcıdan veri almak için değeri kullanın ve uygun şekilde devre dışı bırakın.

Zaten kaydırmamanız gereken belirli tutucu türleriniz varsa, kabul edilen yanıt işe yarayacaktır. Bununla birlikte, pozisyon için bir vekil olarak tutucu türleri oluşturmak bir karışıklıktır ve bundan kaçınılmalıdır.


6

Bunu yapmanın birkaç yolu var, ancak yalnızca bir ViewHolder'ınız varsa, ancak birden fazla düzeniniz varsa bu yaklaşımı uygulayabilirsiniz.

GetItemViewType'ı geçersiz kılın ve nesnedeki verilerin konumuna veya türüne göre görünüm türünü belirlemek için ona biraz mantık verin (Nesnemde bir getType işlevi var)

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

ViewType'a göre onCreateView'da uygun mizanpajı döndürün (Görünüm türünü ViewHolder sınıfına ilettiğinizden emin olun.

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

Görünüm türüne göre farklı düzenlerin içerik görünümlerini alın genel statik sınıf AppListItemHolder, RecyclerView.ViewHolder'ı genişletir {

    public AppListItemHolder (View v, int viewType) {
        super(v);

        if (viewType == 0)
            ... get your views contents
        else
            ... get other views contents
        }
    }
}

Ve sonra ItemTouchHelper'ınızda ViewType'a göre eylemleri değiştirin. Benim için bu, RecyclerView bölüm başlığının kaydırılmasını devre dışı bırakır

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

Güzel fikir ama getItemViewType son
tim

3

İlk olarak, onCreateViewHolder yönteminde recyclerView'de, aşağıdaki kod gibi her viewHolder türü için etiket ayarlayın:

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

ardından ItemTouchHelper.Callback uygulamasında getMovementFlags yöntemini aşağıdaki gibi güncelleyin:

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

sonunda geri dönüştürücüye ekleyin

final SwipeController swipeController = new SwipeController();

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

2

@Rafael Toledo cevabına ek olarak, Adapter'daki nesnedeki konum veya veri türüne göre SOL veya SAĞ kaydırma gibi belirli kaydırma hareketini kaldırmak istiyorsanız, bunu yapabilirsiniz.

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

Benim durumumda, Geri Dönüşümcü görünümümde sohbet konuşmalarını yüklüyorum ve her öğede SAĞ (ARŞİV için) ve SOL (ÇIKIŞ için) kaydırma hareketleri var. Ancak konuşma etkin değilse, Recycler görünümünde belirli bir öğe için SAĞ kaydırmayı devre dışı bırakmam gerekir.

Bu yüzden activeChatSAĞ kaydırmayı kontrol ediyorum ve buna göre ve devre dışı bırakıyorum.


2

Kullanılarak devre dışı bırakılabilir 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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.