Adapter update not visible rows

梦想与她 提交于 2019-11-30 10:03:18

问题


If you review this question Update adapter from different method you will see this answer https://stackoverflow.com/a/25632407/1270400 This answer works only with visible rows.But I have to add badge to not visible and visible rows.@pomber gave a tip but I can't understand it.

How can I do this process ? I need an example.


回答1:


You shouldn't try to modify the child elements of a listview directly. Instead, modify the adapter so that you display the badge based on some condition.

Then, modifying the underlying data for the adapter (and calling notifyDatasetChanged() on the adapter) and the listview will redraw itself.

For example, consider your adapter as being backed by a list of Song objects. In getView() you can display the badge if ((Song) get item(position)).isFavourited() returns true.

To display the badge for the nth Song in the list, you'd modify the list (songs.get(n).favourite()) and call adapter.notifyDatasetChanged().


edit with more detailed, but not exhaustively complete, example. Note the comments and the TODOs:

import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;

import java.util.ArrayList;
import java.util.List;

public class Test  {

    public static void test() {
        List<Song> songsList = new ArrayList<Song>();
        songsList.add(new Song("Generic Song Title", false));
        songsList.add(new Song("Another Song Title", false));
        songsList.add(new Song("A Third Song Title", false));
        Songs songs = new Songs(songsList);

        ListAdapter songsAdapter = new SongsAdapter(songs);
        // TODO: ListView.setAdapter(songsAdapter)

        /*
        When you want to change the visibility on a badge of a given song,
        do NOT modify the view by trying to access it from the ListView
        using ListView.getChildAt(int).

        Update the data, and give it to your adapter, as follows:
         */
        List<Song> anotherSongsListWithFavourites = new ArrayList<Song>();
        songsList.add(new Song("Generic Song Title", false));
        songsList.add(new Song("Another Song Title", true));
        songsList.add(new Song("A Third Song Title", true));
        Songs modifiedSongs = new Songs(anotherSongsListWithFavourites);
        ((SongsAdapter) songsAdapter).updateSongs(modifiedSongs);
    }

    public static void test2_updateExistingSongCollection() {
        List<Song> songsList = new ArrayList<Song>();
        songsList.add(new Song("Generic Song Title", false));
        songsList.add(new Song("Another Song Title", false));
        songsList.add(new Song("A Third Song Title", false));
        Songs songs = new Songs(songsList);

        ListAdapter songsAdapter = new SongsAdapter(songs);
        // TODO: ListView.setAdapter(songsAdapter)

        /*
        Now we update the existing Songs object. The adapter's reference is 
        still pointing to it, so that data will change too, but the adapter
        won't know. This means the data will not immediately update on screen,
        unless the user scrolls up/down OR unless we tell the adapter to
        call `notifyDatasetChanged()` which we'd have to expose another method
        for because it's a `protected` method (not shown).
         */
        songs.get(0).isFavourite = true;
    }

    private static class Song {

        public final String songName;
        // not final because we're grossly modifying this for the example in test2
        public boolean isFavourite;

        private Song(String songName, boolean isFavourite) {
            this.songName = songName;
            this.isFavourite = isFavourite;
        }

    }

    private static class Songs {

        private final List<Song> songs;

        public Songs(List<Song> songs) {
            this.songs = songs;
        }

        public Song get(int position) {
            return songs.get(position);
        }

        public int size() {
            return songs.size();
        }

    }

    private static class SongsAdapter extends BaseAdapter {

        private Songs songs;

        private SongsAdapter(Songs songs) {
            this.songs = songs;
        }

        /*
            Update the dataset, and then pass the new data to the adapter.
            You could update an individual song, but I wouldn't recommmend it.
            This adapter's responsibility is to take a Songs object map each one
            to a View - it shouldn't have to deal with MODIFYING the dataset.

            Note, the `notifyDataSetChanged()`. This tells the ListView to ask
            the adapter for new views (with updated data).
         */
        public void updateSongs(Songs songs) {
            this.songs = songs;
            notifyDataSetChanged();
        }

        @Override
        public int getCount() {
            return songs.size();
        }

        @Override
        public Song getItem(int position) {
            return songs.get(position);
        }

        @Override
        public long getItemId(int position) {
            // we won't support stable IDs for this example
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view = convertView;
            if (view == null) {
                view = createNewView();
            }
            update(view, songs.get(position));
            return view;
        }

        private View createNewView() {
            // TODO: create a new instance of your view and return it
            return null;
        }

        private void update(View view, Song song) {
            // TODO: update the rest of the view
            if (song.isFavourite) {
                // TODO: show badge on view
            } else {
                // TODO: hide the badge on view
            }
        }

    }

}


来源:https://stackoverflow.com/questions/25653905/adapter-update-not-visible-rows

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!