javaandroidsdkandroid-scrollviewandroid-typeface

Scrolling in ListView loses text color and typeface


I'm not sure why it's not working, but what my code should do is very simple.

I have a ListView with default text color (BLACK) and typeface (MONOSPACE) that I declared in getView(), so everything works well when the view is created.

When I select an item from the list it should change the text color to RED and the typeface to MONOSPACE and BOLD, and if I click another item, it will change that item to RED and BOLD and return the previous text to BLACK and NORMAL. This works just fine, but if I scroll away from the RED and BOLD text until it's not visible, and then scroll back, the text is no longer RED and BOLD, but BLACK and NORMAL.

Help is greatly appreciated! Thanks

private ArrayList<String> list;
private ListView myView;
private ListAdapter listAdapter;

protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_list);

    list = new ArrayList<>();
    for (int i = 0; i < 20; i++) {
        list.add("Hello world " + i);
    }
    listAdapter = new ListAdapter();
    myView = (ListView) findViewById(R.id.myList);
    myView.setAdapter(listAdapter);
    myView.setOnItemClickListener(new  AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            TextView tv = (TextView) view.findViewById(R.id.textView);
            tv.setTextColor(Color.RED);
            tv.setTypeface(Typeface.MONOSPACE, Typeface.BOLD);

        }
    });
}

public class ListAdapter extends BaseAdapter {
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        view = getLayoutInflater().inflate(R.layout.listview_layout, null);
        TextView txt = (TextView) view.findViewById(R.id.textView);
        txt.setText(list.get(i));
        txt.setTextColor(Color.BLACK);
        txt.setTypeface(Typeface.MONOSPACE, Typeface.NORMAL);
        return view;
    }
}

Solution

  • Ok, first of all you should keep the style difference between the rows by a flag. So instead of passing a list of String to the adapter, you should consider a list containing pair of a string and a flag. This problem happens because ListView holds limited count of views and when scrolling happened, it assigns values to them.

    public class MainActivity extends AppCompatActivity {
    
        private List<Pair> list;
        private ListAdapter listAdapter;
        private ListView myView;
        private int lastClickedPosition = 0;
    
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_list);
    
            list = new ArrayList<>();
            for (int i = 0; i < 20; i++) {
                list.add(new Pair("Hello world " + i, false));
            }
            listAdapter = new ListAdapter();
            myView = (ListView) findViewById(R.id.myList);
            myView.setAdapter(listAdapter);
            myView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    list.get(lastClickedPosition).flag = false;
                    list.get(position).flag = true;
                    lastClickedPosition = position;
                    listAdapter.notifyDataSetChanged();
                }
            });
        }
    
        public class ListAdapter extends BaseAdapter {
            @Override
            public View getView(int i, View view, ViewGroup viewGroup) {
                view = getLayoutInflater().inflate(R.layout.listview_layout, null);
                TextView txt = (TextView) view.findViewById(R.id.textView);
                txt.setText(list.get(i).text);
    
                if (list.get(i).flag) {
                    txt.setTextColor(Color.RED);
                    txt.setTypeface(Typeface.MONOSPACE, Typeface.BOLD);
                } else {
                    txt.setTextColor(Color.BLACK);
                    txt.setTypeface(Typeface.MONOSPACE, Typeface.NORMAL);
                }
    
                return view;
            }
    
            @Override
            public int getCount() {
                return list.size();
            }
    
            @Override
            public Object getItem(int i) {
                return null;
            }
    
            @Override
            public long getItemId(int i) {
                return 0;
            }
        }
    
        static class Pair {
            String text;
            boolean flag;
    
            Pair(String text, boolean flag){
                this.text = text;
                this.flag = flag;
            }
        }
    }