仅在ListView或RecycleView中更改一个项目

时间:2016-12-21 06:04:53

标签: android listview

我有一个带有自定义适配器的自定义对象ListView。单击列表中的单个项目将启动结果的新活动,以更新该项目,然后返回到列表,其中ListView项目右侧的绿色勾选图像为TextView,我只是用row.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.tick_green, 0) 但是当我向下滚动时,我看到另一行具有相同的drawable。来回滚动只是将这个drawable随机设置为不同的行。大多数答案都说它是因为视图正在被回收,但是当另一个活动返回结果时,无论是否可见,改变单行的方法是什么?

来自Activity的

代码与列表视图 -

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;
  }
}

如何确保我只更新被点击的行?

4 个答案:

答案 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();
         }

现在您将获得预期的输出