2016-10-03 57 views
0

我有一個RecyclerView,它顯示從數據庫派生的一系列視圖。我想確認用戶已經通過突出顯示其邊緣來選擇其中一個視圖,並且我已經成功地這樣做了。如果用戶繼續選擇不同選項,我希望刪除原始選擇中的突出顯示。這是我遇到了一些麻煩的地方。直接從RecyclerView訪問ViewHolder,按位置

最初的亮點並不是什麼問題,因爲我是在內部做的。但是,我不知道如何使用適配器位置訪問以前的視圖。我一直在搜索StackOverflow大約一個小時,因爲我無法在Android API或谷歌上找到很多東西。許多用戶似乎提出了類似的問題,但最終,細微的差異使任何有用的答案都無效。

裏面我ViewHolder,這是我RecyclerView的內部public class,我有一個OnClickListener如下:

@Override 
    public void onClick(View view) { 
     if(!selected) { 
      selected = true; 
      view.setBackgroundResource(R.drawable.default_selection_background); 
     } else { 
      selected = false; 
      view.setBackgroundResource(0); 
     } 

     UpdateSelected(getAdapterPosition()); 
    } 

這點回到我的RecyclerView,並坦率地說,我還沒有添加任何的工作代碼我的UpdateSelected(int position)方法。

如果有幫助,我打算把它的功能是這樣的:

void UpdateSelected(int position) { 
    if(position != currentlySelected) { 
     ViewHolder[currentlySelected].Deselect(); 
    } 
} 

public class ViewHolder extends RecyclerView.ViewHolder { 
    ... 

    public void Deselect() { 
     // and from here, I can go on as normal. 
    } 
} 

我已經注意到了用戶的建議他人使用getLayoutPosition()來推導UI目的位置,除非他們特別希望繼續工作內部數據,這是我打算做的。

如何從我的RecyclerView使用其位置訪問特定的ViewHolder?

回答

3

你可以做這樣的事情。

在您的適配器中,創建一個會跟蹤所選物品位置的成員變量。

int selectedPosition = -1; // -1 some default value for nothing selected 

然後在你的回收站視圖適配器onBindViewHolder

int backgroundRes = (position == selectedPosition)? R.drawable.default_selection_background : 0; 
    view.setBackgroundResource(backgroundRes); 

最後,在你的viewholder的的onClick

@Override 
public void onClick(View view) { 
    selectedPosition = getAdapterPosition(); 
    notifyDataSetChanged(); 
} 
+0

太棒了!奇蹟般有效。我必須做的只是在'onBindViewHolder'中,它立即可以訪問'view'。我只是使用'viewHolder.itemView.setBackgroundResource(backgroundRes)'。爲了提高效率,我也只在'previousSelection'和'currentSelection'上使用'notifyItemChanged',但非常感謝。 – Gnemlock

+0

我也面臨同樣的問題。所以我嘗試這個解決方案,但在我的情況下沒有工作。 @Gnemlock –

+0

我只是偶然發現了這個答案,雖然不錯,但我建議將'notifyDataSetChanged()'更改爲'notifyItemChanged(selectedPosition)'。 當您可以精確地告訴適配器需要更新哪些視圖時,避免調用notifyDataSetChanged()是個好習慣。 –

1

您可以通過它訪問viewholder是從recyclerview位置

這是我實現

recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, 
       recyclerView, new RecyclerItemClickListener.OnItemClickListener() { 
      @Override 
      public void onItemClick(View view, int position) { 
       /*your coding */ 
      } 

      @Override 
      public void onItemLongClick(View view, int position) { 

      } 

     })); 

,並創建類

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { 

    private OnItemClickListener mListener; 
    private GestureDetector mGestureDetector; 
    public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) { 
     mListener = listener; 

     mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { 
      @Override 
      public boolean onSingleTapUp(MotionEvent e) { 
       return true; 
      } 
      @Override 
      public void onLongPress(MotionEvent e) { 
       View childView = recyclerView.findChildViewUnder(e.getX(), e.getY()); 

       if (childView != null && mListener != null) { 
        mListener.onItemLongClick(childView, recyclerView.getChildPosition(childView)); 
       } 
      } 
     }); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { 
     View childView = view.findChildViewUnder(e.getX(), e.getY()); 
     if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) { 
      mListener.onItemClick(childView, view.getChildPosition(childView)); 
     } 
     return false; 
    } 

    @Override 
    public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { 
    } 

    @Override 
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { 

    } 
    public interface OnItemClickListener { 
     void onItemClick(View view, int position); 
     void onItemLongClick(View view, int position); 
    } 
} 
0

代替手動交換的背景資源,可以改爲標記視圖中選擇與否,並有Android的變化的背景使用可繪製的選擇器。

res/drawable/background。XML

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:state_selected="true" android:drawable="@drawable/default_selection_background" /> 
    <item android:drawable="@null" /> 
</selector> 

background.xml將被設置爲你的項目的佈局XML的android:background

然後在你的onBindViewHolder(ViewHolder holder, int position)您必須更新Android查看的狀態:

@Override 
public void onBindViewHolder(ViewHolder holder, int position) { 
    boolean isSelected = position == selectedPosition; 
    holder.itemView.setSelected(isSelected); 
} 

對於我來說,我寧願具有適配器這是笨並有較少的邏輯。你可以通過保留ViewModel列表(數據類代表你將在視圖中顯示的內容 - 不多,不少於),在其中一個屬性可以是所選標記(在每個ViewModel中)的情況下做到這一點。

當用戶選擇或取消選擇視圖時,回調會向演示者發出更新,演示者然後更新適配器,並通知適配器哪些位置已更新。這意味着在演示者中保留當前選定的項目(最好是ID,但可以存儲ViewModel或位置),以便更新它。