GridView с кнопкой меню фильтра в Android

У меня есть некоторые проблемы: у меня есть простой GridView, в котором у меня есть две категории предметов. Я хотел добавить три Menu Buttons, чтобы иметь Filter для этого GridView и показать/скрыть элементы с выбранной категорией.

Например, на следующем изображении первое изображение представляет мой простой GridView с Button in ActionBar. Когда я нажимаю кнопку, SubMenu отображает три строки, например: «Все», «Открыто» и «Закрыто». . И когда я нажимаю кнопку "Открыть", я хочу показывать только элементы с категорией "Открыть":

введите здесь описание изображения

Я нашел несколько вещей для Search Editext с помощью инструментов Filterable, но я не думаю, что это хороший способ добиться того, чего я хочу. Мне не нужен фильтр TextView/EditText, просто кнопка в ActionBar.


ОБНОВИТЬ:

Примечание. Я обновил свой Adapter после изменений с помощью @ana01 answer.

Кажется, что getView() вызываются слишком часто. Я добавил 3 Integers, чтобы подсчитать количество элементов с их категориями (nValues = общее количество, nOpen = nb открытых элементов, nClosed = nb of Закрытый пункт). Я использовал notifyDataSetChanged() для обновления своего адаптера.

Вот мой Activity с моим BaseAdapter:

public class MainActivity extends SherlockActivity {

    ActionBar actionbar;
    static GridView gridview;
    static MyAdapter adapter;

    String[] values = new String[] { 
        "Item 1", "Item 2", "Item 3", "Item 4", "Item 5"
    };

    // 1 for Open items, 2 for Closed items
    int[] vStatus = new int[] {
        1, 2, 1, 2, 1
    };

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

        gridview = (GridView) findViewById(R.id.grid);
        adapter = new MyAdapter(this);
        gridview.setAdapter(adapter);

