2016-10-03 13 views
0

私はRecyclerViewを持っています。RecyclerViewはデータベースから派生した一連のビューを表示します。ユーザーがエッジを強調表示してビューの1つを選択したことを確認したいと思います。ユーザーが別のオプションを選択する場合は、元の選択範囲のハイライトを削除します。これは私が少し苦しんだところです。RecyclerViewから直接ViewHolderへのアクセス

最初のハイライトは、私が内部で行っていたように、問題はありませんでした。しかし、アダプタの位置だけで前のビューにアクセスする方法はわかりません。私はAndroid APIやgoogleから多くを見つけることができないので、StackOverflowを約1時間探しています。多くのユーザーが同様の質問をしているように見えますが、最終的に微妙な違いは役に立つ回答を無効にします。私RecyclerViewの内部public classである私のViewHolder、インサイド

次のように、私は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. 
    } 
} 

彼らは、具体的に作業を続けたい場合を除き、私は、UIの目的のために位置を導出するgetLayoutPosition()を使用して他の人に助言ユーザーに気づきました私がしようとしている内部データです。

RecyclerViewから特定のViewHolderにアクセスするにはどうすればよいですか?

答えて

3

あなたはこのようなことをすることができます。

アダプタで、選択した項目の位置を追跡するメンバー変数を作成します。次に、あなたのリサイクル・ビュー・アダプタの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にアクセスすることができます

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

はrecyclerview

からの位置ですは、あなたが選択したかのようにビューをマークし、Androidの変更に背景を持つ代わりにすることができますここに私の実装

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

代わりにクラスを作成しますドロアブルセレクタを使用します。

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のリスト(ビューに表示する内容を表すデータクラス、それ以上ないしはそれ以下)、プロパティの1つが(各ViewModel内の)選択されたフラグになる場合があります。

ユーザーがビューを選択または選択解除すると、コールバックによってプレゼンターへの更新が発行され、プレゼンターが更新され、アダプターが更新されたことをアダプターに通知します。これは、現在選択されている項目(IDが望ましいが、ViewModelまたは位置を格納できる)をプレゼンターに保持して、更新できるようにすることを意味します。

関連する問題