Подтвердить что ты не робот

Gmail-подобный ListView с флажками (и с помощью ActionBar)

Я пытаюсь воссоздать то, что Google сделал с ListView в приложении Gmail. В частности, я хотел бы, чтобы каждый элемент списка включал CheckBox и два TextViews (один поверх другого). Мне нужны слушатели, когда CheckBox отмечен (или щелкнут), и когда в другом месте элемента списка будет нажата кнопка. Наконец, я бы хотел, чтобы ActionBar отражал, что элементы выбраны и предоставляют такие параметры, как "Выбрать все", "Выбрать" Нет "и т.д. (См. этот скриншот),

enter image description here

До сих пор здесь был макет, который я придумал.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <CheckBox android:id="@+id/checkBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|center_horizontal" />

    <LinearLayout android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="6dp"
        android:focusable="true"
        android:clickable="true" >

        <TextView android:id="@+id/titleTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="16sp" />

        <TextView android:id="@+id/dateTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="12sp" />

    </LinearLayout>

</LinearLayout>

Это отображает все правильно, но мне нужно указать, как настроить слушателей для двух представлений (@+ id/checkBox и @+ id/linearLayout1)., Я просмотрел List16 API demo, но они используют макет simple_list_item_activated_1, и я не уверен, что XML для этого выглядит, Как показывает их код, я создал класс ModeCallback, который реализует ListView.MultiChoiceModeListener, и я установил режим выбора ListView на CHOICE_MODE_MULTIPLE_MODAL, но я не знаю, как получить CheckBox в моем макете для работы с этим.

Кто-нибудь успешно скопировал поведение ListView в приложении Gmail? Я искал совсем немного и ничего не мог придумать (несмотря на то, что некоторые другие задавали похожие вопросы, как этот - большинство ответов просто указывают на эту же демонстрационную версию API).

Кроме того, для контекста я загружаю данные из базы данных SQLite в список, и я создал свой собственный адаптер курсора (который отлично работает). У меня есть ощущение, что мне нужно настроить слушателей в этом классе в методах newView() и bindView(), но все, что я пробовал, не сработало.

Любые идеи?

4b9b3361

Ответ 1

Режим на рисунке называется режимом действия. Если вы используете свой собственный просмотр строки и пользовательский адаптер, вам не нужно использовать CHOICE_MODE_MULTIPLE_MODAL для запуска режима действия. Я попробовал один раз и не смог, и я подозреваю, что он используется для встроенного адаптера.

Чтобы вызвать режим действия самостоятельно в вашем коде, вызовите метод startActionMode в любом методе прослушивания любого из ваших представлений, пусть это будет checkbox, textview или что-то в этом роде. Затем вы передаете в него параметры ModeCallback и выполняете любую операцию, которую хотите выполнять в классе ModeCallback.

Я не думаю, что этот был бы работать на pre-3.0 Android, хотя.

Вот краткий пример. У меня есть расширяемая активность в списке и вызывается меню режима действия, когда пользователь проверяет/снимает флажок, и вот мой метод getChildView в моем классе адаптера:

public View getChildView(int groupPosition, int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {

        if (convertView == null) {
            LayoutInflater inflater =  (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.childrow, null);
        }
        CheckBox cb = (CheckBox)convertView.findViewById(R.id.row_check);
        cb.setChecked(false);   // Initialize
        cb.setTag(groupPosition + "," + childPosition);
        cb.setFocusable(false); // To make the whole row selectable
        cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                String tag = (String)buttonView.getTag();
                String[] pos = tag.split(",");
                if (isChecked) {
                    if (mActionMode == null) mActionMode = startActionMode(mMultipleCallback);                      
                }
                else {
                    if (mActionMode != null) {  // Only operate when mActionMode is available

                        mActionMode.finish();
                        mActionMode = null;
                    }
                }
            }
        });

        TextView tvTop = (TextView)convertView.findViewById(R.id.row_text_top);
        TextView tvBottom = (TextView)convertView.findViewById(R.id.row_text_bottom);
        tvTop.setText(mChildren.get(groupPosition).get(childPosition));
        tvBottom.setText(mChildrenSize.get(groupPosition).get(childPosition));
        return convertView;
    }

Ответ 2

Это будет работать в SDK 7 (Android 2.1) и выше. (вместе с SherlockActionBar)

Totaly имитирует работу с почтовым ящиком gmail.

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