        gridview.setOnItemClickListener(new OnItemClickListener() {
            // new Intent to another Activity
            // ...
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getSupportMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    // call an adapter method filterView() 
    // with the integer sort by category
    // 0 = All items | 1 = Open | 2 = Closed
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                return false;
            case R.id.action_listfilter_all :
                adapter.filterView(0);
                return true;
            case R.id.action_listfilter_open :
                adapter.filterView(1);
                return true;
            case R.id.action_listfilter_closed :
                adapter.filterView(2);
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    public class MyAdapter extends BaseAdapter {
        private Context mContext;

        // Initialize the category's integer "visibleFlag"
        private int visibleFlag = 0;
        // Initialize the counters' categories
        int nValues, nOpen, nClosed;

        public MyAdapter(Context c) {
            mContext = c;
        }

        // filterView method called by option selected item menu
        public void filterView(int i) {
            visibleFlag = i;

            // refresh the content
            notifyDataSetChanged();
            /* gridview.invalidateViews(); */
        }

        protected class ViewHolder {
            TextView text, view, like, user, coms;
            ImageView imageview, imageflag;
        }

        // return the number of items regarding by category selected
        public int getCount() {
            switch(visibleFlag) {
                case 0: nValues = values.length; break;
                case 1: nValues = nOpen; break;
                case 2: nValues = nClosed; break;
            }
            return nValues;
        }

        public Object getItem(int position) {
            return null;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder;

            if (convertView == null) {
                LayoutInflater inflater = ((MainActivity) mContext).getLayoutInflater();
                convertView = inflater.inflate(R.layout.item_main, parent, false);

                viewHolder = new ViewHolder();

                viewHolder.text = (TextView) convertView.findViewById(R.id.text);
                viewHolder.imageview = (ImageView) convertView.findViewById(R.id.image);

                // set the tag of the category and 
                // augment the selected category (by + 1)
                switch(vStatus[position]) {
                    case 1: viewHolder.imageview.setTag(1); nOpen++; break;
                    case 2: viewHolder.imageview.setTag(2); nClosed++; break;
                }

                // set the tag of the item's position
                viewHolder.text.setTag(position);

                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }

            // display the text with the position's tag
            viewHolder.text.setText(values[(Integer) viewHolder.text.getTag()]);

            // display the image with the position's tag
            switch((Integer) viewHolder.imageview.getTag()) {
                case 1: viewHolder.imageview.setImageResource(R.drawable.ic_open); break;
                case 2: viewHolder.imageview.setImageResource(R.drawable.ic_closed); break;
            }

            return convertView;
        }

    }

}

Но это не отображает правильные элементы с выбранной категорией!
Может ли кто-нибудь помочь мне разобраться?


person fllo    schedule 24.02.2014    source источник


Ответы (1)


Вам, вероятно, нужны только первые две строки, потому что gridView.setAdapter(adapter) не имеет смысла, если адаптер уже установлен.

Я не думаю, что вам нужен AsynkTask для обновления вашей коллекции, просто измените свой адаптер, чтобы он знал о типах элементов: когда установлен фильтр (целое число, представляющее одно из 3 состояний: все, закрыто, открыто), ваш адаптер должен сообщить правильное количество и вернуть правильный элемент (вы можете использовать 3 разных набора элементов, хотя это означает дублирование ваших данных).

gridView.notifyDataChanged() инициирует новый вызов getCount() в вашем адаптере, за которым следуют несколько вызовов getView(..). gridView.invalidateViews() говорит, что нужно перерисовать дочерние представления. Вам не нужно воссоздавать gridView.

Если ваши элементы должны быть похожи на то, что вы нарисовали, я думаю, вы могли бы использовать ListView (с тем же адаптером).

Обновление. Это нормально, если getCount() вызывается несколько раз, но вам следует избегать выполнения тяжелых задач в этом методе (в данный момент это не так).

В getView(..) вы должны предоставить представление, полностью синхронизированное с соответствующей позицией, независимо от того, используете ли вы ранее созданное представление или нет. Итак, проблема в том, что вы обновляете представление только в том случае, если оно только что создано (convertView==null), хотя вам следует обновить текст заголовка &CO. прямо перед возвратом представления. Что касается вашего «элемента-призрака», я не знаю, насколько велики ваши элементы макета, видны ли они все сразу и т. Д., Но ваш адаптер должен создавать как минимум столько же представлений, сколько и видимых.

Обновление 2:

Измените свой адаптер, как показано ниже, вызовите prepareData() в конструкторе вашего адаптера и посмотрите, работает ли он:

private ArrayList<Integer> closedIndexToRealIndex;
private ArrayList<Integer> openedIndexToRealIndex;

private void prepareData(){
    nOpen = nClosed = 0;
    closedIndexToRealIndex = new ArrayList<Integer>();
    openedIndexToRealIndex = new ArrayList<Integer>();
    for(int i = 0; i < values.count; i++){
        if(vStatus[i] == 0){    
            openedInexToRealIndex.add(Integer.valueOf(i));
            nOpen++;
        }
        else{
            closedIndexToRealIndex.add(Integer.valueOf(i));
            nClosed++;
       }
    }
}

public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder;

            if (convertView == null) {
                LayoutInflater inflater = ((MainActivity) mContext).getLayoutInflater();
                convertView = inflater.inflate(R.layout.item_main, parent, false);

                viewHolder = new ViewHolder();
                viewHolder.text = (TextView) convertView.findViewById(R.id.text);
                viewHolder.imageview = (ImageView) convertView.findViewById(R.id.image);

                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }

            int actualIndex = 0;
            switch(visibleFlag){
            case 0://all
                actualIndex = position;
                break;
            case 1://opened
                actualIndex = openedIndexToRealIndex.get(position).intValue();
                break;
            case 2://closed
                actualIndex = closedIndexToRealIndex.get(position).intValue();
                break;
            default:
                break;
            }
            viewHolder.text.setText(values[acutalIndex]);

            if(vStatus[position] == 1)
                viewHolder.imageview.setImageResource(R.drawable.ic_open);
            else
                viewHolder.imageview.setImageResource(R.drawable.ic_closed);

            return convertView;
        }
person Bianca Daniciuc    schedule 25.02.2014
comment
Спасибо за ваш ответ, я обновил свой вопрос. Кстати, я выбираю GridView, потому что хочу отображать 2 элемента подряд в ландшафтном режиме. Это небольшой совет, как имитировать внешность ListView. - person fllo; 26.02.2014
comment
Я обновил свой вопрос в соответствии с вашими предложениями. Но это не работает после многих, многих модификаций. Не могли бы вы помочь мне с этим? В любом случае, спасибо за ваше время. - person fllo; 27.02.2014
comment
Я обновил свой ответ, хотя он отредактирован с помощью блокнота, он должен работать. Пожалуйста! - person Bianca Daniciuc; 27.02.2014
comment
Я действительно ценю. Я просто делаю два изменения в вашем методе getView: 1- openedIndexToRealIndex[position].intValue() имеет ошибку Это выражение должно быть типом массива, оно стало openedIndexToRealIndex.get(position).intValue() | 2- Это не изменило изображение в зависимости от позиции элемента, поэтому: vStatus[position] стало valuesS[actualIndex]. Наконец, это работает как шарм. Большое спасибо! - person fllo; 28.02.2014