GridView Adapter.getView() неправильно устанавливает выбранное состояние

У меня есть GridView, который я заполняю пользовательским подклассом ArrayAdapter. Этот адаптер возвращает кнопки, которые я настроил для выбора (см. Android ImageButton с выбранным состоянием? ). Это работает до сих пор, и нажатие кнопок выбирает их (что видно с фоном селектора).

Проблема в том, что я не могу установить эти кнопки в выбранное состояние с самого начала. Они просто отображаются невыбранными, когда я впервые запускаю представление.

Я создал простой тестовый проект, чтобы проиллюстрировать проблему:

package com.example.buttonselection;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.GridView;

public class MainActivity extends Activity {

    public class SelectButtonAdapter extends ArrayAdapter<String> {

        public SelectButtonAdapter(Context context) {
            super(context, 0);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            String name = getItem(position);

            View rowView = convertView;
            if (rowView == null || !(rowView instanceof Button)) {
                rowView = new Button(getContext());
                ((Button)rowView).setOnClickListener(new OnClickListener() {
                    public void onClick(View button) {
                        if (button.isSelected()){
                            button.setSelected(false);
                        } else {
                            button.setSelected(true);
                        }
                    }
                });
            }

            Button button = (Button)rowView;
            button.setText(name);
            button.setBackgroundResource(R.drawable.button_selection);

            button.setSelected(true); // this does not work

            return button;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        GridView grid = (GridView)findViewById(R.id.gridview);

        SelectButtonAdapter adapter = new SelectButtonAdapter(this);
        adapter.add("One");
        adapter.add("Two");
        adapter.add("Three");
        grid.setAdapter(adapter);
    }
}

Из-за этого я даже не могу восстановить состояние кнопок, которое я сохранил с помощью onSaveInstanceState. Как я могу решить или обойти эту проблему?

Я благодарен за любую помощь!

РЕДАКТИРОВАТЬ: вот мой button_selection.xml, хотя это должно быть нормально, так как выбор кнопок позже работает нормально.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true">
        <shape>

            <solid android:color="@color/bet_button_pressed" />

            <stroke
                android:width="2dip"
                android:color="@color/white" />

        </shape>
    </item>

    <item android:state_selected="true">
        <shape>

            <solid android:color="@color/bet_button_selected" />

            <stroke
                android:width="2dip"
                android:color="@color/white" />

        </shape>
    </item>

        <item>
        <shape>

            <gradient
                android:angle="90"
                android:startColor="@color/bet_button_dark_green"
                android:endColor="@color/bet_button_light_green"
                android:centerX="0.5"
                android:centerY="0.5" />

            <stroke
                android:width="2dip"
                android:color="@color/white" />

        </shape>
    </item>
</selector>

person cit    schedule 22.09.2012    source источник
comment
мы можем увидеть, что button_selection рисуется?   -  person Sherif elKhatib    schedule 22.09.2012
comment
Конечно, но я не думаю, что это важно, так как он правильно выбирает и отображает кнопки позже, щелкая/выбирая их.   -  person cit    schedule 22.09.2012
comment
Точно! Я работал над этим несколько часов и не могу найти решение. Я бы сказал, что это ошибка в API. Кто-нибудь может придумать обходной путь?   -  person cit    schedule 22.09.2012


Ответы (2)


Ну, я нашел обходной путь для этой ошибки. Я просто сохраняю внешнее состояние, когда выбрана кнопка, и переопределяю метод ondraw кнопки, чтобы устанавливать правильное состояние каждый раз, когда она рисуется. Это имеет дополнительное преимущество, заключающееся в том, что выборки могут быть сохранены намного проще.

Вот обходной путь (просто доказательство концепции, мой производственный код более сложен):

package com.example.buttonselection;

import java.util.HashSet;
import java.util.Set;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.GridView;

public class MainActivity extends Activity {

    public class SelectButtonAdapter extends ArrayAdapter<String> {

        public SelectButtonAdapter(Context context) {
            super(context, 0);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            String name = getItem(position);

            View rowView = convertView;
            if (rowView == null || !(rowView instanceof Button)) {
                rowView = new Button(getContext()) {
                    @Override
                    protected void onDraw(Canvas canvas) {
                        setSelected(selectedButtons.contains(getText()));
                        super.onDraw(canvas);
                    }
                };
                ((Button)rowView).setOnClickListener(new OnClickListener() {
                    public void onClick(View button) {
                        String text = ((Button)button).getText().toString();

                        if(selectedButtons.contains(text)) {
                            selectedButtons.remove(text);
                        } else {
                            selectedButtons.add(text);
                        }
                        button.invalidate();
                    }
                });
            }

            Button button = (Button)rowView;
            button.setText(name);
            button.setBackgroundResource(R.drawable.button_selection);

            return button;
        }

    }
    private Set<String> selectedButtons = new HashSet<String>();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        GridView grid = (GridView)findViewById(R.id.gridview);

        SelectButtonAdapter adapter = new SelectButtonAdapter(this);
        adapter.add("One");
        adapter.add("Two");
        adapter.add("Three");
        grid.setAdapter(adapter);

        // this selects the first button from the start
        selectedButtons.add("One");
    }

}

На заметку: можно подумать, что API версии 4.1 не будет содержать таких очевидных ошибок. Потраченное на это время просто расстраивает и не мотивирует разрабатывать дальше для этой системы.

person cit    schedule 23.09.2012

У меня такая же проблема. В качестве обходного пути я использовал runnable, чтобы установить выбранное представление.

для вашего случая:

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
           String name = getItem(position);

           View rowView = convertView;
           if (rowView == null || !(rowView instanceof Button)) {
               rowView = new Button(getContext());
               ((Button)rowView).setOnClickListener(new OnClickListener() {
                    public void onClick(View button) {
                        if (button.isSelected()){
                            button.setSelected(false);
                        } else {
                            button.setSelected(true);
                        }
                   }
               });
            }

            Button button = (Button)rowView;
            button.setText(name);
            button.setBackgroundResource(R.drawable.button_selection);

            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    button.setSelected(true);
                }
            }, 50);

            return button;
        }

50 — это просто случайное число, которое я использую, вы можете изменить его по своему усмотрению.

Этот обходной путь работает для меня, и лично мне это нравится больше, чем переопределение метода onDraw.

Надеюсь, это кому-то поможет.

person Shinta S    schedule 02.09.2014