Как правильно изменить цвет фона для определенной строки в ListView?(Android) - PullRequest
4 голосов
/ 08 января 2011

Я потратил несколько дней, пытаясь решить проблему с ListViews на Android. Я хотел бы реализовать один список выбора с использованием ListView. Итак, я хотел бы иметь только одну строку с предопределенным светлым цветом фона, а остальные - с другим предварительно выбранным цветом. У меня проблема в том, что, когда я нажимаю на определенную строку, выделяется другая строка, а не та, которую я нажал. Я добавил несколько сообщений в журнал, что происходит, но все, кажется, работает нормально. Вот мой код:

public class TryListViewActivity extends Activity {
    protected static final int NO_SELECTED_COLOR = 0xFF191919;
    protected static final int SELECTED_COLOR = 0xFF3366CC;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ListView listView = new ListView(this);
        ArrayList<String> list = new ArrayList<String>();
        list.add("Option 1");
        list.add("Option 2");
        list.add("Option 3");
        list.add("Option 4");
        list.add("Option 5");
        list.add("Option 6");
        list.add("Option 7");
        list.add("Option 8");
        list.add("Option 9");
        list.add("Option 10");
        list.add("Option 11");
        list.add("Option 12");
        list.add("Option 13");
        list.add("Option 14");
        list.add("Option 15");

        ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(
            this,
            R.layout.list_box_entry,
            list
        );
        listView.setAdapter(listAdapter);

        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);

        // Set the listener
        listView.setOnItemClickListener(
            new AdapterView.OnItemClickListener() {
                public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                    Log.i(
                        "Log",
                        "[SingleSelectionListBox] Item clicked: position="
                        + position + ";id=" + id
                    );

                    // First, set all rows to be unselected
                    int counter  = parent.getCount();
                    Log.i(
                        "Log",
                        "[SingleSelectionListBox] "
                        + counter + " items found inside the parent"
                    );
                    int children = parent.getChildCount();
                    Log.i(
                        "Log",
                        "[SingleSelectionListBox] "
                        + children + " views found inside the parent"
                    );
                    for(int i=0;i<children;i++) {
                        Log.i(
                            "Log",
                            "[SingleSelectionListBox] Child "
                            + i + " has message "
                            + ((TextView)parent.getChildAt(i)).getText()
                        );
                    }

                    // Too inefficient but for now is OK
                    for(int i=0;i<children;i++)
                        parent.getChildAt(i)
                            .setBackgroundColor(NO_SELECTED_COLOR);
                    Log.i("Log",
                        "[SingleSelectionListBox] First visible position: "
                        + parent.getFirstVisiblePosition()
                    );

                    // Set the background color
                    TextView textView = (TextView)(parent.getChildAt(
                        position-parent.getFirstVisiblePosition()));
                    textView.setBackgroundColor(SELECTED_COLOR);
                    Log.i(
                        "Log",
                        "[SingleSelectionListBox] Text inside the "
                        + " View changing the color " + textView.getText()
                    );
                }
            }
        );
        setContentView(listView);
    }
}

Внутри ресурсов (res / layout) я вставил файл list_text_entry.xml со следующим содержимым

<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
  android:layout_height="fill_parent" android:gravity="center"
  android:textColor="#FFFFFF" android:padding="10dp" android:textSize="16sp">
</TextView>

Например, если я щелкну по записи «Option 11», когда listView ранее был прокручен, пока первая строка, которую я вижу, не будет «Option 4», появится строка «Option 7», выбранная как единственная несущая синий цвет на заднем плане. Может кто-нибудь объяснить, что здесь происходит со мной? Я публикую ниже сообщения, которые я получил, бросить Журнал.

[SingleSelectionListBox] Item clicked: position=10;id=10
[SingleSelectionListBox] 15 items found inside the parent
[SingleSelectionListBox] 11 views found inside the parent
[SingleSelectionListBox] Child 0 has message Option 4
[SingleSelectionListBox] Child 1 has message Option 5
[SingleSelectionListBox] Child 2 has message Option 6
[SingleSelectionListBox] Child 3 has message Option 7
[SingleSelectionListBox] Child 4 has message Option 8
[SingleSelectionListBox] Child 5 has message Option 9
[SingleSelectionListBox] Child 6 has message Option 10
[SingleSelectionListBox] Child 7 has message Option 11
[SingleSelectionListBox] Child 8 has message Option 12
[SingleSelectionListBox] Child 9 has message Option 13
[SingleSelectionListBox] Child 10 has message Option 14
[SingleSelectionListBox] First visible position: 3
[SingleSelectionListBox] Text inside the View changing the color Option 11

Как я могу догадаться, все дети внутри ViewGroup упорядочены сверху вниз, и даже когда я делаю это в коде:

TextView textView = (TextView)(parent.getChildAt(
    position-parent.getFirstVisiblePosition()
));
textView.setBackgroundColor(SELECTED_COLOR);

Появляется сообщение Option 11, но на самом деле выбрано option 7. Это ошибка с Android?

Ответы [ 7 ]

