私はRecyclerView
を探索していましたが、RecyclerView
がonItemClickListener()
を持たないことに驚きました。 RecyclerView
は拡張するので
Android.view.ViewGroup
そしてListView
は拡張します
Android.widget.AbsListView
。しかし、私は自分のRecyclerView.Adapter
にonClick
を書くことで問題を解決しました。
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
}
@Override
public void onClick(View v) {
}
}
しかし、それでもGoogleがonItemClickListener()
を削除した理由を知りたいのですが。
パフォーマンスの問題などありませんか。
tl; dr 2016 / RxJavaとPublishSubjectを使用して、クリックに対してObservableを公開します。
public class ReactiveAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
String[] mDataset = { "Data", "In", "Adapter" };
private final PublishSubject<String> onClickSubject = PublishSubject.create();
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final String element = mDataset[position];
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onClickSubject.onNext(element);
}
});
}
public Observable<String> getPositionClicks(){
return onClickSubject.asObservable();
}
}
オリジナル投稿:
ListView
の登場以来、onItemClickListener
は問題がありました。あなたがクリックバックリスナーを持っている瞬間にはコールバックは引き起こされないでしょうが、通知されていないか(もしあったとしても)文書化されていないので、についての混乱とSO質問がたくさんありましたそれ。
RecyclerView
がさらに一歩進んで行/列の概念を持っているのではなく、任意にレイアウトされた量の子を持っていることを考えると、彼らはonClickをそれぞれの子またはプログラマ実装に委任しています。
Recyclerview
をListView
1:1の置き換えとしてではなく、複雑なユースケースのためのより柔軟なコンポーネントとして考えてください。そしてあなたが言うように、あなたの解決策はグーグルがあなたに期待したものです。これで、コンストラクタに渡されたインタフェースにonClickを委任できるアダプタができました。これは、ListView
とRecyclerview
の両方の正しいパターンです。
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public IMyViewHolderClicks mListener;
public ViewHolder(View itemLayoutView, IMyViewHolderClicks listener) {
super(itemLayoutView);
mListener = listener;
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
imgViewIcon.setOnClickListener(this);
itemLayoutView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v instanceof ImageView){
mListener.onTomato((ImageView)v);
} else {
mListener.onPotato(v);
}
}
public static interface IMyViewHolderClicks {
public void onPotato(View caller);
public void onTomato(ImageView callerImage);
}
}
それからあなたのアダプターで
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
String[] mDataset = { "Data" };
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_layout, parent, false);
MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() {
public void onPotato(View caller) { Log.d("VEGETABLES", "Poh-tah-tos"); };
public void onTomato(ImageView callerImage) { Log.d("VEGETABLES", "To-m8-tohs"); }
});
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Get element from your dataset at this position
// Replace the contents of the view with that element
// Clear the ones that won't be used
holder.txtViewTitle.setText(mDataset[position]);
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return mDataset.length;
}
...
最後のコードを見てください。onCreateViewHolder(ViewGroup parent, int viewType)
シグネチャはすでにさまざまなビュータイプを提案しています。それぞれに異なるビューホルダーも必要です。その後、それぞれが異なるクリックセットを持つことができます。あるいは、任意のビューと1つのonClickListener
を取り、それに応じて適用される汎用ビューホルダーを作成することもできます。または、1つ上のレベルのオーケストレータに委任して、複数のフラグメント/アクティビティが同じリストを持ち、クリック動作が異なるようにします。繰り返しますが、すべての柔軟性はあなたの側にあります。
これは本当に必要なコンポーネントであり、これまでの内部実装とListView
への改善にかなり近いものです。グーグルがついにそれを認めたのは良いことです。
もう1つの解決策は、Android GDEの 提案 by Hugo Visser)です。彼は、コードを追加して使用するためのライセンスフリークラスを作成しました。
使用法:
ItemClickSupport.addTo(mRecyclerView)
.setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// do it
}
});
(それはまた長い項目クリックを支えます)
実装(私が追加したコメント):
public class ItemClickSupport {
private final RecyclerView mRecyclerView;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
// ask the RecyclerView for the viewHolder of this view.
// then use it to get the position for the adapter
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
}
};
private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mOnItemLongClickListener != null) {
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
return false;
}
};
private RecyclerView.OnChildAttachStateChangeListener mAttachListener
= new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(View view) {
// every time a new child view is attached add click listeners to it
if (mOnItemClickListener != null) {
view.setOnClickListener(mOnClickListener);
}
if (mOnItemLongClickListener != null) {
view.setOnLongClickListener(mOnLongClickListener);
}
}
@Override
public void onChildViewDetachedFromWindow(View view) {
}
};
private ItemClickSupport(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
// the ID must be declared in XML, used to avoid
// replacing the ItemClickSupport without removing
// the old one from the RecyclerView
mRecyclerView.setTag(R.id.item_click_support, this);
mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}
public static ItemClickSupport addTo(RecyclerView view) {
// if there's already an ItemClickSupport attached
// to this RecyclerView do not replace it, use it
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support == null) {
support = new ItemClickSupport(view);
}
return support;
}
public static ItemClickSupport removeFrom(RecyclerView view) {
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support != null) {
support.detach(view);
}
return support;
}
public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
mOnItemClickListener = listener;
return this;
}
public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
mOnItemLongClickListener = listener;
return this;
}
private void detach(RecyclerView view) {
view.removeOnChildAttachStateChangeListener(mAttachListener);
view.setTag(R.id.item_click_support, null);
}
public interface OnItemClickListener {
void onItemClicked(RecyclerView recyclerView, int position, View v);
}
public interface OnItemLongClickListener {
boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
}
}
また、ファイルvalues/ids.xml
を作成して、その中に置きます。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="item_click_support" type="id" />
</resources>
このクラスは、RecyclerView
にRecyclerView.OnChildAttachStateChangeListener
を添付することによって機能します。このリスナーは、子がRecyclerView
からアタッチまたはデタッチされるたびに通知されます。コードはこれを使ってタップ/ロングクリックリスナーをビューに追加します。そのリスナーは、位置を含むRecyclerView.ViewHolder
をRecyclerView
に要求します。
さらに必要な場合は、コードを修正して所有者自身を元に戻すこともできます。
他の回答で提案されているように、リストの各ビューにクリックリスナーを設定してアダプタで処理しても問題ありません。これは最も効率的な方法ではありません(ビューを再利用するたびに新しいリスナーを作成する)が、うまく機能します。ほとんどの場合、それは問題にはなりません。
なぜRecyclerView
にはonItemClickListener
がありません。
RecyclerView
はツールボックスですが、古いListView
は機能があまり組み込まれておらず、より柔軟です。 onItemClickListener
は、ListViewから削除される唯一の機能ではありません。しかし、それはあなたの好みに合わせてそれを拡張するためのたくさんのリスナーと方法を持っています。
私の意見では、RecyclerView
で削除された最も複雑な機能はFast Scrollです。他のほとんどの機能は簡単に再実装できます。
私はこのように好きです、そして私はそれを使っています
内部
public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
プット
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_image_and_text, parent, false);
v.setOnClickListener(new MyOnClickListener());
そしてこのクラスを好きな場所に作成してください
class MyOnClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
int itemPosition = recyclerView.indexOfChild(v);
Log.e("Clicked and Position is ",String.valueOf(itemPosition));
}
}
もっと良い方法があると以前に読んだことがありますが、この方法は簡単で複雑ではないことが好きです。
Android Recyclerview onItemClickListener
では、なぜこれを試すことができないのかはListView
のみのように機能します。
ソース: リンク
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
private OnItemClickListener mListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
}
@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.getChildAdapterPosition(childView));
}
return false;
}
@Override
public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
そしてこれをRecyclerViewに設定します。
recyclerView = (RecyclerView)rootView. findViewById(R.id.recyclerView);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
// TODO Handle item click
Log.e("@@@@@",""+position);
}
})
);
@marmorのおかげで、私は自分の答えを更新しました。
ViewHolder classコンストラクタでonClick()を処理し、それを OnItemClickListener インタフェースを介して親クラスに渡すのが良い解決策だと思います。
MyAdapter.Java
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
private LayoutInflater layoutInflater;
private List<MyObject> items;
private AdapterView.OnItemClickListener onItemClickListener;
public MyAdapter(Context context, AdapterView.OnItemClickListener onItemClickListener, List<MyObject> items) {
layoutInflater = LayoutInflater.from(context);
this.items = items;
this.onItemClickListener = onItemClickListener;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.my_row_layout, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
MyObject item = items.get(position);
}
public MyObject getItem(int position) {
return items.get(position);
}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView title;
private ImageView avatar;
public ViewHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
avatar = itemView.findViewById(R.id.avatar);
title.setOnClickListener(this);
avatar.setOnClickListener(this);
itemView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
//passing the clicked position to the parent class
onItemClickListener.onItemClick(null, view, getAdapterPosition(), view.getId());
}
}
}
他のクラスでのアダプタの使用法
MyFragment.Java
public class MyFragment extends Fragment implements AdapterView.OnItemClickListener {
private RecyclerView recycleview;
private MyAdapter adapter;
.
.
.
private void init(Context context) {
//passing this fragment as OnItemClickListener to the adapter
adapter = new MyAdapter(context, this, items);
recycleview.setAdapter(adapter);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//you can get the clicked item from the adapter using its position
MyObject item = adapter.getItem(position);
//you can also find out which view was clicked
switch (view.getId()) {
case R.id.title:
//title view was clicked
break;
case R.id.avatar:
//avatar view was clicked
break;
default:
//the whole row was clicked
}
}
}
みんながこのコードをあなたの主な活動に使っています。非常に効率的な方法
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.users_list);
UsersAdapter adapter = new UsersAdapter(users, this);
recyclerView.setAdapter(adapter);
adapter.setOnCardClickListner(this);
これがあなたのAdapterクラスです。
public class UsersAdapter extends RecyclerView.Adapter<UsersAdapter.UserViewHolder> {
private ArrayList<User> mDataSet;
OnCardClickListner onCardClickListner;
public UsersAdapter(ArrayList<User> mDataSet) {
this.mDataSet = mDataSet;
}
@Override
public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.user_row_layout, parent, false);
UserViewHolder userViewHolder = new UserViewHolder(v);
return userViewHolder;
}
@Override
public void onBindViewHolder(UserViewHolder holder, final int position) {
holder.name_entry.setText(mDataSet.get(position).getUser_name());
holder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onCardClickListner.OnCardClicked(v, position);
}
});
}
@Override
public int getItemCount() {
return mDataSet.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
public static class UserViewHolder extends RecyclerView.ViewHolder {
CardView cardView;
TextView name_entry;
public UserViewHolder(View itemView) {
super(itemView);
cardView = (CardView) itemView.findViewById(R.id.user_layout);
name_entry = (TextView) itemView.findViewById(R.id.name_entry);
}
}
public interface OnCardClickListner {
void OnCardClicked(View view, int position);
}
public void setOnCardClickListner(OnCardClickListner onCardClickListner) {
this.onCardClickListner = onCardClickListner;
}
}
この後は、あなたの活動の中でこのオーバーライドメソッドを取得します。
@Override
public void OnCardClicked(View view, int position) {
Log.d("OnClick", "Card Position" + position);
}
> RecyclerViewはListviewとどう違うのですか?
1つの違いは、RecyclerViewにはLayoutManager
クラスがあり、それによってRecyclerView
を管理できることです。
水平方向 または
LinearLayoutManager
による垂直方向のスクロール
GridLayoutManager
によるGridLayout
StaggeredGridLayoutManager
でGridLayoutをずらす
RecyclerView-の水平スクロールのように
LinearLayoutManager llm = new LinearLayoutManager(context);
llm.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(llm);
すべてをまとめる方法の例...
public class OrderListCursorAdapter extends CursorRecyclerViewAdapter<OrderListCursorAdapter.ViewHolder> {
private static final String TAG = OrderListCursorAdapter.class.getSimpleName();
private static final int ID_VIEW_HOLDER_ACTUAL = 0;
private static final int ID_VIEW_HOLDER = 1;
public OrderListCursorAdapter(Context context, Cursor cursor) {
super(context, cursor);
}
public static class ViewHolderActual extends ViewHolder {
private static final String TAG = ViewHolderActual.class.getSimpleName();
protected IViewHolderClick listener;
protected Button button;
public ViewHolderActual(View v, IViewHolderClick listener) {
super(v, listener);
this.listener = listener;
button = (Button) v.findViewById(R.id.orderList_item_button);
button.setOnClickListener(this);
}
public void initFromData(OrderData data) {
Log.d(TAG, "><initFromData(data=" + data + ")");
orderId = data.getId();
vAddressStart.setText(data.getAddressStart());
vAddressEnd.setText(data.getAddressEnd());
}
@Override
public void onClick(View view) {
if (view instanceof Button) {
listener.onButtonClick((Button) view, getPosition(), this);
} else {
super.onClick(view);
}
}
public interface IViewHolderClick extends ViewHolder.IViewHolderClick {
public void onButtonClick(Button button, int position, ViewHolder viewHolder);
}
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private static final String TAG = ViewHolder.class.getSimpleName();
protected long orderId;
protected IViewHolderClick listener;
protected TextView vAddressStart;
protected TextView vAddressEnd;
protected TextView vStatus;
public ViewHolder(View v, IViewHolderClick listener) {
super(v);
this.listener = listener;
v.setOnClickListener(this);
vAddressStart = (TextView) v.findViewById(R.id.addressStart);
vAddressEnd = (TextView) v.findViewById(R.id.addressEnd);
vStatus = (TextView) v.findViewById(R.id.status);
}
public void initFromData(OrderData data) {
Log.d(TAG, "><initFromData(data=" + data + ")");
orderId = data.getId();
vAddressStart.setText(data.getAddressStart());
vAddressEnd.setText(data.getAddressEnd());
}
public long getOrderId() {
return orderId;
}
@Override
public void onClick(View view) {
listener.onCardClick(view, getPosition(), this);
}
public interface IViewHolderClick {
public void onCardClick(View view, int position, ViewHolder viewHolder);
}
}
@Override
public int getItemViewType(int position) {
return position == 0 ? ID_VIEW_HOLDER_ACTUAL : ID_VIEW_HOLDER;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.d(TAG, ">>onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")");
ViewHolder result;
switch (viewType) {
case ID_VIEW_HOLDER_ACTUAL: {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout_actual, parent, false);
result = new ViewHolderActual(itemView, new ViewHolderActual.IViewHolderClick() {
@Override
public void onCardClick(View view, int position, ViewHolder viewHolder) {
Log.d(TAG, "><onCardClick(view=" + view + ", position=" + position + ", viewHolder=" + viewHolder + ")");
Intent intent = new Intent(view.getContext(), OrderDetailActivity.class);
intent.putExtra(OrderDetailActivity.ARG_ORDER_ID, viewHolder.getOrderId());
view.getContext().startActivity(intent);
}
@Override
public void onButtonClick(Button button, int position, ViewHolder viewHolder) {
Log.d(TAG, "><onButtonClick(button=" + button + ", position=" + position + ", viewHolder=" + viewHolder + ")");
Intent intent = new Intent(button.getContext(), OrderMapActivity.class);
intent.putExtra(OrderMapActivity.ARG_ORDER_ID, viewHolder.getOrderId());
button.getContext().startActivity(intent);
}
});
break;
}
case ID_VIEW_HOLDER:
default: {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout, parent, false);
result = new ViewHolder(itemView, new ViewHolder.IViewHolderClick() {
@Override
public void onCardClick(View view, int position, ViewHolder viewHolder) {
Log.d(TAG, "><onCardClick(view=" + view + ", position=" + position + ", viewHolder=" + viewHolder + ")");
Intent intent = new Intent(view.getContext(), OrderDetailActivity.class);
intent.putExtra(OrderDetailActivity.ARG_ORDER_ID, viewHolder.getOrderId());
view.getContext().startActivity(intent);
}
});
break;
}
}
Log.d(TAG, "<<onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")= " + result);
return result;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, Cursor cursor) {
Log.d(TAG, "><onBindViewHolder(viewHolder=" + viewHolder + ", cursor=" + cursor + ")");
final OrderData orderData = new OrderData(cursor);
viewHolder.initFromData(orderData);
}
}
フォローアップ MLProgrammer-CiMの優れたRxJavaソリューション
Consumer<String> mClickConsumer = new Consumer<String>() {
@Override
public void accept(@NonNull String element) throws Exception {
Toast.makeText(getApplicationContext(), element +" was clicked", Toast.LENGTH_LONG).show();
}
};
ReactiveAdapter rxAdapter = new ReactiveAdapter();
rxAdapter.getPositionClicks().subscribe(mClickConsumer);
元の tl; dr を変更します。
public Observable<String> getPositionClicks(){
return onClickSubject;
}
PublishSubject#asObservable()
が削除されました。 PublishSubject
であるObservable
を返すだけです。
MLProgrammer-CiM answerを理解する限り、単にこれを実行することが可能です。
class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private ImageView image;
private TextView title;
private TextView price;
public MyViewHolder(View itemView) {
super(itemView);
image = (ImageView)itemView.findViewById(R.id.horizontal_list_image);
title = (TextView)itemView.findViewById(R.id.horizontal_list_title);
price = (TextView)itemView.findViewById(R.id.horizontal_list_price);
image.setOnClickListener(this);
title.setOnClickListener(this);
price.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Toast.makeText(context, "Item click nr: "+getLayoutPosition(), Toast.LENGTH_SHORT).show();
}
}
私はこのようにしました、それはとても単純です:
1行を追加 / クリックしたRecyclerViewポジション :
int position = getLayoutPosition()
ViewHolder classのフルコード
private class ChildViewHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public TextView txtView;
public ChildViewHolder(View itemView) {
super(itemView);
imageView= (ImageView)itemView.findViewById(R.id.imageView);
txtView= (TextView) itemView.findViewById(R.id.txtView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.i("RecyclerView Item Click Position", String.valueOf(getLayoutPosition()));
}
});
}
}
これがお役に立てば幸いです。
@ MLProgrammer-CiM の答えを読んだ後、これが私のコードです。
class NormalViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
@Bind(R.id.card_item_normal)
CardView cardView;
public NormalViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
cardView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v instanceof CardView) {
// use getAdapterPosition() instead of getLayoutPosition()
int itemPosition = getAdapterPosition();
removeItem(itemPosition);
}
}
}
RecyclerViewからインテントを開始するためにこのメソッドを使います。
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
final MyClass myClass = mList.get(i);
viewHolder.txtViewTitle.setText(myclass.name);
...
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v){
Intent detailIntent = new Intent(mContext, type.class);
detailIntent.putExtra("MyClass", myclass);
mContext.startActivity(detailIntent);
}
}
);
あなたがPOJOのリストを持っていて、アダプタの外側からクリックでそれを検索したいならば、これはそれを非常に簡単に実装する方法です。
アダプタで、クリックイベントのリスナとそれを設定するメソッドを作成します。
public class MyAdapter extends RecyclerView.Adapter<SitesListAdapter.ViewHolder> {
...
private List<MyPojo> mMyPojos;
private static OnItemClickListener mOnItemClickListener;
...
public interface OnItemClickListener {
public void onItemClick(MyPojo pojo);
}
...
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
mOnItemClickListener = onItemClickListener;
}
...
}
あなたのViewHolderで、onClickListenerを実装して、ビューが提示しているPOJOを一時的に格納するクラスメンバーを作成します(これは例です、セッターを作成することはより良いでしょう):
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public MyPojo mCurrentPojo;
...
public ViewHolder(View view) {
super(v);
...
view.setOnClickListener(this); //You could set this on part of the layout too
}
...
@Override
public void onClick(View view) {
if(mOnItemClickListener != null && mCurrentPojo != null){
mOnItemClickListener.onItemClick(mCurrentPojo);
}
}
アダプタに戻り、ViewHolderがバインドされているときに現在のPOJOを設定します(現在のビューに1つもない場合はnullに設定します)。
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final MyPojo currentPojo = mMyPojos.get(position);
holder.mCurrentPojo = currentPojo;
...
これで終わりです。これで、フラグメント/アクティビティから次のように使用できます。
mMyAdapter.setOnItemClickListener(new mMyAdapter.OnItemClickListener() {
@Override
public void onItemClick(MyPojo pojo) {
//Do whatever you want with your pojo here
}
});
RecyclerViewは ビューのリサイクル を担当するのでRecyclerViewにはonItemClickListener
はありません。したがって、受け取ったクリックイベントを処理するためにリサイクルされるのはビューの責任です。
複数の場所でクリックできるアイテムがある場合は特に、これは実際にははるかに使いやすくなります。
とにかく、RecyclerView項目のクリックを検出することは非常に簡単です。あなたがする必要があるのはインターフェースを定義することです(あなたがKotlinを使用していないなら、その場合あなたはただラムダを渡す):
public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
private final Clicks clicks;
public MyAdapter(Clicks clicks) {
this.clicks = clicks;
}
private List<MyObject> items = Collections.emptyList();
public void updateData(List<MyObject> items) {
this.items = items;
notifyDataSetChanged(); // TODO: use ListAdapter for diffing instead if you need animations
}
public interface Clicks {
void onItemSelected(MyObject myObject, int position);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private MyObject myObject;
public MyViewHolder(View view) {
super(view);
// bind views
view.setOnClickListener((v) -> {
int adapterPosition = getAdapterPosition();
if(adapterPosition >= 0) {
clicks.onItemSelected(myObject, adapterPosition);
}
});
}
public void bind(MyObject myObject) {
this.myObject = myObject;
// bind data to views
}
}
}
コトリンで同じコード:
class MyAdapter(val itemClicks: (MyObject, Int) -> Unit): RecyclerView.Adapter<MyViewHolder>() {
private var items: List<MyObject> = Collections.emptyList()
fun updateData(items: List<MyObject>) {
this.items = items
notifyDataSetChanged() // TODO: use ListAdapter for diffing instead if you need animations
}
inner class MyViewHolder(val myView: View): RecyclerView.ViewHolder(myView) {
private lateinit var myObject: MyObject
init {
// binds views
myView.onClick {
val adapterPosition = getAdapterPosition()
if(adapterPosition >= 0) {
itemClicks.invoke(myObject, adapterPosition)
}
}
}
fun bind(myObject: MyObject) {
this.myObject = myObject
// bind data to views
}
}
}
これに対する私のアプローチを見てください。
最初に次のようなインタフェースを宣言します。
/**
* Interface used for delegating item click events in a {@link Android.support.v7.widget.RecyclerView}
* Created by Alex on 11/28/2015.
*/
public interface OnRecyclerItemClickListener<T> {
/**
* Called when a click occurred inside a recyclerView item view
* @param view that was clicked
* @param position of the clicked view
* @param item the concrete data that is displayed through the clicked view
*/
void onItemClick(View view, int position, T item);
}
次にアダプタを作成します。
public class CustomRecyclerAdapter extends RecyclerView.Adapter {
private class InternalClickListener implements View.OnClickListener{
@Override
public void onClick(View v) {
if(mRecyclerView != null && mItemClickListener != null){
// find the position of the item that was clicked
int position = mRecyclerView.getChildAdapterPosition(v);
Data data = getItem(position);
// notify the main listener
mItemClickListener.onItemClick(v, position, data);
}
}
}
private final OnRecyclerItemClickListener mItemClickListener;
private RecyclerView mRecyclerView;
private InternalClickListener mInternalClickListener;
/**
*
* @param itemClickListener used to trigger an item click event
*/
public PlayerListRecyclerAdapter(OnRecyclerItemClickListener itemClickListener){
mItemClickListener = itemClickListener;
mInternalClickListener = new InternalClickListener();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);
v.setOnClickListener(mInternalClickListener);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
// do your binding here
}
@Override
public int getItemCount() {
return mDataSet.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
mRecyclerView = recyclerView;
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
mRecyclerView = null;
}
public Data getItem(int position){
return mDataset.get(position);
}
}
そして今、フラグメントからこれを統合する方法を見てみましょう:
public class TestFragment extends Fragment implements OnRecyclerItemClickListener<Data>{
private RecyclerView mRecyclerView;
@Override
public void onItemClick(View view, int position, Data item) {
// do something
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.test_fragment, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mRecyclerView = view.findViewById(idOfTheRecycler);
mRecyclerView .setAdapter(new CustomRecyclerAdapter(this));
}
私が適切な方法ですべてのものを実装したこの1つをチェックしてください
RecyclerViewHolderクラス
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
//view holder is for girdview as we used in the listView
public ImageView imageView,imageView2;
public RecyclerViewHolder(View itemView) {
super(itemView);
this.imageView=(ImageView)itemView.findViewById(R.id.image);
}
}
アダプタ
public class RecyclerView_Adapter extends RecyclerView.Adapter<RecyclerViewHolder> {
//RecyclerView will extend to recayclerview Adapter
private ArrayList<ModelClass> arrayList;
private Context context;
private static RecyclerViewClickListener itemListener;
//constructor of the RecyclerView Adapter
RecyclerView_Adapter(Context context,ArrayList<ModelClass> arrayList,RecyclerViewClickListener itemListener){
this.context=context;
this.arrayList=arrayList;
this.itemListener=itemListener;
}
@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//this method will inflate the custom layout and return as viewHolder
LayoutInflater layoutInflater=LayoutInflater.from(parent.getContext());
ViewGroup mainGroup=(ViewGroup) layoutInflater.inflate(R.layout.single_item,parent,false);
RecyclerViewHolder listHolder=new RecyclerViewHolder(mainGroup);
return listHolder;
}
@Override
public void onBindViewHolder(RecyclerViewHolder holder, final int position) {
final ModelClass modelClass=arrayList.get(position);
//holder
RecyclerViewHolder mainHolder=(RecyclerViewHolder)holder;
//convert the drawable image into bitmap
Bitmap image= BitmapFactory.decodeResource(context.getResources(),modelClass.getImage());
//set the image into imageView
mainHolder.imageView.setImageBitmap(image);
//to handle on click event when clicked on the recyclerview item and
// get it through the RecyclerViewHolder class we have defined the views there
mainHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//get the position of the image which is clicked
itemListener.recyclerViewListClicked(v,position);
}
});
}
@Override
public int getItemCount() {
return (null!=arrayList?arrayList.size():0);
}
}
インターフェース
public interface RecyclerViewClickListener {
//this is method to handle the event when clicked on the image in Recyclerview
public void recyclerViewListClicked(View v,int position);
}
//and to call this method in activity
RecyclerView_Adapter adapter=new RecyclerView_Adapter(Wallpaper.this,arrayList,this);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
@Override
public void recyclerViewListClicked(View v,int position){
imageView.setImageResource(wallpaperImages[position]);
}
私のコメントを修正しました...
public class MyViewHolder extends RecyclerView.ViewHolder {
private Context mContext;
public MyViewHolder(View itemView) {
super(itemView);
mContext = itemView.getContext();
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int itemPosition = getLayoutPosition();
Toast.makeText(mContext, "" + itemPosition, Toast.LENGTH_SHORT).show();
}
});
}
ここであなたは複数のonclick以下のコードを見て処理することができます、そしてそれは非常に効率的です。
public class RVNewsAdapter extends RecyclerView.Adapter<RVNewsAdapter.FeedHolder> {
private Context context;
List<News> newsList;
// Allows to remember the last item shown on screen
private int lastPosition = -1;
public RVNewsAdapter(List<News> newsList, Context context) {
this.newsList = newsList;
this.context = context;
}
public static class FeedHolder extends RecyclerView.ViewHolder implements OnClickListener {
ImageView img_main;
TextView tv_title;
Button bt_facebook, bt_Twitter, bt_share, bt_comment;
public FeedHolder(View itemView) {
super(itemView);
img_main = (ImageView) itemView.findViewById(R.id.img_main);
tv_title = (TextView) itemView.findViewById(R.id.tv_title);
bt_facebook = (Button) itemView.findViewById(R.id.bt_facebook);
bt_Twitter = (Button) itemView.findViewById(R.id.bt_Twitter);
bt_share = (Button) itemView.findViewById(R.id.bt_share);
bt_comment = (Button) itemView.findViewById(R.id.bt_comment);
img_main.setOnClickListener(this);
bt_facebook.setOnClickListener(this);
bt_Twitter.setOnClickListener(this);
bt_comment.setOnClickListener(this);
bt_share.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == bt_comment.getId()) {
Toast.makeText(v.getContext(), "Comment " , Toast.LENGTH_SHORT).show();
} else if (v.getId() == bt_facebook.getId()) {
Toast.makeText(v.getContext(), "Facebook " , Toast.LENGTH_SHORT).show();
} else if (v.getId() == bt_Twitter.getId()) {
Toast.makeText(v.getContext(), "Twitter " , Toast.LENGTH_SHORT).show();
} else if (v.getId() == bt_share.getId()) {
Toast.makeText(v.getContext(), "share " , Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(v.getContext(), "ROW PRESSED = " + String.valueOf(getAdapterPosition()), Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
@Override
public FeedHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.feed_row, parent, false);
FeedHolder feedHolder = new FeedHolder(view);
return feedHolder;
}
@Override
public void onBindViewHolder(FeedHolder holder, int position) {
holder.tv_title.setText(newsList.get(position).getTitle());
// Here you apply the animation when the view is bound
setAnimation(holder.img_main, position);
}
@Override
public int getItemCount() {
return newsList.size();
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position) {
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(context, Android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
}
あなたがアイテムの子ビューにonClick()を追加したいのであれば、例えば、アイテムの中のボタン、私はあなたがこれと同じようにあなた自身のRecyclerView.AdapterのonCreateViewHolder()でそれを簡単にすることができるということがわかりました
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater
.from(parent.getContext())
.inflate(R.layout.cell, null);
Button btn = (Button) v.findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do it
}
});
return new MyViewHolder(v);
}
それが良い方法かどうかはわかりませんが、うまくいきます。誰かがより良い考えを持っているならば、私に言い、私の答えを訂正して非常にうれしいです! :)
はい、できます
public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
//inflate the view
View view = LayoutInflator.from(parent.getContext()).inflate(R.layout.layoutID,null);
ViewHolder holder = new ViewHolder(view);
//here we can set onClicklistener
view.setOnClickListener(new View.OnClickListeener(){
public void onClick(View v)
{
//action
}
});
return holder;
rowLayout(cell)
のmainView
にアクセスしますRecyclerView
そしてOnBindViewHolder
に次のコードを書いてください:
@Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
Movie movie = moviesList.get(position);
holder.mainView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
System.out.println("pos " + position);
}
});
}
それは私のために働きました。それが役立つことを願っています。最も簡単な方法です。
インサイドビューホルダー
class GeneralViewHolder extends RecyclerView.ViewHolder {
View cachedView = null;
public GeneralViewHolder(View itemView) {
super(itemView);
cachedView = itemView;
}
内部OnBindViewHolder()
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final GeneralViewHolder generalViewHolder = (GeneralViewHolder) holder;
generalViewHolder.cachedView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "item Clicked at "+position, Toast.LENGTH_SHORT).show();
}
});
そして、教えてください、あなたはこの解決策について何か質問がありますか?
これは私のために働いた:
@Override
public void onBindViewHolder(PlacesListViewAdapter.ViewHolder holder, int position) {
----
----
----
// Set setOnClickListener(holder);
}
@Override
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
----
----
----
@Override
public void onClick(View view) {
// Use to get the item clicked getAdapterPosition()
}
}
main_recyclerview.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
{
int position=rv.getChildAdapterPosition(rv.findChildViewUnder(e.getX(),e.getY()));
switch (position)
{
case 0:
{
wifi(position);
adapter2.notifyDataSetChanged();
}
break;
case 1:
{
sound(position);
adapter2.notifyDataSetChanged();
}
break;
case 2:
{
bluetooth(position);
adapter2.notifyDataSetChanged();
}
break;
}
return true;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e)
{
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
Viewホルダー内にView.OnClickListenerインターフェースを実装するか、あなたの活動にインターフェースを作成して実装しインターフェースを実装する代わりに、OnClickListener実装の単純化のためにこのコードを使いました。
public static class SimpleStringRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> {
// Your initializations goes here...
private List<String> mValues;
public static class ViewHolder extends RecyclerView.ViewHolder {
//create a variable mView
public final View mView;
/*All your row widgets goes here
public final ImageView mImageView;
public final TextView mTextView;*/
public ViewHolder(View view) {
super(view);
//Initialize it here
mView = view;
/* your row widgets initializations goes here
mImageView = (ImageView) view.findViewById(R.id.avatar);
mTextView = (TextView) view.findViewById(Android.R.id.text1);*/
}
}
public String getValueAt(int position) {
return mValues.get(position);
}
public SimpleStringRecyclerViewAdapter(Context context, List<String> items) {
mBackground = mTypedValue.resourceId;
mValues = items;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
view.setBackgroundResource(mBackground);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mBoundString = mValues.get(position);
holder.mTextView.setText(mValues.get(position));
//Here it is simply write onItemClick listener here
holder.mView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
Intent intent = new Intent(context, ExampleActivity.class);
context.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return mValues.size();
}
}
recyclerviewアニメーションはテストされていません、他は正常です。私はそれが最大限に最適化されたと思います。インタフェースには他の用途があります、あなたは一時的に無視することができます。
public abstract class BaseAdapterRV<VH extends BaseViewHolder> extends RecyclerView.Adapter<VH> implements AdapterInterface {
public final String TAG = getClass().getSimpleName();
protected final Activity mActivity;
protected final LayoutInflater mInflater;
protected ItemClickInterface<?, Integer> mListener;
public BaseAdapterRV(Activity activity) {
mActivity = activity;
mInflater = LayoutInflater.from(mActivity);
}
@Override
public final VH onCreateViewHolder(ViewGroup parent, int viewType) {
return onCreateViewHolder(parent, viewType, mInflater);
}
@Override
public final void onBindViewHolder(VH holder, int position) {
holder.itemView.setTag(R.id.tag_view_click, position);
//创建点击事件
holder.itemView.setOnClickListener(mListener);
holder.itemView.setOnLongClickListener(mListener);
onBindVH(holder, position);
}
///////////////////////////////////////////////////////////////////////////
// 以下是增加的方法
///////////////////////////////////////////////////////////////////////////
/**
* 注意!涉及到notifyItemInserted刷新时立即获取position可能会不正确
* 里面也有onItemLongClick
*/
public void setOnItemClickListener(ItemClickInterface<?, Integer> listener) {
mListener = listener;
notifyDataSetChanged();
}
@NonNull
protected abstract VH onCreateViewHolder(ViewGroup parent, int viewType, LayoutInflater inflater);
protected abstract void onBindVH(VH holder, int position);
}
これはインターフェースです
/**
* OnItemClickListener的接口
* 见子类实现{@link OnItemClickListener}{@link OnItemItemClickListener}
*/
public interface ItemClickInterface<DATA1, DATA2> extends View.OnClickListener, View.OnLongClickListener {
void onItemClick(DATA1 data1, DATA2 data2);
boolean onItemLongClick(DATA1 data1, DATA2 data2);
}
これは抽象クラスです
public abstract class OnItemClickListener<DATA> implements ItemClickInterface<View, DATA> {
@Override
public void onClick(View v) {
onItemClick(v, (DATA) v.getTag(R.id.tag_view_click));
}
@Override
public boolean onLongClick(View v) {
return onItemLongClick(v, (DATA) v.getTag(R.id.tag_view_click));
}
@Override
public boolean onItemLongClick(View view, DATA data) {
return false;
}
}
必要なだけ
mAdapter.setOnItemClickListener(new OnItemClickListener<Integer>() {
@Override
public void onItemClick(View view, Integer integer) {
}
@Override
public boolean onItemLongClick(View view, Integer integer) {
return true;
}
});
@Layout(R.layout.item_view_1)
public class View1{
@View(R.id.txt)
public TextView txt;
@Resolve
public void onResolved() {
txt.setText(String.valueOf(System.currentTimeMillis() / 1000));
}
@Click(R.id.btn)
public void onClick(){
txt.setText(String.valueOf(System.currentTimeMillis() / 1000));
}
}
私はAndroidのリサイクラーのビューアイテムのクリックイベントを処理するためのライブラリを書きました。チュートリアル全体は https://github.com/ChathuraHettiarachchi/RecycleClick にあります。
RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// YOUR CODE
}
});
またはあなたが使用できるアイテムの長押しを処理するために
RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemLongClickListener(new RecycleClick.OnItemLongClickListener() {
@Override
public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) {
// YOUR CODE
return true;
}
});