Прокрутка в ListView теряет цвет текста и шрифт

Я не уверен, почему это не работает, но мой код должен делать очень просто.

У меня есть ListView с цветом текста по умолчанию (BLACK) и шрифтом (MONOSPACE), которые я объявил в getView(), поэтому все работает хорошо, когда представление создается.

Когда я выбираю элемент из списка, он должен изменить цвет текста на КРАСНЫЙ и шрифт на МОНОПРОСТРАНСТВЕННЫЙ и ЖИРНЫЙ, и если я щелкну другой элемент, он изменит этот элемент на КРАСНЫЙ и ЖИРНЫЙ и вернет предыдущий текст на ЧЕРНЫЙ и НОРМАЛЬНЫЙ. Это работает просто отлично, но если я прокручиваю от КРАСНОГО и ЖИРНОГО текста до тех пор, пока он не будет виден, а затем прокручиваю назад, текст больше не КРАСНЫЙ и ЖИРНЫЙ, а ЧЕРНЫЙ и НОРМАЛЬНЫЙ.

Помощь приветствуется! Спасибо

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;
    }
}

person 6rchid    schedule 06.09.2018    source источник


Ответы (1)


Хорошо, прежде всего вы должны сохранить разницу стилей между строками с помощью флага. Таким образом, вместо того, чтобы передавать адаптеру список String, вы должны рассмотреть список, содержащий пару строк и флагов. Эта проблема возникает из-за того, что ListView содержит ограниченное количество просмотров и при прокрутке присваивает им значения.

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;
        }
    }
}
person aminography    schedule 06.09.2018
comment
Спасибо за ответ! Кажется, это работает, но я забыл упомянуть, что хочу, чтобы, если я щелкну другой элемент, он изменил этот элемент на КРАСНЫЙ и ЖИРНЫЙ и вернул предыдущий текст на ЧЕРНЫЙ и НОРМАЛЬНЫЙ. Я попытался добавить list.get(i).flag = false; в ваш код под txt.setTypeface(Typeface.MONOSPACE, Typeface.BOLD);, но та же проблема все еще возникает. - person 6rchid; 06.09.2018
comment
@NocTurn, ты не понимаешь. Вы должны прочитать о модели класса. И как модели используются в listview. Вам нужно обновить все элементы, например, в цикле. Прежде чем установить новый цвет для текущего выбранного элемента. Или вам нужно запомнить позицию последнего элемента, который щелкнул, и изменить цвет/выделение жирным шрифтом на нормальный после того, как вы нажмете на новый элемент (и снова сохраните позицию элемента). Это очень легко. - person Peter; 06.09.2018
comment
Как сказал Питер, я редактирую решение, чтобы решить вашу проблему. Я надеюсь, что это поможет вам. - person aminography; 06.09.2018
comment
Большое спасибо, это сработало! Таким образом, в основном все должно быть обновлено до notifyDataSetChanged(), который вызывает метод getView, и что вызывало проблему, устанавливая все обновления до того, как представление было возвращено? - person 6rchid; 07.09.2018