Reputation: 493
I have a custom BaseAdapter
used for a ListView
. The usual layout of a row looks like on the first picture.
But the list can also have items whose second line's string is empty, like on the second picture, and if that second line's string has a length equal to 0, the second line's view's setVisibility(View.GONE)
method is called.
And when the list is filled with items so it's neccessary to scroll to see the most-bottom items, and you scroll down and there is an item with only one line, and you scroll back to top, some of the two-line items can lose their second line, like on the third picture.
A simillar thing happens when an item is deleted from the list - the item going on its place gets the height of the deleted one - like on the fourth picture (forget the colored bar).
So it seems that the adapter thinks the "Cookies" item is the same as the "Something" item... or something. Why does it happen? How can i fix that?
Another gallery to show exactly what happens
Adapter code:
public class CounterItemAdapter extends BaseAdapter{
private Activity activity;
private ArrayList<CounterItem> data;
private SQLiteOpenHelper helper;
private static LayoutInflater inflater = null;
public CounterItemAdapter(Activity activity, ArrayList<CounterItem> data, SQLiteOpenHelper helper) {
this.activity = activity;
this.data = data;
this.helper = helper;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return data.size();
}
@Override
public CounterItem getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return getItem(position).getId();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(convertView == null)
view = inflater.inflate(R.layout.counter_list_item, null);
TextView nameView = (TextView)view.findViewById(R.id.nameView);
TextView descView = (TextView)view.findViewById(R.id.descView);
final TextView countView = (TextView)view.findViewById(R.id.countView);
ImageButton plusButton = (ImageButton)view.findViewById(R.id.plusButton);
final CounterItem counterItem;
counterItem = data.get(position);
nameView.setText(counterItem.getName());
if(counterItem.getDesc().length() == 0){
descView.setVisibility(View.GONE);
Log.d(HomeActivity.DEBUG_TAG, "GONE " + counterItem.getName() + ", LENGTH " + counterItem.getDesc().length());
}else
descView.setText(counterItem.getDesc());
countView.setText(counterItem.getCount() + "");
plusButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
counterItem.increment(helper.getWritableDatabase());
countView.setText(counterItem.getCount() + "");
}
});
View categoryView = view.findViewById(R.id.category);
String colors[] = {"#ff99cc00",
"#ff00ddff",
"#ffffbb33",
"#ffaa66cc",
"#ffcc0000"};
Random rand = new Random();
String color = colors[rand.nextInt(colors.length)];
categoryView.setBackgroundColor(Color.parseColor(color));
return view;
}
}
Row layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:baselineAligned="false"
android:descendantFocusability="blocksDescendants"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@+id/linearLayout" android:layout_centerVertical="true"
android:gravity="center_vertical" android:paddingLeft="12dp" android:paddingRight="12dp"
android:paddingBottom="8dp" android:paddingTop="8dp" android:id="@+id/linearLayout1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Counter name"
android:id="@+id/nameView"
android:textSize="16dp"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:id="@+id/descView"
android:textSize="16dp"
android:textColor="@color/dividerGrey"
android:text="wtf"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:id="@+id/linearLayout" android:gravity="center_vertical" android:layout_centerVertical="true"
android:paddingTop="8dp" android:paddingBottom="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="13"
android:id="@+id/countView"
android:textSize="30dp"
android:layout_marginRight="13dp" android:textColor="@color/dividerGrey"/>
<View android:layout_width="0.5dp" android:layout_height="48dp"
android:background="@color/dividerGrey" android:id="@+id/plusDivider"/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/plusButton"
android:src="@drawable/ic_button_increment"
style="@android:style/Widget.Holo.Light.ActionButton"
android:contentDescription="@string/plus_button"/>
</LinearLayout>
</RelativeLayout>
Upvotes: 0
Views: 382
Reputation: 1785
Well i suppose you use the ViewHolder pattern in a ListView right? I don't want to try and explain the whole usage of this pattern as there are many other good tutorials.
So the case you describe happens, because the listAdapter reuses the convertView that was inflated for every object so if the last object for your listview has setVisibility(View.Gone) for your second line then when you scroll up all the other childs that become visible will also have visibility(View.Gone).
A simple workaround for this is to setVisibility for each row like this:
if (convertView == null) {
convertView = (View) inflater.inflate(R.layout.view_item, null);
viewHolder = new ViewHolder();
viewHolder.itemName = (TextView) convertView.findViewById(R.id.item_name);
viewHolder.secondLine = (TextView) convertView.findViewById(R.id.second_line)
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag();
}
if(<-- your condition here-->){
secondLine.setVisibility(View.VISIBLE);
}
else{
secondLine.setVisibility(View.GONE);
}
And now that you have added the code for your adapter i believe that your mistake is here:
if(counterItem.getDesc().length() == 0){
descView.setVisibility(View.GONE);
Log.d(HomeActivity.DEBUG_TAG, "GONE " + counterItem.getName() + ", LENGTH " + counterItem.getDesc().length());
}else {
**descView.setVisibility(View.VISIBLE);**
descView.setText(counterItem.getDesc());
}
You should add code to set it visible again if needed bacause with your code when it gets gone for one of the rows it stays gone forever.
Update
Also for your second problem, whenever you delete an item from your listview you should remove the item from the adapter and call notifyDataSetChanged(); in order for the adapter to recreate the Views.
Upvotes: 1