2

我想在实际上不允许使用的ActionBarSherlock中使用上下文菜单ListView.CHOICE_MODE_MULTIPLE_MODAL

我已经为列表中的多选项目创建了自己的实现,但问题是(实际上在其他情况下这是一个很棒的功能)androidListView. 我通过着色它们的背景以将它们标记为选中来处理列表上的多选项目,此外我将选择存储在SparseArray但现在没关系,因为它工作得很好。

您可以猜到,从我选择的项目开始,我的列表中每 10 个项目都会复制背景颜色。

那么我应该怎么做才能为每个列表项提供不同的视图呢?或者也许有另一种解决这个问题的方法?

我用SimpleCursorAdapterwithViewBinder来填写我的列表项。


    /***************************************
     ******** ACTION MODES HANDLING ********
     ***************************************/

    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {
        switchActionMode();

        if (isInActionMode) {
            checkItem(position, v);
            startActionMode();
        }
        else {
            uncolorAndClearAllItems();
            actionMode.finish();
        }

        return true;
    }

    private void switchActionMode() {
        isInActionMode ^= true;
    }

    private void checkItem(int position, View v) {
        boolean isChecked = isItemChecked(position);
        setItemChecked(position, v, !isChecked);
        colorItem(v, !isChecked);
    }

    private boolean isItemChecked(int position) {
        return checkedItems.get(position, false);
    }

    private void startActionMode() {
        actionMode = activity.startActionMode(new ActionModeCallback());
    }

    private void setItemChecked(int position, View v, boolean isChecked) {
        if (isChecked) {
            checkedItems.put(position, true);
        }
        else {
            checkedItems.delete(position);
        }
    }

    private void colorItem(View v, boolean isChecked) {
        int color;
        if (isChecked) {
            color = COLOR_BLUE;
        }
        else {
            color = Color.TRANSPARENT;
        }
        v.setBackgroundColor(color);
    }

    private void colorItem(int position, boolean isChecked) {
        View listItemView = listView.getChildAt(position);
        colorItem(listItemView, isChecked);
    }

    private final class ActionModeCallback implements ActionMode.Callback {
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            activity.getSupportMenuInflater().inflate(R.menu.list_action_menu, menu);
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            isInActionMode = true;
            swipeDismissList.pause();
            return true;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            int itemsSize = checkedItems.size();

            switch (item.getItemId()) {
                case R.id.menu_dismiss:
                    dismissFeeds(itemsSize);
                    break;
                case R.id.menu_mark_as_read:
                    markFeedsAsRead(itemsSize);
                    break;
            }

            restartLoaderIfNecessary(itemsSize);
            mode.finish();
            return true;
        }

        private void dismissFeeds(int itemsSize) {
            ArrayList<Feed> feeds = new ArrayList<Feed>();
            for (int i = itemsSize - 1; i >= 0; i--) {
                int position = checkedItems.keyAt(i);
                Feed dismissedFeed = dismissFeedAndReturn(position);
                feeds.add(dismissedFeed);
            }
            createUndoAction(feeds, R.string.undobar_message_deleted_selected, Action.DISMISSED);
        }

        private void markFeedsAsRead(int itemsSize) {
            ArrayList<Long> feedsIDs = new ArrayList<Long>();
            for (int i = itemsSize - 1; i >= 0; i--) {
                int position = checkedItems.keyAt(i);
                Feed readFeed = markFeedAsReadAndReturn(position);
                feedsIDs.add(readFeed.ID());
            }
            createUndoAction(feedsIDs, R.string.undobar_message_read_selected, Action.READ);
        }

        private void createUndoAction(ArrayList<? extends Serializable> feedsIDs, int messageId, Action actionType) {
            UndoableCollection undoableAction = new UndoableCollection(feedsIDs, actionType);
            undoBarController.showUndoBar(undoableAction, messageId);
        }

        private void restartLoaderIfNecessary(int itemsSize) {
            if (itemsWillChange(itemsSize)) {
                restartLoader();
            }
        }

        private boolean itemsWillChange(int itemsSize) {
            return itemsSize != 0;
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {
            isInActionMode = false;
            swipeDismissList.resume();
            uncolorAndClearAllItems();
        }
    }

    private void uncolorAndClearAllItems() {
        int size = checkedItems.size();
        for (int i = size - 1; i >= 0; i--) {
            int position = checkedItems.keyAt(i);
            colorItem(position, false);
        }
        checkedItems.clear();
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);

        if (isInActionMode) {
            checkItem(position, v);
            clearCheckedItemsIfNoSelection();
        }
    }

    private void clearCheckedItemsIfNoSelection() {
        if (noItemSelected()) {
            checkedItems.clear();
            actionMode.finish();
        }
    }

    private boolean noItemSelected() {
        return checkedItems.size() == 0;
    }


