ListView 中的 CardViews:卡片点击不执行点击监听器
CardViews in ListView: Card clicks not executing click listener
我正在实现 CardView 的 ListView。
但是,当我单击时,我可以看到正在单击的卡片,但不会执行侦听器。
所有卡片都正确呈现并点击,但没有执行侦听器功能。
Activity.java
final List<String> deviceStringList = new ArrayList<String>();
deviceStringList.add("Device 1");
deviceStringList.add("Device 2");
deviceStringList.add("Device 3");
deviceStringList.add("Device 4");
String[] deviceStringArray = deviceStringList.toArray(new String[deviceStringList.size()]);
DevicesListViewAdapter cardListAdapter = new DevicesListViewAdapter(this, deviceStringArray);
ListView deviceCardsListView = (ListView) findViewById(R.id.deviceCardsListView);
deviceCardsListView.setAdapter(cardListAdapter);
final List<String> finalDeviceList = deviceStringList;
deviceCardsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast toast = Toast.makeText(getApplicationContext(), finalDeviceList.get(position), Toast.LENGTH_LONG);
toast.show();
}
});
ListViewAdapter.java
public class DevicesListViewAdapter extends ArrayAdapter<String>
{
private final Activity context;
private final String[] deviceName;
public DevicesListViewAdapter(@NonNull Activity context, String[] deviceName) {
super(context, R.layout.device_card_layout, deviceName);
this.context = context;
this.deviceName = deviceName;
}
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View cardView = inflater.inflate(R.layout.device_card_layout, null, true);
Button cardBtn = (Button) cardView.findViewById(R.id.cardButton);
cardBtn.setText(deviceName[position]);
return cardView;
}
}
卡片视图布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingBottom="@dimen/cardview_default_elevation"
android:paddingLeft="@dimen/cardview_default_elevation"
android:paddingRight="@dimen/cardview_default_elevation"
android:paddingTop="@dimen/cardview_default_elevation"
android:clickable="true"
android:focusable="true"
android:foreground="?android:selectableItemBackground">
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="300dp"
card_view:cardCornerRadius="6dp"
android:layout_margin="10dp"
android:clickable="true"
android:focusable="true"
android:foreground="?android:selectableItemBackground">
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp">
<Button
android:id="@+id/cardButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:background="@drawable/add_device_btn"
android:text=""
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
我做错了什么?
谢谢。
解法:
删除这个:
deviceCardsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast toast = Toast.makeText(getApplicationContext(), finalDeviceList.get(position), Toast.LENGTH_LONG);
toast.show();
}
});
然后这样写:
cardBtn.setOnClickListener(...) {
onClick() {
Toast toast = Toast.makeText(getApplicationContext(), "" + position, Toast.LENGTH_LONG);
toast.show();
}
}
在您的适配器内部,如下所示:
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View cardView = inflater.inflate(R.layout.device_card_layout, null, true);
Button cardBtn = (Button) cardView.findViewById(R.id.cardButton);
cardBtn.setText(deviceName[position]);
.......(Write Here)
return cardView;
}
希望对您有所帮助。谢谢。
不要提供 onItemClickListener,而是尝试将单击侦听器提供给主 LinearLayout 或 CardView。 OnItemClick 不适用于可聚焦或具有可点击项目的列表视图。因此,为列表中的项目定义点击侦听器应该可以解决问题。
供大家参考
LinearLayout mainView = (LinearLayout) findViewById(R.id.id_of_LL);
mainView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast toast = Toast.makeText(getApplicationContext(), "" + position, Toast.LENGTH_LONG);
toast.show();
}
});
您是否尝试过为适配器中的每个视图注册您的 onClick 侦听器,然后通过接口与父 activity 通信?例如,在您的适配器中 class 创建一个接口
public interface CardListener {
void onSelected();
}
在您的适配器中,定义一个私有变量来存储要通过 setter 方法传入的接口实现的引用。类似于:
private CardListener listener;
在适配器中定义一个setter
public void setListener(CardListener listener) { this.listener = listener; }
然后在 getView 方法中绑定数据时执行以下操作
cardBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener != null) { listener.onSelected(); }
}
});
最后,在您的 activity 中,您可以像这样设置回调定义
adapter.setListener(new CardListener() {
@Override
public void onSelected() { // Do something here };
});
这将允许您定义许多自定义点击操作,以防您需要对卡片视图中的不同视图执行单独的点击操作。它还允许您来回传递任何适配器数据,并允许您以更加分隔的方式将适配器逻辑与 activity 逻辑分开。希望这有帮助。
有关更多信息,请查看此有用的资源:https://guides.codepath.com/android/Using-an-ArrayAdapter-with-ListView#attaching-event-handlers-within-adapter
android:clickable="true" 改为 android:clickable="false"
如果你使用 listview.setonclick 那么 cardview clickable 必须是 false
我正在实现 CardView 的 ListView。 但是,当我单击时,我可以看到正在单击的卡片,但不会执行侦听器。 所有卡片都正确呈现并点击,但没有执行侦听器功能。
Activity.java
final List<String> deviceStringList = new ArrayList<String>();
deviceStringList.add("Device 1");
deviceStringList.add("Device 2");
deviceStringList.add("Device 3");
deviceStringList.add("Device 4");
String[] deviceStringArray = deviceStringList.toArray(new String[deviceStringList.size()]);
DevicesListViewAdapter cardListAdapter = new DevicesListViewAdapter(this, deviceStringArray);
ListView deviceCardsListView = (ListView) findViewById(R.id.deviceCardsListView);
deviceCardsListView.setAdapter(cardListAdapter);
final List<String> finalDeviceList = deviceStringList;
deviceCardsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast toast = Toast.makeText(getApplicationContext(), finalDeviceList.get(position), Toast.LENGTH_LONG);
toast.show();
}
});
ListViewAdapter.java
public class DevicesListViewAdapter extends ArrayAdapter<String>
{
private final Activity context;
private final String[] deviceName;
public DevicesListViewAdapter(@NonNull Activity context, String[] deviceName) {
super(context, R.layout.device_card_layout, deviceName);
this.context = context;
this.deviceName = deviceName;
}
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View cardView = inflater.inflate(R.layout.device_card_layout, null, true);
Button cardBtn = (Button) cardView.findViewById(R.id.cardButton);
cardBtn.setText(deviceName[position]);
return cardView;
}
}
卡片视图布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingBottom="@dimen/cardview_default_elevation"
android:paddingLeft="@dimen/cardview_default_elevation"
android:paddingRight="@dimen/cardview_default_elevation"
android:paddingTop="@dimen/cardview_default_elevation"
android:clickable="true"
android:focusable="true"
android:foreground="?android:selectableItemBackground">
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="300dp"
card_view:cardCornerRadius="6dp"
android:layout_margin="10dp"
android:clickable="true"
android:focusable="true"
android:foreground="?android:selectableItemBackground">
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp">
<Button
android:id="@+id/cardButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:background="@drawable/add_device_btn"
android:text=""
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
我做错了什么? 谢谢。
解法:
删除这个:
deviceCardsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast toast = Toast.makeText(getApplicationContext(), finalDeviceList.get(position), Toast.LENGTH_LONG);
toast.show();
}
});
然后这样写:
cardBtn.setOnClickListener(...) {
onClick() {
Toast toast = Toast.makeText(getApplicationContext(), "" + position, Toast.LENGTH_LONG);
toast.show();
}
}
在您的适配器内部,如下所示:
public View getView(int position, View view, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View cardView = inflater.inflate(R.layout.device_card_layout, null, true);
Button cardBtn = (Button) cardView.findViewById(R.id.cardButton);
cardBtn.setText(deviceName[position]);
.......(Write Here)
return cardView;
}
希望对您有所帮助。谢谢。
不要提供 onItemClickListener,而是尝试将单击侦听器提供给主 LinearLayout 或 CardView。 OnItemClick 不适用于可聚焦或具有可点击项目的列表视图。因此,为列表中的项目定义点击侦听器应该可以解决问题。
供大家参考
LinearLayout mainView = (LinearLayout) findViewById(R.id.id_of_LL);
mainView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast toast = Toast.makeText(getApplicationContext(), "" + position, Toast.LENGTH_LONG);
toast.show();
}
});
您是否尝试过为适配器中的每个视图注册您的 onClick 侦听器,然后通过接口与父 activity 通信?例如,在您的适配器中 class 创建一个接口
public interface CardListener {
void onSelected();
}
在您的适配器中,定义一个私有变量来存储要通过 setter 方法传入的接口实现的引用。类似于:
private CardListener listener;
在适配器中定义一个setter
public void setListener(CardListener listener) { this.listener = listener; }
然后在 getView 方法中绑定数据时执行以下操作
cardBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener != null) { listener.onSelected(); }
}
});
最后,在您的 activity 中,您可以像这样设置回调定义
adapter.setListener(new CardListener() {
@Override
public void onSelected() { // Do something here };
});
这将允许您定义许多自定义点击操作,以防您需要对卡片视图中的不同视图执行单独的点击操作。它还允许您来回传递任何适配器数据,并允许您以更加分隔的方式将适配器逻辑与 activity 逻辑分开。希望这有帮助。
有关更多信息,请查看此有用的资源:https://guides.codepath.com/android/Using-an-ArrayAdapter-with-ListView#attaching-event-handlers-within-adapter
android:clickable="true" 改为 android:clickable="false"
如果你使用 listview.setonclick 那么 cardview clickable 必须是 false