Search code examples
androidlistviewandroid-arrayadapterandroid-adapterview

Updating views within a single row of a ListView when clicked


I was wondering how to update views/UI (say, making a TextView invisible) within a single row of a ListView when clicking on the row because every other rows' views would be affected as well. A good example would be playing a song in Google Play Music, and the equalizer animation would be displayed accordingly. Here are my snippets:

MainActivity's onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main); // Renders only a ListView

    ListView songListView = (ListView) findViewById(R.id.list);
    List<Song> songList = new ArrayList<>();
    for (int i = 1; i <= 200; i++) songList.add(new Song("Song" + i, "Artist" + i));
    SongAdapter songAdapter = new SongAdapter(this, songList);
    songListView.setAdapter(songAdapter);
    songListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long l) {
            if (position == view.getId()) {
                TextView titleText = (TextView) view.findViewById(R.id.song_title);
                titleText.setVisibility(View.INVISIBLE);
            }
        }
    });
}

... and my ArrayAdapter's getView method and ViewHolder class:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;

    if (convertView == null) {
        convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent,
                false);

        holder = new ViewHolder();
        holder.song = (TextView) convertView.findViewById(R.id.song_title);
        holder.artist = (TextView) convertView.findViewById(R.id.song_artist);

        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    convertView.setId(position);

    Song currentSong = getItem(position);

    if (currentSong != null) {
        holder.song.setText(currentSong.getTitle());
        holder.artist.setText(currentSong.getArtist());
    }

    return convertView;
}

private static class ViewHolder {
    TextView song;
    TextView artist;
}

Solution

  • I finally figured this out after getting help from my mentor. Initializing an int field in the adapter to keep record of previous positions in the list did the trick as follows:

    MainActivity:

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            ListView songListView = (ListView) findViewById(R.id.list);
            List<Song> songList = new ArrayList<>();
            for (int i = 1; i <= 200; i++) songList.add(new Song("Song" + i, "Artist" + i));
            final SongAdapter songAdapter = new SongAdapter(this, songList);
            songListView.setAdapter(songAdapter);
            songListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long l) {
                    songAdapter.setSongPosition(position);
                    songAdapter.notifyDataSetChanged();
                }
            });
        }
    }
    

    Custom Song class:

    public class Song {
        private String mSongTitle, mSongArtist;
    
        public Song(String songTitle, String songArtist) {
            mSongTitle = songTitle;
            mSongArtist = songArtist;
        }
    
        public String getSongTitle() {
            return mSongTitle;
        }
    
        public String getSongArtist() {
            return mSongArtist;
        }
    }
    

    Custom adapter:

    public class SongAdapter extends ArrayAdapter<Song> {
        private int currentlyPlaying = -1;
    
        public SongAdapter(Context context, List<Song> songList) {
            super(context, 0, songList);
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
    
            if (convertView == null) {
                convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent,
                        false);
    
                holder = new ViewHolder(convertView);
    
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
    
            Song song = getItem(position);
            holder.song.setText(song.getSongTitle());
            holder.artist.setText(song.getSongArtist());
    
            // Hides the row, so both TextViews. Otherwise, sets each row visible.
            if (position == currentlyPlaying) convertView.setVisibility(View.INVISIBLE);
            else convertView.setVisibility(View.VISIBLE);
    
            return convertView;
        }
    
        private class ViewHolder {
            private TextView song;
            private TextView artist;
    
            private ViewHolder(View itemView) {
                song = (TextView) itemView.findViewById(R.id.song_title);
                artist = (TextView) itemView.findViewById(R.id.artist);
            }
        }
    
        public void setSongPosition(int position) {
            currentlyPlaying = position;
        }
    }