user2456977
user2456977

Reputation: 3964

Visibility GONE in ListView

I use a ListView to display TextViews. My app looks like this:

enter image description here

When I click on a word it disappears:

enter image description here

But the ListView still keeps the empty row. I want my app to look like this after click:

enter image description here

Does anyone know why the empty row stays in place. Why Isn't it removed completely? I use setVisibility(View.GONE) to make the TextViews disappear.

When I simply use Textviews with LinearLayouts and set the visibilty to GONE the entire row disappears and the rows beneath automatically readjust accordingly.

EDIT : I edited the code to now include adapter.remove(adapter.getItem(position)) and it causes my application to crash. I added the error log and edited code. Please help.

Edited code:

package com.example.listview;

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        populateListView();
        registerClickCallback();
    }

    private void populateListView() {

        //Create list of items
        String[] myItems = {"Blue", "Green","Purple","Red"};

        //Build Adapter
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.items, myItems);

        //Configure the list view
        ListView list = (ListView) findViewById(R.id.listView1);
        list.setAdapter(adapter);
    }

    private void registerClickCallback() {
        ListView list = (ListView) findViewById(R.id.listView1);
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {

                TextView textview = (TextView) view;
                textview.setVisibility(View.GONE);
                adapter.remove(adapter.getItem(position));
            }
    }); 
}

}

Error Log:

12-19 12:04:57.994: E/AndroidRuntime(23120): FATAL EXCEPTION: main
12-19 12:04:57.994: E/AndroidRuntime(23120): Process: com.example.listview, PID: 23120
12-19 12:04:57.994: E/AndroidRuntime(23120): java.lang.UnsupportedOperationException
12-19 12:04:57.994: E/AndroidRuntime(23120):    at java.util.AbstractList.remove(AbstractList.java:638)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at java.util.AbstractList$SimpleListIterator.remove(AbstractList.java:75)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at java.util.AbstractCollection.remove(AbstractCollection.java:229)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at android.widget.ArrayAdapter.remove(ArrayAdapter.java:244)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at com.example.listview.MainActivity$1.onItemClick(MainActivity.java:50)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at android.widget.AdapterView.performItemClick(AdapterView.java:298)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at android.widget.AbsListView.performItemClick(AbsListView.java:1113)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at android.widget.AbsListView$PerformClick.run(AbsListView.java:2911)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at android.widget.AbsListView$3.run(AbsListView.java:3645)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at android.os.Handler.handleCallback(Handler.java:733)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at android.os.Handler.dispatchMessage(Handler.java:95)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at android.os.Looper.loop(Looper.java:136)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at android.app.ActivityThread.main(ActivityThread.java:5146)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at java.lang.reflect.Method.invokeNative(Native Method)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at java.lang.reflect.Method.invoke(Method.java:515)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:796)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:612)
12-19 12:04:57.994: E/AndroidRuntime(23120):    at dalvik.system.NativeStart.main(Native Method)

Upvotes: 3

Views: 3597

Answers (3)

danb
danb

Reputation: 10379

You could do

adapter.remove(adapter.getItem(position));

update: as Gabe mentions, if you need to show/hide these items based on other events, you probably want to create a custom adapter and track state so that you can set the visibility of the rows correctly at recycle time. There are also many libraries that might help like FunDapter, easy-adapter and others.

update 2: the remove() will only work if the backing list supports the .remove() operation... so you could do new ArrayAdapter<String>(this, R.layout.items, new ArrayList(Arrays.asList(myItems)));

Upvotes: 1

Gabe Sechan
Gabe Sechan

Reputation: 93569

I see a lot of people suggesting you remove the string from your dataset. I wouldn't suggest that, especially if you were to ever want a version where items can have their visibility changed by other events. The common way to do this is to create a custom Adaptor that tracks both the string value at each index and the visibility of the item. Then in getView you have to correctly set the visibility of the text view for the given index.

Just setting the visibility of the textview is bad, because listviews use view recycling. This causes the index being displayed in each textview to change at runtime, so directly changing the visibility of the textview without properly setting it in getView will cause issues when the mapping changes.

Upvotes: 1

Price
Price

Reputation: 2703

You are changing the visibility of the textview and not its parent view - the row item. The ideal way to do this would be to remove the selected item from your list and then call notifyDatasetChanged() on the adapter

Upvotes: 0

Related Questions