我有一个带有自定义适配器的自定义对象ListView
。单击列表中的单个项目将启动结果的新活动,以更新该项目,然后返回到列表,其中ListView
项目右侧的绿色勾选图像为TextView
,我只是用row.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.tick_green, 0)
但是当我向下滚动时,我看到另一行具有相同的drawable。来回滚动只是将这个drawable随机设置为不同的行。大多数答案都说它是因为视图正在被回收,但是当另一个活动返回结果时,无论是否可见,改变单行的方法是什么?
代码与列表视图 -
private ItemAdapter adapter;
private ArrayList<Item> labels;
private ArrayList<Item> updatedItems;
private TextView label;
@Override
protected void onCreate(Bundle savedInstanceState) {
// initializations
updatedItems = new ArrayList<>();
adapter = new ItemAdapter(getBaseContext(), R.layout.label_list_item, labels);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
label = (TextView) listView.getChildAt(position - listView.getFirstVisiblePosition()).findViewById(R.id.text1);
Item item = adapter.getItem(position);
Intent myIntent = new Intent(ProviderPutawayActivity.this, PutawayScanLocationActivity.class);
myIntent.putExtra("ITEM", item);
ProviderPutawayActivity.this.startActivityForResult(myIntent, 1);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == 1) {
Item item = (Item) data.getSerializableExtra("ITEM");
label.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.tick_green, 0);
}
建议here的{p> v.findViewById(r.id.text1)
和(TextView) listView.getChildAt(position - listView.getFirstVisiblePosition()).findViewById(R.id.text1)
都存在同样的问题。
ItemAdapter类 -
public class ItemAdapter extends ArrayAdapter<Item> {
private View v;
public ItemAdapter(Context context, int resource, List<Item> items) {
super(context, resource, items);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
v = convertView;
TextView label;
if(v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.label_list_item, null);
}
Item item = getItem(position);
if(item != null) {
label = (TextView)v.findViewById(R.id.text1);
if(label != null) label.setText(String.valueOf(item.getLabel()));
}
return v;
}
}
如何确保我只更新被点击的行?
答案 0 :(得分:1)
问题是,当视图被回收时,你永远不会取消设置 drawable。这与ViewHolder模式无关,它与更新项目的方式有关。您的getView()
方法应该具有以下内容:
int check = item.isChecked() ? R.drawable.tick_green : 0;
label.setCompountDrawablesWithIntrinsicBounds(0, 0, check, 0);
这是将项目数据绑定到行视图的正确方法。
您现在正在做的是将点击的行的一些视图保存到活动的成员字段中,并在到达onActivityResult()
时更新它们一次。问题是如果我滚动并向后滚动,没有任何标识实际检查哪个项目,并且适配器无法显示正确的状态。
应该正在做的是修改实际数据源(在这种情况下为Item
,或包含Item
s的结构),然后调用{{ 1}}在适配器上。这将导致notifyDatasetChanged()
重建其行,因此正确的绑定逻辑将负责显示正确的状态。
顺便说一下,切换到ListView
有很多好处(代价是更复杂一些)。首先,使用RecyclerView
,您可以通知单个项目已更改,因此它只会重建一行; RecyclerView.Adapter
s这是不可能的。另一方面,它会强制您使用视图,无论如何都要更高效。
答案 1 :(得分:0)
首先,您应该在项目中存储一个代表绿色勾号图像的变量(例如:boolean isSelected
)
然后,在onActivityResult
中,检查条件,更新isSelected
并重新加载listView
答案 2 :(得分:0)
我是#34;受害者&#34;对此视图也是回收机制!
你的问题
然而,当我向下滚动时,我看到另一行具有相同的drawable。来回滚动只会将此drawable随机设置为不同的行。
基本上是因为
listView with adapter tenses回收/重用不再可见的viewItem。
如果您需要detailed-explanation,请查看此答案。
对于您的情况,只需为您的 添加其他(当涉及到设置适配器的视图时):
if(label != null)
label.setText(String.valueOf(item.getLabel()));
else
label.setText("Default text");
希望这会有所帮助〜
答案 3 :(得分:0)
如上所述,无论何时需要更新listview或recyclerview中的项目行,都应该使用ififiyDataSetchange。所以,你去吧
首先,您必须在项目模型类中创建setter和getter方法以更新列表视图行。如下所示
public class Item {
private boolean mIsSelected;
public void setIsSelected(boolean isSelected) {
mIsSelected = isSelected;
}
public boolean isSelected() {
return mIsSelected;
}
}
然后在你的ItemAdapter类里面,getView()方法就是这样做的
@Override
public View getView(int position, View convertView, ViewGroup parent) {
v = convertView;
TextView label;
if(v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.label_list_item, null);
}
Item item = getItem(position);
if(item != null) {
label = (TextView)v.findViewById(R.id.text1);
label.setText(String.valueOf(item.getLabel()));
if (item.isSelected) {
label.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.tick_green, 0);
} else { // by default it will be false until you select an item here
label.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
}
}
return v;
}
然后在你的活动里面setOnItemClickListener更新你的项目模型类,如下所示
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
Item item = adapter.getItem(position);
item.setIsSelected(true);
Intent myIntent = new Intent(ProviderPutawayActivity.this, PutawayScanLocationActivity.class);
myIntent.putExtra("ITEM", item);
ProviderPutawayActivity.this.startActivityForResult(myIntent, 1);
}
});
然后在startActivityResult内部使用notifyDataSetChanged更新你的列表
@Override
protected void onActivityResult(int requestCode, in resultCode, Intent data) {
if(requestCode == 1) {
adapter.notifyDataSetChanged();
}
现在您将获得预期的输出