2016-02-08 5 views
7

RecyclerView kullanarak oluşturduğum bir öğe listesi var. Kullanıcı bunlardan birine tıkladığında, o seçilmiş öğenin arka plan rengini değiştiriyorum. Sorun, öğelerimde kaydırma yaptığımda ve geri dönüştürüldüklerinde, bazı öğeler seçilen öğenin arka plan rengini alır (yanlış). Eğer assing zorunda sizin onBindViewHolder yönteminde SonraRecyclerView, geri dönüşümde sorun yaratıyor

orderItem.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      orderItem.setSelected(xxxx); 
     } 
    }); 

: view Eğer mantık öğesi (nesne) içindeki değeri atamak değiştirmesi gerektiğini

public class OrderAdapter extends RecyclerView.Adapter<OrderAdapter.ViewHolder> { 

private static final String SELECTED_COLOR = "#ffedcc"; 

private List<OrderModel> mOrders; 

public OrderAdapter() { 
    this.mOrders = new ArrayList<>(); 
} 

public void setOrders(List<OrderModel> orders) { 
    mOrders = orders; 
} 

public void addOrders(List<OrderModel> orders) { 
    mOrders.addAll(0, orders); 
} 

public void addOrder(OrderModel order) { 
    mOrders.add(0, order); 
} 

@Override 
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
    Context context = parent.getContext(); 
    LayoutInflater inflater = LayoutInflater.from(context); 

    // Inflate the custom layout 
    View contactView = inflater.inflate(R.layout.order_main_item, parent, false); 

    // Return a new holder instance 
    ViewHolder viewHolder = new ViewHolder(contactView); 
    return viewHolder; 
} 

@Override 
public void onBindViewHolder(final ViewHolder viewHolder, final int position) { 
    final OrderModel orderModel = mOrders.get(position); 

    // Set item views based on the data model 
    TextView customerName = viewHolder.customerNameText; 

    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/dd/yyyy' 'HH:mm:ss:S"); 
    String time = simpleDateFormat.format(orderModel.getOrderTime()); 
    customerName.setText(time); 

    TextView orderNumber = viewHolder.orderNumberText; 
    orderNumber.setText("Order No: " + orderModel.getOrderNumber()); 

    Button button = viewHolder.acceptButton; 
    button.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      viewHolder.userActions.acceptButtonClicked(position); 
     } 
    }); 

    final LinearLayout orderItem = viewHolder.orderItem; 
    orderItem.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      viewHolder.userActions.itemClicked(orderModel); 
      viewHolder.orderItem.setBackgroundColor(Color.parseColor(SELECTED_COLOR)); 
     } 
    }); 
} 

@Override 
public int getItemCount() { 
    return mOrders.size(); 
} 


public static class ViewHolder extends RecyclerView.ViewHolder implements OrderContract.View { 

    public TextView customerNameText; 
    public Button acceptButton; 
    public TextView orderNumberText; 
    public OrderContract.UserActions userActions; 
    public LinearLayout orderItem; 

    public ViewHolder(View itemView) { 
     super(itemView); 

     userActions = new OrderPresenter(this); 

     customerNameText = (TextView) itemView.findViewById(R.id.customer_name); 
     acceptButton = (Button) itemView.findViewById(R.id.accept_button); 
     orderNumberText = (TextView) itemView.findViewById(R.id.order_number); 
     orderItem = (LinearLayout) itemView.findViewById(R.id.order_item_selection); 
    } 

    @Override 
    public void removeItem() { 

    } 
} 
+0

Ayarlanan arka plan rengine bağlı olarak hangi öğenin seçildiğini korumalısınız –

cevap

7

sorun ViewHolder ürün için ekranın sizin dışarı atar recyclerView geri dönüşüm davranıştır sıfırlanmış edilmelidir başına içeriklerle ilgili olmayan herhangi bir değişiklik değiştirmek halinde ortaya çıkar Ekranda görüntülenecek yeni öğeler. Yukarıdaki tüm cevaplarda olduğu gibi mantığınızı ViewHolder nesnesine göre bağlamanızı önermem. Bu gerçekten sana sorun çıkarır. ViewHolder nesnesinin veri nesnesinin durumuna bağlı olarak mantık oluşturmalısınız, çünkü ne zaman geri dönüştürüleceğini bilemezsiniz.

Bir devlet boolean kontrol etmek ViewHolder yılında IsSelected kurtarmak varsayalım, ama ve eğer doğruysa bu viewHolder geri dönüşümlü olacak, o zaman aynı durum yeni Öğe için orada olacak. Yukarıda yapılacak

