如何从 ListView 中获取项目而不使用 Android 中的回收视图?
How do I get an item from a ListView to not use a recycled view in Android?
我目前有一个 buttons_row 有条件地显示在我的 item_exercise.xml 中:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_exercise"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="?android:attr/listPreferredItemHeight"
>
<RelativeLayout
android:id="@+id/text_row"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:id="@+id/exercise_name_value"
style="@style/h5"
android:text="@string/no_exercise"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:gravity="center_vertical"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/item_nav_image"
/>
<ImageView
android:id="@+id/item_nav_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginEnd="12dp"
android:src="@drawable/ic_action_expand"
android:contentDescription="@string/nav_expand_collapse"
android:layout_centerVertical="true"
/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/buttons_row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/text_row"
android:visibility="gone"
>
<ImageButton
android:id="@+id/exercise_rename_btn"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:src="@drawable/ic_action_mic"
android:contentDescription="@string/rename"
android:layout_marginStart="10dp"
/>
<ImageButton
android:id="@+id/exercise_delete_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_action_discard"
android:contentDescription="@string/delete"
android:layout_alignParentEnd="true"
/>
</RelativeLayout>
</RelativeLayout>
我正在使用 ViewHolder 模式,当我从列表中删除练习时 运行 遇到问题,因为回收视图(显示 buttons_row)被回收到另一个 item_exercise 物品。我想知道如何解决这个问题?
Adapter.java:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = View.inflate(mContext, R.layout.item_exercise, null);
holder = new ViewHolder();
holder.rithmId = 0;
holder.exerciseName = (TextView) convertView.findViewById(R.id.exercise_name_value);
holder.renameButton = (ImageButton) convertView.findViewById(R.id.exercise_rename_btn);
holder.deleteButton = (ImageButton) convertView.findViewById(R.id.exercise_delete_btn);
holder.buttonsRow = (RelativeLayout) convertView.findViewById(R.id.buttons_row);
holder.navImage = (ImageView) convertView.findViewById(R.id.item_nav_image);
holder.navShown = EXPAND;
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final BaseAdapter baseAdapter = this;
final ActiveRithm rithm = (ActiveRithm) getItem(position);
holder.rithmId = rithm.getRithmID();
holder.exerciseName.setText(rithm.getName());
holder.displayNavCorrectly();
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.toggleNav();
}
});
holder.deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//brings up confirmation dialog to delete this exercise/rithm
}
});
return convertView;
}
static class ViewHolder {
public int rithmId;
public TextView exerciseName;
public ImageButton renameButton;
public ImageButton deleteButton;
public String navShown;
public RelativeLayout buttonsRow;
public ImageView navImage;
public void toggleNav() {
Log.d(TAG, "navShown: " + navShown);
if (navShown != null && navShown.equals(EXPAND)) {
// display buttons
buttonsRow.setVisibility(View.VISIBLE);
// change image to be collapse
navImage.setImageResource(R.drawable.ic_action_collapse);
navShown = COLLAPSE;
} else {
// hide buttons
buttonsRow.setVisibility(View.GONE);
// change the image to be expand
navImage.setImageResource(R.drawable.ic_action_expand);
navShown = EXPAND;
}
}
/**
* Sometimes when you delete a rithm, the holder does not display the correct navigation
* This method makes sure that recycled views are being displayed correctly.
*/
public void displayNavCorrectly() {
Log.d(TAG, "displayNavCorrectly: " + navShown);
if (navShown != null && navShown.equals(EXPAND)) {
// Hide buttons and image should be expand
buttonsRow.setVisibility(View.GONE);
navImage.setImageResource(R.drawable.ic_action_expand);
} else {
buttonsRow.setVisibility(View.VISIBLE);
navImage.setImageResource(R.drawable.ic_action_collapse);
}
}
}
我以为我的 displayNavCorrectly() 方法可以解决问题,但事实并非如此。我是否需要将 UI 的 'state' 存储在我的对象中?或者有更好的方法吗?
最简单的方法是废弃回收视图并每次都膨胀一个新视图。但这对性能不利。
总的来说,holder 模式用于避免在视图相同时调用 findViewById 来查找视图。所以你不应该在你的持有人中有 rithmId 和 navShown。
之后您应该设置视图的状态。如果按钮行的可见性可以更改,则可以为每个视图设置它。在您的情况下,您似乎希望隐藏或显示按钮。所以你的数据(在你的情况下是 ActiveRithm)应该记住这一点,而不是你的持有者。
所以当你得到你的对象时,用它来设置当前视图的当前状态
final ActiveRithm rithm = (ActiveRithm) getItem(position);
if (rithm.showingButtons) {
holder.buttonsRow.setVisibility(View.VISIBLE);
} else {
holder.buttonsRow.setVisibility(View.GONE);
}
然后在您的点击中不要操纵持有人,而是操纵持有人的视图和您的数据状态。
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
rithm.showingButtons = !rithm.showingButtons;
if (rithm.showingButtons) {
holder.buttonsRow.setVisibility(View.VISIBLE);
} else {
holder.buttonsRow.setVisibility(View.GONE);
}
}
});
我目前有一个 buttons_row 有条件地显示在我的 item_exercise.xml 中:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_exercise"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="?android:attr/listPreferredItemHeight"
>
<RelativeLayout
android:id="@+id/text_row"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:id="@+id/exercise_name_value"
style="@style/h5"
android:text="@string/no_exercise"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:gravity="center_vertical"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/item_nav_image"
/>
<ImageView
android:id="@+id/item_nav_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginEnd="12dp"
android:src="@drawable/ic_action_expand"
android:contentDescription="@string/nav_expand_collapse"
android:layout_centerVertical="true"
/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/buttons_row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/text_row"
android:visibility="gone"
>
<ImageButton
android:id="@+id/exercise_rename_btn"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:src="@drawable/ic_action_mic"
android:contentDescription="@string/rename"
android:layout_marginStart="10dp"
/>
<ImageButton
android:id="@+id/exercise_delete_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_action_discard"
android:contentDescription="@string/delete"
android:layout_alignParentEnd="true"
/>
</RelativeLayout>
</RelativeLayout>
我正在使用 ViewHolder 模式,当我从列表中删除练习时 运行 遇到问题,因为回收视图(显示 buttons_row)被回收到另一个 item_exercise 物品。我想知道如何解决这个问题?
Adapter.java:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if (convertView == null) {
convertView = View.inflate(mContext, R.layout.item_exercise, null);
holder = new ViewHolder();
holder.rithmId = 0;
holder.exerciseName = (TextView) convertView.findViewById(R.id.exercise_name_value);
holder.renameButton = (ImageButton) convertView.findViewById(R.id.exercise_rename_btn);
holder.deleteButton = (ImageButton) convertView.findViewById(R.id.exercise_delete_btn);
holder.buttonsRow = (RelativeLayout) convertView.findViewById(R.id.buttons_row);
holder.navImage = (ImageView) convertView.findViewById(R.id.item_nav_image);
holder.navShown = EXPAND;
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final BaseAdapter baseAdapter = this;
final ActiveRithm rithm = (ActiveRithm) getItem(position);
holder.rithmId = rithm.getRithmID();
holder.exerciseName.setText(rithm.getName());
holder.displayNavCorrectly();
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.toggleNav();
}
});
holder.deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//brings up confirmation dialog to delete this exercise/rithm
}
});
return convertView;
}
static class ViewHolder {
public int rithmId;
public TextView exerciseName;
public ImageButton renameButton;
public ImageButton deleteButton;
public String navShown;
public RelativeLayout buttonsRow;
public ImageView navImage;
public void toggleNav() {
Log.d(TAG, "navShown: " + navShown);
if (navShown != null && navShown.equals(EXPAND)) {
// display buttons
buttonsRow.setVisibility(View.VISIBLE);
// change image to be collapse
navImage.setImageResource(R.drawable.ic_action_collapse);
navShown = COLLAPSE;
} else {
// hide buttons
buttonsRow.setVisibility(View.GONE);
// change the image to be expand
navImage.setImageResource(R.drawable.ic_action_expand);
navShown = EXPAND;
}
}
/**
* Sometimes when you delete a rithm, the holder does not display the correct navigation
* This method makes sure that recycled views are being displayed correctly.
*/
public void displayNavCorrectly() {
Log.d(TAG, "displayNavCorrectly: " + navShown);
if (navShown != null && navShown.equals(EXPAND)) {
// Hide buttons and image should be expand
buttonsRow.setVisibility(View.GONE);
navImage.setImageResource(R.drawable.ic_action_expand);
} else {
buttonsRow.setVisibility(View.VISIBLE);
navImage.setImageResource(R.drawable.ic_action_collapse);
}
}
}
我以为我的 displayNavCorrectly() 方法可以解决问题,但事实并非如此。我是否需要将 UI 的 'state' 存储在我的对象中?或者有更好的方法吗?
最简单的方法是废弃回收视图并每次都膨胀一个新视图。但这对性能不利。
总的来说,holder 模式用于避免在视图相同时调用 findViewById 来查找视图。所以你不应该在你的持有人中有 rithmId 和 navShown。
之后您应该设置视图的状态。如果按钮行的可见性可以更改,则可以为每个视图设置它。在您的情况下,您似乎希望隐藏或显示按钮。所以你的数据(在你的情况下是 ActiveRithm)应该记住这一点,而不是你的持有者。
所以当你得到你的对象时,用它来设置当前视图的当前状态
final ActiveRithm rithm = (ActiveRithm) getItem(position);
if (rithm.showingButtons) {
holder.buttonsRow.setVisibility(View.VISIBLE);
} else {
holder.buttonsRow.setVisibility(View.GONE);
}
然后在您的点击中不要操纵持有人,而是操纵持有人的视图和您的数据状态。
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
rithm.showingButtons = !rithm.showingButtons;
if (rithm.showingButtons) {
holder.buttonsRow.setVisibility(View.VISIBLE);
} else {
holder.buttonsRow.setVisibility(View.GONE);
}
}
});