Я переопределяю performItemClick, поэтому нажатие не влево будет действовать как регулярное нажатие.

Я переопределяю setItemChecked, чтобы он обновлял mActionMode по мере необходимости.

public class SelectListView extends ListView {

    private SherlockFragmentActivity mActivity;
    ActionMode mActionMode;

      public SelectListView(Context context) {
    this( context, null, 0); 
}

public SelectListView(Context context, AttributeSet attrs) {   
    this( context, attrs, 0); 
}   


public SelectListView(Context context, AttributeSet attrs, int defStyle) {
    super( context, attrs, defStyle ); 
    setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
    mActivity = (SherlockFragmentActivity) context;
}

    @Override
    public boolean performItemClick(View view, int position, long id) {
        OnItemClickListener mOnItemClickListener = getOnItemClickListener();
        if (mOnItemClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            if (view != null)
                view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
            mOnItemClickListener.onItemClick(this, view, position, id);
            return true;
        }
        return false;
    }

    boolean mSelectionMode = false;
    int mStartPosition;

    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        final int action = ev.getAction();
        final int x = (int) ev.getX();
        final int y = (int) ev.getY();

        if (action == MotionEvent.ACTION_DOWN && x < getWidth() / 7) {
            mSelectionMode = true;
            mStartPosition = pointToPosition(x, y);
        }
        if (!mSelectionMode)
            return super.onTouchEvent(ev);
        switch (action) {
        case MotionEvent.ACTION_DOWN:
            break;
        case MotionEvent.ACTION_MOVE:
            if (pointToPosition(x, y) != mStartPosition)
                mSelectionMode = false;
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
        default:
            mSelectionMode = false;
            int mItemPosition = pointToPosition(x, y);
            if (mStartPosition != ListView.INVALID_POSITION)
                setItemChecked(mItemPosition, !isItemChecked(mItemPosition));
        }

        return true;
    }

    @Override
    public void setItemChecked(int position, boolean value) {
        super.setItemChecked(position, value);
        // boolean r = getAdapter().hasStableIds();
        int checkedCount = getCheckItemIds().length;

        if (checkedCount == 0) {
            if (mActionMode != null)
                mActionMode.finish();
            return;
        }
        if (mActionMode == null)
            mActionMode = mActivity.startActionMode(new ModeCallback());

        mActionMode.setTitle(checkedCount + " selected");

    }

    class ModeCallback implements ActionMode.Callback {

        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {

            menu.add(getResources().getString(R.string.aBar_remove)).setIcon(R.drawable.ic_action_trash)
                    .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return true;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            Toast.makeText(mActivity, "Delted  items", Toast.LENGTH_SHORT).show();
            mode.finish();
            return true;
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {
            mActionMode = null;
            clearChecked();
        }

    }

    public void clearChecked() {
        SparseBooleanArray CItem = getCheckedItemPositions();
        for (int i = 0; i < CItem.size(); i++)
            if (CItem.valueAt(i))
                super.setItemChecked(CItem.keyAt(i), false);
    }

}

вы можете использовать любой адаптер списка, который вам нужен.

если у вас есть флажок в вашем list_item_layout, вам необходимо расширить ваш адаптер следующим образом:

ArrayAdapter<String> mAdapter = new ArrayAdapter<String>(this, R.layout.simple_list_item_multiple_choice,
            R.id.text1, Cheeses.sCheeseStrings) {

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View v = super.getView(position, convertView, parent);
            CheckBox checkBox = (CheckBox) v.findViewById(R.id.CheckBox);
            checkBox.setChecked(((ListView)parent).isItemChecked(position));
            return v;
        }

    };

Не забудьте использовать android: background = "? attr/activatedBackgroundIndicator" в вашем list_item_layout.xml

Ответ 3

В дополнение tocnbuff410 ответ используйте следующий код для обновления отмеченных элементов count

public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
    ++checkBoxCount;
 } else {
    --checkBoxCount;
 }
...

if (mActionMode != null) {
    mActionMode.setSubtitle(checkBoxCount + " item(s) selected.");
}

Я могу подтвердить, что следующий код не будет работать с флажками пользовательских списков просмотров. Однако долгое нажатие будет работать:

listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new ModeCallback());

Выбор флажка в пользовательском ListView не приведет к срабатыванию actionmode. Только встроенные ListViews, например. расширение ListActivity автоматически сделает это.