iyi şekilde DataModel nesnesinin herhangi bir durum tutmaktadır. Sizin durumunuzda sadece bir boolean seçilmiştir. @Gabriel yorumunda sorulan gibi

package chhimwal.mahendra.multipleviewrecyclerproject; 

import android.content.Context; 
import android.support.v7.widget.RecyclerView; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.support.v7.widget.CardView; 
import android.widget.TextView; 

import java.util.List; 

/** 
* Created by mahendra.chhimwal on 12/10/2015. 
*/ 
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> { 

    private Context mContext; 
    private List<DataModel> mRViewDataList; 


    public MyRecyclerViewAdapter(Context context, List<DataModel> rViewDataList) { 
     this.mContext = context; 
     this.mRViewDataList = rViewDataList; 
    } 

    @Override 
    public MyRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 
     View view = inflater.inflate(R.layout.item_recycler_view, parent, false); 
     return new ViewHolder(view); 
    } 

    @Override 
    public void onBindViewHolder(ViewHolder holder, int position) { 
     holder.bindDataWithViewHolder(mRViewDataList.get(position)); 
    } 

    @Override 
    public int getItemCount() { 
     return mRViewDataList != null ? mRViewDataList.size() : 0; 
    } 


    public class ViewHolder extends RecyclerView.ViewHolder { 
     private TextView textView; 
     private LinearLayout llView; 
     private DataModel mDataItem=null; 

     public ViewHolder(View itemView) { 
      super(itemView); 
      llView=(LinearLayout)itemView.findViewById(R.id.ll_root_view); 
      textView = (TextView) itemView.findViewById(R.id.tvItemName); 
      cvItemView.setOnClickListener(new View.OnClickListener() { 
       @Override 
       public void onClick(View v) { 
        // One should handle onclick of event here based on the dataItem i.e. mDataItem in this case. 
        // something like that.. 
       /* Intent intent = new Intent(mContext,ResultActivity.class); 
       intent.putExtra("MY_DATA",mDataItem); //If you want to pass data. 
       intent.putExtra("CLICKED_ITEM_POSTION",getAdapterPosition()); // If one want to get selected item position 
       startActivity(intent);*/ 
       Toast.makeText(mContext,"You clicked item number "+ViewHolder.this.getAdapterPosition(),Toast.LENTH_SHORT).show(); 
       } 
      }); 
     } 

     //This is clean method to bind data with viewHolder. Do all dirty things on View based on dataItem. 
     //Must be called from onBindViewHolder(),with dataItem. In our case dataItem is String object. 
     public void bindDataWithViewHolder(DataModel dataItem){ 
      this.mDataItem=dataItem; 

      if(mDataItem.isSelected()){ 
       llView.setBackgroundColor(Color.ParseColor(SELCTED_COLOR); 
      }else{ 
       llView.setBackgroundColor(Color.ParseColor(DEFAULT_COLOR); 
      } 
      //other View binding logics like setting text , loading image etc. 
      textView.setText(mDataItem); 
     } 
    } 
} 

gibi

Numune örneği, tek seferde tek bir öğe seçmek istediğini eğer

? Bu durumda

, yine kimse geri dönüşümlü ve size soruna neden olur aynı şekilde, ViewHolder nesne öğe durumuna seçili tasarruf olmamalıdır. Daha iyi bir yol için Adapter sınıfında alanı ViewHolder değil. Aşağıdaki kod snippet'i gösterilmektedir.Yalnızca seçilen Öğe durumunu korumak için varsa RecyclerView Bu durumlarda çok daha fazla esneklik sağladığı için

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> { 



     private Context mContext; 
     private List<DataModel> mRViewDataList; 

     //variable to hold selected Item position 
     private int mSelectedItemPosition = -1; 


     public MyRecyclerViewAdapter(Context context, List<DataModel> rViewDataList) { 
      this.mContext = context; 
      this.mRViewDataList = rViewDataList; 
     } 

     @Override 
     public MyRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
      LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 
      View view = inflater.inflate(R.layout.item_recycler_view, parent, false); 
      return new ViewHolder(view); 
     } 

     @Override 
     public void onBindViewHolder(ViewHolder holder, int position) { 
      holder.bindDataWithViewHolder(mRViewDataList.get(position),position); 
     } 

     @Override 
     public int getItemCount() { 
      return mRViewDataList != null ? mRViewDataList.size() : 0; 
     } 


     public class ViewHolder extends RecyclerView.ViewHolder { 
      private TextView textView; 
      private LinearLayout llView; 
      private DataModel mDataItem=null; 

      public ViewHolder(View itemView) { 
       super(itemView); 
       llView=(LinearLayout)itemView.findViewById(R.id.ll_root_view); 
       textView = (TextView) itemView.findViewById(R.id.tvItemName); 
       cvItemView.setOnClickListener(new View.OnClickListener() { 
        @Override 
        public void onClick(View v) { 
         //Handling for background selection state changed 
         int previousSelectState=mSelectedItemPosition; 
         mSelectedItemPosition = getAdapterPosition(); 
         //notify previous selected item 
         notifyItemChanged(previousSelectState); 
         //notify new selected Item 
         notifyItemChanged(mSelectedItemPosition); 

         //Your other handling in onclick 

        } 
       }); 
      } 

      //This is clean method to bind data with viewHolder. Do all dirty things on View based on dataItem. 
      //Must be called from onBindViewHolder(),with dataItem. In our case dataItem is String object. 
      public void bindDataWithViewHolder(DataModel dataItem, int currentPosition){ 
       this.mDataItem=dataItem; 
       //Handle selection state in object View. 
       if(currentPosition == mSelectedItemPosition){ 
        llView.setBackgroundColor(Color.ParseColor(SELCTED_COLOR); 
       }else{ 
        llView.setBackgroundColor(Color.ParseColor(DEFAULT_COLOR); 
       } 
       //other View binding logics like setting text , loading image etc. 
       textView.setText(mDataItem); 
      } 
     } 
    } 

, şiddetle notifyDataSetChanged() Adaptör sınıfının yönteminin kullanılmasını önermemektedir.

+0

Cevabınızı doğru olarak işaretledim, bunu yaptığımda tam olarak düşünmedim. Ama bununla ilgili bir problem var, eğer mDataItem.isSelected() öğesinin true olup olmadığını kontrol ettiğiniz if ifadenizde, bu her zaman böyle olur, bir kez seçtiğinizde bir öğe seçildiğinde sonsuza dek seçilebilir. Ama başka bir öğe seçildiğinde seçimini kaldırmanız gerekiyor! – Gabriel

+0

@Gabriel, navigasyon gibi tek seferde sadece bir öğe seçmek istiyorsanız, Çekmece genellikle başka bir durumdur. Soru, tek seferde tek bir seçime gereksinim duymaz. Ancak bunu çok zarif bir şekilde halledebilirsiniz. Lütfen güncellenmiş yanıtıma bir göz atın. –

+0

@Gabriel sorununun çözülüp çözülmediğini bana bildirir mi? –

1

değil: Burada benim Adaptçrünün kodunu görebilirsiniz öğedeki bu değere göre renk.

if (orderItem.isSelected()){ 
    viewHolder.orderItem.setBackgroundColor(xxxx); 
} else { 
    viewHolder.orderItem.setBackgroundColor(xxxx); 
} 
+0

Cevabınıza artı bir tane verdim, bunu yaptığımda tam olarak düşünmedim. Ama bununla ilgili bir problem var, eğer mDataItem.isSelected() öğesinin true olup olmadığını kontrol ettiğiniz if ifadenizde, bu her zaman böyle olur, bir kez seçtiğinizde bir öğe seçildiğinde sonsuza dek seçilebilir. Ama başka bir öğe seçildiğinde seçimini kaldırmanız gerekiyor! – Gabriel

+0

@Gabriel Cevap, kaydırma yaparken neden sorun yaşadığınızı açıklar. Tabii ki tüm davalarınızı çözemez. Öğeyi seçmemeniz gerekiyorsa, tıklamanızın clickListener'da değiştirilmesini sağlayın. Diğer öğeleri devre dışı bırakın veya seçilen öğenin kimliğini (konumun değil) saklayın. –

1

Bu, kolay bir çözümü olan oldukça yaygın bir hatadır.

Hızlı cevap:

if (orderItem.isSelected()){ 
    viewHolder.orderItem.setBackgroundColor(Color.parseColor(SELECTED_COLOR)); 
} else { 
    viewHolder.orderItem.setBackgroundColor(Color.parseColor(DEFAULT_COLOR)); 
} 

(DEFAULT_COLOR viewholder varsayılan olarak sahip renk ile)

Açıklaması cevap : Sistem bir viewholder geri dönüştürür zaman sadece aramaların onBindViewHolder yönteminde bu satırı ekleyin onBindViewHolder yöntemi bu nedenle, bu görüntüleyicinin herhangi birisini değiştirdiyseniz, sıfırlamanız gerekir. Eğer arka plan, öğenin konumunu vb o yöntemle