Different "visibility" values in each row in a ListView
I have developed a very simple app that uses a custom adapter for a ListView.
Each row has two TextViews:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView android:id="@+id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView android:id="@+id/text2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:visibility="gone" />
</LinearLayout>
The first TextView is named "text1", and the second "text2". As you see, text2 is hidden (visibility="gone").
Also, the list has a header that only contains an EditText widget:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<EditText android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Each row is represented by a very simple object named "Item" that has 2 properties (text1 and text2), and its getters/setters. Also, it has a "hasText2" method that just checks if the object has the text2 property value's length > 0:
public class Item {
private String text1;
private String text2;
public String getText1() {
return text1;
}
public void setText1(String text1) {
this.text1 = text1;
}
public boolean hasText2() {
return text2.length() > 0;
}
public String getText2() {
开发者_如何转开发 return text2;
}
public void setText2(String text2) {
this.text2 = text2;
}
}
Okay, I'll initialize the list with just 2 items in my main app file:
Item item1 = new Item();
item1.setText1("Item 1");
item1.setText2("optional 1");
Item item2 = new Item();
item2.setText1("Item 2");
item2.setText2("");
getListView().addHeaderView(getLayoutInflater().inflate(R.layout.list_header, null), false, false);
m_items = new ArrayList<Item>();
m_adapter = new CustomListAdapter(this, R.layout.list_row, m_items);
setListAdapter(m_adapter);
m_items.add(item1);
m_items.add(item2);
m_adapter.notifyDataSetChanged();
This is the getView method of my custom adapter (that extends ArrayAdapter):
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.list_row, null);
}
// get the two text widgets of this row layout
TextView text1 = (TextView) convertView.findViewById(R.id.text1);
TextView text2 = (TextView) convertView.findViewById(R.id.text2);
// get the Item object of this row
Item list_item = items.get(position);
// we set the text1 property of this Item to the text1 widget
text1.setText(list_item.getText1());
// if this Item has a text2 (value length > 0), then set it to the text2 widget and make it visible
if (list_item.hasText2()) {
text2.setText(list_item.getText2());
text2.setVisibility(0);
}
return convertView;
}
So, what I want is to show the text2 widget only if the Item object has it defined (value's length > 0).
And this is the result after running the app:
That's good, it works just as I expected!! :)
But what if I tap the EditText of the list header? (so I force to update the list):
What happened here? That's impossible. The second row has no text2 defined, and Android just has taken the text2 from the first row! Why??
The only reason I could imagine is that I cannot use rows with different visibility... but then, why Android let me do it when I just run the app? It seems to fail only when the keyboard appears (list update).
This has a problem for the exact same reason I described in notes on your previous question. The view is being recycled, so the customization performed in the clause if (list_item.hasText2()) {
is permanently set on that view; even when recycled to a view for which that clause would not be true.
In this case the following modification would probably fix the issue:
if (list_item.hasText2()) {
text2.setText(list_item.getText2());
text2.setVisibility(View.VISIBLE);
} else {
text2.setVisibility(View.GONE);
}
精彩评论