SimpleCursorAdapter

class FeedCursorAdapter(context: Context, cursor: Cursor)
    extends SimpleCursorAdapter(
        context,
        R.layout.list_item,
        cursor,
        Array(C_TITLE, C_SITE, C_ADDED_DATE, C_IMAGE),
        Array(R.id.textViewFeedTitle, R.id.textViewChannelSite, R.id.textViewFeedDate, R.id.imageViewFeedImage),
        0) {

setViewBinder(new FeedCursorViewBinder(context))
}


ViewBinder

class FeedCursorViewBinder(context: Context) extends SimpleCursorAdapter.ViewBinder {
    implicit def int2bool(int: Int) = if (int == 1) true else false
    implicit def longDate2String(longDate: Long) = new Date(longDate).toLocaleString

    private lazy val bitmapUtils = new BitmapUtils(context)

    override def setViewValue(view: View, cursor: Cursor, columnIndex: Int) = {
            /**
              * Get columns indexes from cursor
              */
            def getColumnIndex(columnName: String) = cursor.getColumnIndex(columnName)
        val indexTitle = getColumnIndex(C_TITLE)
        val indexRead = getColumnIndex(C_READ)
        val indexDate = getColumnIndex(C_ADDED_DATE)
        val indexImage = getColumnIndex(C_IMAGE)
        val indexChannel = getColumnIndex(C_CHANNEL)
        val indexSite = getColumnIndex(C_SITE)

            def setTextAndColor(index: Int) = {
                val text = cursor.getString(index)
                val textView = view.asInstanceOf[TextView]
                textView.setTextColor(getTextColor)
                textView.setText(text)
                true
            }

            def getTextColor = {
                val isRead: Boolean = cursor.getInt(indexRead)
                if (isRead) Color.GRAY
                else Color.BLACK
            }

        columnIndex match {
            case `indexTitle` | `indexSite` => setTextAndColor(columnIndex)

            case `indexImage` => {
                val imageId: Int = cursor.getInt(indexImage)
                val imageFromFile = bitmapUtils.readBitmapForFeed(imageId)
                val feedImage =
                    if (imageFromFile != null) imageFromFile
                    else BitmapFactory.decodeResource(context.getResources, imageId)
                val imageViewFeedImage = view.asInstanceOf[ImageView]
                imageViewFeedImage.setImageBitmap(feedImage)
                true
            }

            case `indexDate` => {
                val dateLong = cursor.getLong(indexDate)
                val textViewFeedDate = view.asInstanceOf[TextView]
                textViewFeedDate.setText(dateLong)
                true
            }

            case _ => false
        }
    }
}

也许我会明确我的问题:

重用列表项视图时,如何在运行时设置列表项背景(使用光标适配器)而不复制它?

4

2 回答 2

0

这只是 actionBarSherlock 的问题吗?如果不 :

  1. listview 应该重用旧视图。如果你不这样做,并继续为 getView 方法返回一个新视图,你最终会得到 OOM 。我在这里写了一篇关于它的文章。

  2. 正如您所写,您可以在 listview 上进行多项选择,即使它重复使用这些项目。只需保存某种集合(或一个数组,或一个稀疏的布尔数组)来保存哪些项目被选中,并在 getView 中相应地设置项目的背景(即使它被重复使用)。

  3. 如果您是 listView 的新手,请观看讲座“ listView 的世界”。

  4. 如果您没有很多项目,您可以安全地使用其中包含多个视图的滚动视图。

于 2013-07-20T08:55:26.600 回答
0

答案太简单了,我很惭愧我没有早点找到它。
覆盖以下方法就足够了:

override def getViewTypeCount = if (getCount < 1) LIST_COUNT else getCount
// which returns how many different views will be in list view

override def getItemViewType(position: Int) = position
// which defines the type of current list item (when some of list items returns the same type, this view will be reused!)

whereLIST_COUNT足够大,以确保不会在 a 中显示更多项目ListView

只有两个限制:

  • 这根本不是有效的,因为它强制为每一行创建新的列表项而不重用旧的。
  • 在这种技术中,不需要创建ViewHolder模式,因为列表项不会被再次使用
于 2013-07-21T07:16:19.033 回答