ネストされたReyclerView(垂直方向の水平)を実装しましたが、CardView要素でラップされた行全体のクリックリスナーを追加することはできません。ネストされたRecyclerView onClickListenerが機能しない
問題は、内部RecyclerViewがすべてのタッチイベントをキャプチャし、ルートCardViewがonClickイベントに応答しないことです。
私はまた、CardViewがタッチイベントを傍受させようとしましたが、このアプローチではリップル効果(実際にはフィードバック)は機能しませんでした。
RecyclerViewを入れ子にした状態で行にクリックリスナーを実装する方法をお勧めしますか?
ありがとうございます。
--LE--
この現在の実装である:
断片レイアウト
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list"
android:name=".NestedRecyclerViewsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="LinearLayoutManager"
tools:context=".NestedRecyclerViewsFragment"
tools:listitem="@layout/fragment_nested_recyclerview_item"
/>
フラグメントonCreateView()実装
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_nested_recyclerview_list, container, false);
// Set the adapter
if (view instanceof RecyclerView) {
Context context = view.getContext();
RecyclerView recyclerView = (RecyclerView) view;
recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));
recyclerView.setHasFixedSize(true); // Improves performance - as we know the size doesn't change
//Initialize and set the adapter
mAdapter = new RootAdapter(context, mListener);
recyclerView.setAdapter(mAdapter);
final GestureDetector mGestureDetector =
new GestureDetector(view.getContext(), new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
//TODO: intercept simple gestures like onClick and/or onLongClick
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && mGestureDetector.onTouchEvent(e)) {
//TODO: handle the intercept??
child.callOnClick();
return true;
}
return super.onInterceptTouchEvent(rv, e);
}
});
recyclerView.setNestedScrollingEnabled(true);
}
return view;
}
**ルートアダプタレイアウト**
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="@dimen/row_height"
android:layout_gravity="center_horizontal"
android:layout_margin="@dimen/none"
android:padding="@dimen/none"
app:cardCornerRadius="@dimen/none"
tools:context=".NestedRecyclerViewActivity"
<!-- Simple selector for API < 21 and ripple effect for APi >= 21 -->
android:foreground="@drawable/selector_default"
android:clickable="true"
android:focusable="true"
>
<!-- Horizontal image gallery inside row item -->
<android.support.v7.widget.RecyclerView
android:id="@+id/child_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
...
</android.support.v7.widget.CardView>
ルートアダプタonBindView()の実装:
...
holder.childRecyclerView.setLayoutManager(new LinearLayoutManager(holder.mView.getContext(),
LinearLayoutManager.HORIZONTAL, false));
holder.childRecyclerView.setHasFixedSize(true); // We know the image don't change size
holder.childRecyclerView.setAdapter(new ChildAdapter(items));
...
ルートアダプタViewHolder実装:
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private ItemClickListener mClickListener;
/**
* The whole view - useful if you need to place some touch listener on the entire row.
*/
public final View mView;
/**
* The model associated with this view. - will be updated on bind method
*/
public Object mItem;
@Bind(R.id.child_recycler_view)
RecyclerView childRecyclerView;
...
public ViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
mView = view;
mView.setOnClickListener(this);
// Set the click listener bound to the fragment or activity
mClickListener = RootAdapter.this;
}
@Override
public void onClick(View v) {
if (null != mClickListener) {
mClickListener.onClick(v, getAdapterPosition());
}
}
}
内側RecyclerView (子供)は、リスナーが設定されていない非常にシンプルでスタンドアロンの実装です。
このソリューションは機能しますが、クリックイベントが発生し、内部のRecyclerViewスクロールが機能しますが、クリックのフィードバックが表示されないという問題が発生しました。
LE:私はこの問題を掲載するのでソリューション
私の要件はPagerAdapterで、内側RecyclerViewを交換すること、少し変更しましたが、私は実装ソリューションは、ネストされたRecyclerViewで動作するはずです。
基本的に私は、すぐに彼らが傍受されているとして、バック親にクリックイベントを渡しますカスタムItemClickSupportクラスを使用します。
/**
* Utility class which adds the ability to add Click Support for RecyclerViews without the need to implement click
* listeners into the adapter or in the ViewHolder's implementation.
* <p>
* Use it by simply binding an click listener to the desired RecyclerView.
* <pre><code>
* ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
* {@[email protected]}Override
* public void onItemClicked(RecyclerView recyclerView, int position, View v) {
* // Handle the clicked item
* }
* });
* </code></pre>
* </p>
* Based on <a href="http://www.littlerobots.nl/blog/Handle-Android-RecyclerView-Clicks/">Handle-Android-RecyclerView
* -Clicks</a>, <br/><b>Hugo Visser</b>. Which is very similar with the implementation from <a
* href="https://github.com/lucasr/twoway-view">TwoWay-View</a>.
* <p/>
* Created by ionut on 22.03.2016.
*/
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) {
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) {
if (mOnItemClickListener != null) {
view.setOnClickListener(mOnClickListener);
}
if (mOnItemLongClickListener != null) {
view.setOnLongClickListener(mOnLongClickListener);
}
}
@Override
public void onChildViewDetachedFromWindow(View view) {
}
};
private ItemClickSupport(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
mRecyclerView.setTag(R.id.item_click_support, this);
mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}
public static ItemClickSupport addTo(RecyclerView view) {
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);
void onItemClicked(int position);
}
public interface OnItemLongClickListener {
boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
}
public static class SimpleOnItemClickListener implements OnItemClickListener {
@Override
public void onItemClicked(int position) {
}
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
}
}
}
ルートアダプタを作成するとき、私はそれのためのアイテムをクリックリスナーを設定し、このような:
ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(this);
そして私はまた、このように、setterメソッドを介して内アダプタは、このリスナーを送信:
rootAdapter.setOnItemClickListener(this);
rootAdapter
はルートアダプタであり、this
は現在のフラグメントで、ItemClickSupportListener
を実装しています。ルートアダプタで
、アイテムを結合し、内部アダプタを作成するときに、私はこのように、内側のアダプタにアイテムのクリック支援リスナーに渡す:
innerAdapter.setOnItemClickListener(new ItemClickSupport.SimpleOnItemClickListener() {
@Override
public void onItemClicked(int position) {
// Here we pass the click to the parent provided click listener.
// We modify the position with the one of the ViewHolder so that we don't get the
// position of the horizontal RecyclerView adapter - we are interested on the
// vertical item actually.
if (null != mItemClickListener) {
mItemClickListener.onItemClicked(holder.getAdapterPosition());
}
}
});
mItemClickListener
が実際によって設定されたリスナーです上記のセッター法により断片化する。ビューを作成、私は私が膨張レイアウトのルートにクリックリスナを設定して、戻って私のカスタムクリックリスナーにそのイベントを渡す内側のアダプタでは、
:
// Detect the click events and pass them to any listeners
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (null != mOnItemClickListener) {
mOnItemClickListener.onItemClicked(position);
}
}
});
mOnItemClickListener
が実際にあります上記のアダプタで渡されたアイテムクリックサポート。
もう一つ重要なことは、このように、アダプタ項目ビューの内容のためでframeLayoutを使用することです:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:addStatesFromChildren="true"
android:foreground="@drawable/selector_default"
>
ここで重要なのは、セレクタとフラグandroid:addStatesFromChildren
を使用しますです。これはルートアダプター項目に設定されています。我々はまた、フォアグラウンド属性を使用して、それのセレクタを設定することができるように
内部アダプタ項目は、コンテンツビューとしてでframeLayoutを使用する必要があります。
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="@drawable/selector_default"
>
をこれが必要とされ、内側のアダプタ項目がキャプチャしますときので、クリックイベント、セレクタをアクティブにします。そうでない場合、親はclickイベントに反応し、セレクタをアクティブにする必要があります。
試みをクリックリスナーを設定してみてください。 – Irfan
子RecyclerViewはonBindViewHolder()メソッドで作成されるため、水平方向の各行項目に対してリスナーを作成する必要があります。 また、CardViewセレクタがもう動作しない問題を解決するとは思えません。 –
ここでonClickListenerを設定しますか? – Irfan