7 голосов
/ 24 февраля 2015

Я использовал этот код, он работает хорошо, вы должны попробовать это:

listView.getChildAt(0).setBackgroundColor(Color.BLUE);
5 голосов
/ 12 января 2011

Спасибо Дейву и ChristianB за ваши ответы. Я до сих пор не знаю, почему Android это делает, поэтому вопрос до сих пор не решен. Однако я нашел способ получить то, что мне было нужно, создав собственный адаптер. Я дам вам код на случай, если он кому-нибудь понадобится.

public class CustomAdapter extends ArrayAdapter<String> {

    protected static final int NO_SELECTED_COLOR = 0xFF191919;
    protected static final int SELECTED_COLOR = 0xFF3366CC;

    private ArrayList<String> items;
    private LayoutInflater mInflater;
    private int viewResourceId;
    private int selectedPosition;

    public CustomAdapter(Activity activity,int resourceId,
        ArrayList<String> list) {
        super(activity,resourceId,list);

        // Sets the layout inflater
        mInflater = (LayoutInflater)activity
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        // Set a copy of the layout to inflate
        viewResourceId = resourceId;

        // Set a copy of the list
        items = list;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TextView tv = (TextView)convertView;
        if (tv == null) {
            tv = (TextView)mInflater.inflate(viewResourceId, null);
        }
        tv.setText(items.get(position));

        // Change the background color
        if (position==selectedPosition) tv.setBackgroundColor(SELECTED_COLOR);
        else tv.setBackgroundColor(NO_SELECTED_COLOR);

        return tv;
    }

    public void setSelected(int position) {
        selectedPosition = position;
    }
}

Итак, в инициализации ListView мне просто нужно поставить этот слушатель:

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    public void onItemClick(AdapterView<?> parent, View view,
        int position, long id) {
        ((CustomAdapter)listAdapter).setSelected(position);
        listView.invalidate();
    }
});

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

5 голосов
/ 08 января 2011

Да, вы должны использовать, как сказал Дейв:

view.setBackgroundColor(SELECTED_COLOR);

и, возможно,

view.refreshDrawableState(); 

однако, поскольку Android перерабатывает списки, он будет повторять выбранный вами цвет для каждого первого элемента, который не отображается на экране. Поэтому, если на экране вашего размера могут отображаться десять элементов, то при прокрутке также будут отображаться выбранные элементы 11-го, 21-го и т.д.

Чтобы избежать этого, вам нужно создать собственный адаптер. Тогда в getView вам нужно сказать это:

if (myActivity.selectedRow != position){
    v.setBackgroundColor(Color.TRANSPARENT);
} else {
    v.setBackgroundColor(SELECTED_COLOUR);
}

Где selectedRow - это public static int selectedRow в myActivity, активности, которая создает ваш список. Там вы сохраняете номер строки, который выбирается при нажатии на список.

0 голосов
/ 24 сентября 2015

попробуйте это,

OnItemClickListener onitemclick = new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> adapter, View arg1, int position, long id) {
                selectedItem= position;
                adapter.notifyDataSetChanged();
        }
    };

переопределите метод getView () вашего адаптера:

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final View view = View.inflate(context, R.layout.item_list, null);

        if (position == selectedItem) {
            // set your color
        }

        return view;
    }
0 голосов
/ 24 сентября 2015
    @Override
    public View getView(int position, View convertView, ViewGroup parent) 
    {
   LayoutInflater inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

  View itemView = inflater.inflate(R.layout.verselayout, parent, false); 
    txttitle = (TextView) itemView.findViewById(R.id.Versetxt);
    if (position%2 == 0) {
       txttitle.setTextColor(Color.parseColor("#FFFFFF"));
    }
 else
       {
    txttitle.setTextColor(Color.parseColor("#FFFF00"));
       }

     return itemView;
    }
0 голосов
/ 27 июня 2013

listview.setOnItemClickListener (new AdapterView.OnItemClickListener () {

  @Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long   id) 
{

    View v;

    int count = parent.getChildCount();
    v =parent.getChildAt(position);
    parent.requestChildFocus(v, view);  v.setBackground(res.getDrawable(R.drawable.transparent_button));

            for (int i=0; i<count; i++)
            {
                if (i!= position)
                {
                    v = parent.getChildAt(i);t  v.setBackground(res.getDrawable(R.drawable.not_clicked));

                }
            }

        }

    });

По сути, создайте два рисованных объекта - одно прозрачное, а другое желаемого цвета. Запросите фокусировку в позиции, на которую нажалиПоложение, как определено) и измените цвет указанной строки. Затем пройдитесь по родительскому списку и измените все остальные строки соответствующим образом. Это учитывается, когда пользователь нажимает на просмотр списка несколько раз.

0 голосов
/ 08 января 2011

Я считаю, что это связано с тем, как ListViews нумеруют и повторно используют строки.Таким образом, вместо использования parent.getChildAt(i) для получения строки, которой вы хотите манипулировать, используйте объект View, переданный самой onItemClick.

view.setBackgroundColor(SELECTED_COLOR);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...