Every time I click on the ListView the clicked item comes to the top in Android

445 Views Asked by At

I've set a BaseAdapter to the ListView in my Android app. Every time I click on the ListView the click actions work fine. But the element I click always goes to the top of the ListView.

How do I make the clicked item keep its place when I click on the ListView?

Could this problem be due to BaseAdapter?

public class TrackAdapter extends BaseAdapter {
    private final Context context;
    private List<Track> tracks;

    public TrackAdapter(List<Track> tracks, Context context) {

        this.tracks = tracks;
        this.context = context;
    }

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

    @Override
    public Object getItem(int position) {
        return tracks.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    public void updateAdapter(List<Track> list) {
        tracks = list;
        this.notifyDataSetChanged();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        convertView = LayoutInflater.from(context).inflate(R.layout.track_list_layout, parent, false);

        convertView.setBackgroundResource(R.drawable.listview_background);

        TextView name = convertView.findViewById(R.id.track_name);
        name.setText(tracks.get(position).getName());

        TextView bpm = convertView.findViewById(R.id.track_bpm);
        bpm.setText(BPMHelper.Combine(tracks.get(position).getMinBpm(), tracks.get(position).getMaxBpm()));

        TextView type = convertView.findViewById(R.id.track_type);
        type.setText(tracks.get(position).getType());

        TextView size = convertView.findViewById(R.id.track_size);
        size.setText(tracks.get(position).getSize());

        return convertView;
    }   
}

And

trackList = (ListView) findViewById(R.id.listView);
trackList.setAdapter(trackAdapter);

 trackList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            // @SuppressLint("ResourceAsColor")
            TextView previousView = null; // to hold the previous clicked view

            @RequiresApi(api = Build.VERSION_CODES.M)
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
             TextView textView = view.findViewById(R.id.track_name);
               
                if (previousView != null) {
                    // revert the previous view when a new item is clicked
                    previousView.setTextColor(Color.YELLOW);
                }
                previousView = textView;
                textView.setTextColor(Color.RED);
}
        });

My ListView in CoordinatorLayout

      <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="587dp"
        android:layout_margin="10dp"
        android:divider="@color/grey"
        android:dividerHeight="10.0sp"
        android:scrollbars="none" />
2

There are 2 best solutions below

0
snachmsm On

at first: read how recycling pattern works, understaing this is crucial in here. do NOT inflate new convertView by convertView = LayoutInflater.from(context)... line

after that: you very should NOT change Views inside onItemClick, adapter is responsible for that, so you should inform it that some item should be drawn with different color:

public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    trackAdapter.setLastPickedItem(position);
    trackAdapter.notifyDataSetChanged(); // force redraw
}

now you need setLastPickedItem method inside your adapter, which will store this position for further use (when redraw occurs)

private int pickedPosition = -1;

public void setLastPickedItem(int position){
    pickedPosition = position;
}

after calling notifyDataSetChanged adapter will eventually call again getView method for every visible position, so in here you should check is currently being drawn item at postion is flagged as lastly pressed

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // current code in here

    if(position == pickedPosition) name.setTextColor(Color.RED);
    else name.setTextColor(Color.BLUE);

    return convertView;
}

due to recycling pattern ALWAYS draw whole current state (in your case always set text color), as previously drawn item (recycled) may be in any other state and its look may stay

if you want to keep some history of previously clicked items then just adjust setLastPickedItem method, store previously clicked in another variable (or array of all clicked) and don't forget to check and draw this state in getView

0
Khaled hamdan On

implement on Touchlistener on an item click listener associated with adapter position