当我更改已经可见的TextView

时间:2015-12-02 23:50:10

标签: android listview baseadapter

我有一个ListView,它由我的自定义BaseAdapter填充,其中包含一些TextView和ImageButtons的视图。如果用户从其中一个列表项中选择PopupMenu中的项,则会更改该列表项上关联的TextView的文本。这对我的ListView中的所有项目都很有效,除了第一项。由于某种原因,第一项永远不会更新TextView。我怀疑它与我的convertView有关,因为该项没有被重置,但我不知道如何修复它。

这是我的设置。我有一个由自定义BaseAdapter填充的ListView。在我的BaseAdapter中,我有getView()

public View getView(int position, View convertView, ViewGroup parent) {
    if(convertView == null) {
        IMOModGroup modGroup = modGroups.get(position);
        convertView = modGroup.getConvertView(parent);
    } 
    return convertView;
}

IMOModGroup是一种特殊的数据结构,它包含每个列表项的所有状态和数据。因此,当convertView为null时,BaseAdapter会从IMOModGroup为该位置请求一个新的convertView。这是创建新convertView的IMOModGroup方法:

public View getConvertView(ViewGroup parent) {
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    convertView = inflater.inflate(R.layout.modifier_list_item, parent, false);

    //...

    TextView selectedModText = (TextView) convertView.findViewById(R.id.modName);
    selectedModText.setText(R.string.no_modifier_selected);
    selectedModText.setTextColor(context.getResources().getColor(R.color.grayed_out_text_color));

    //...

    return convertView;
}

用户可以在每个列表项上打开PopupMenu并进行选择。当他们这样做时,上面代码中的TextView被更改以反映新文本的选择。该代码如下所示:

public boolean onMenuItemClick(MenuItem item) {
    String selectedMod = item.getTitle().toString();

    TextView selectedModText = (TextView) convertView.findViewById(R.id.modName);
    selectedModText.setText(selectedMod);
    selectedModText.setTextColor(context.getResources().getColor(R.color.imo_blue_light));

    //...

    return false;
}

所有这些对ListView中的每个项目都有效,除了第一个项目,它永远不会更新以反映TextView更改。我已经过测试,以确保TextView文本实际上已被更改,并且可以在以后调用和查看,并且它已正确设置。所以看起来数据是正确的,但视图没有得到更新。

我很确定问题是我的convertView没有被重置,所以ListView只是继续使用旧文本的旧视图。我在设置文本后尝试在BaseAdapter上调用notifyDataSetChanged(),但这并不起作用。

这个问题很有希望:First item in list view is not displaying correctly

但我不确定这是不是我的问题,而且我不确定如何将其应用到我的方案中。

有什么想法吗?我已经在SO和Google上阅读了一些类似的问题,但这些问题似乎与我的具体情况无关。我已经使用ListViews和Adapters很长一段时间了,这是我第一次见到这样的东西。谢谢你的帮助。

对评论作出反应的编辑

这是完整的BaseAdapter代码......

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import java.util.ArrayList;

public class IMOModListAdapter extends BaseAdapter {

    private Context context;
    private ArrayList<IMOModGroup> modGroups;

    public IMOModListAdapter(Context context, ArrayList<IMOModGroup> modGroups) {
        this.context = context;
        this.modGroups = modGroups;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView == null) {
            IMOModGroup modGroup = modGroups.get(position);
            convertView = modGroup.getConvertView(parent);
        }
        return convertView;
    }

    public Object getItem(int position) {
        return 0;
    }

    public long getItemId(int position) {
        return 0;
    }

    public int getCount() {
        return modGroups.size();
    }
}

进一步测试

当我深入研究调试时,我意识到当列表中元素1的TextView发生更改时,甚至根本不会调用getView()。但是当更改任何其他元素时,getView()被称为正常。

作为一个完整性检查,我尝试从父项Activity本身更改外部第一个列表项的文本。如果我尝试更改第一个项目,它什么都不做,但如果我尝试更改任何其他列表项,它工作正常!这太奇怪了!这就是我试过的:

//Set the text of the first item. This does NOTHING and the TextView
//in the item remains unchanged
IMOModGroup modGroup = modGroups.get(0);
modGroup.setTestText("This is some test text");
modList.notifyDataSetChanged();

//Set the text of the second item. This works completely fine!!!!!
IMOModGroup modGroup = modGroups.get(1);
modGroup.setTestText("This is some test text");
modList.notifyDataSetChanged();

1 个答案:

答案 0 :(得分:2)

我找到了解决这个问题的方法。只是研究关于BaseAdapter和getView()的随机SO问题,我终于在this post之前遇到了Romain Guy,其中他声明你绝不应该wrap_content使用layout_height getView()一个ListView,因为它导致ListView调用适配器的layout_height吨次,只是为了创建用于测量内容高度的虚拟视图。事实证明这导致了我的问题,因此将我的match_parent更改为match_parent就可以了。

不幸的是,现在这会导致一个新问题,因为我无法使用wrap_content,因为它会在我的父布局中隐藏其他视图。但至少第一个列表项目现在正确更新。

<强>更新

我学会了如何在填充适配器后手动和动态设置ListView的高度。我使用了下面的方法,希望这可以帮助某些人遇到类似的问题。这使得我不必使用ListView,但我仍然可以将private void setModListHeight() { int numberOfItems = modGroups.size(); //the ArrayList providing data for my ListView int totalItemsHeight = 0; for(int position = 0; position < numberOfItems; position++) { View item = modListAdapter.getView(position, null, modList); item.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); totalItemsHeight += item.getMeasuredHeight(); } int totalDividersHeight = modList.getDividerHeight() * (numberOfItems - 1); ViewGroup.LayoutParams params = modList.getLayoutParams(); params.height = totalItemsHeight + totalDividersHeight; modList.setLayoutParams(params); modList.requestLayout(); } 高度设置为仅与其内容一样大。

.sf-menu {
  list-style: none;
  margin: 0;
  padding: 0;
}

.sf-menu li {  
  float: left;   
}

.sf-menu li a {
    border-right: 2px solid;  
  border-color : #fff #00a54f;
  }

.sf-menu > li.sfHover > a,  
  .sf-menu > li > a:hover, .sf-menu > li.sfHoverForce > a {  
    border-color : #fff black;  
    color: #00a54f; 
  }