2

実際には使用できないActionBarSherlockでコンテキスト メニューを使用したい。ListView.CHOICE_MODE_MULTIPLE_MODAL

リスト上の項目を複数選択するための独自の実装を作成しましたが、問題は (実際には他の場合には優れた機能です) Android が でビューを再利用することですListView。背景を色付けして選択済みとしてマークすることで、リスト上の複数選択アイテムを処理します。さらに、選択を保存しSparseArrayますが、完全に機能しているため、今は問題ありません。

ご想像のとおり、背景色は、選択したアイテムから始まるリストの 10 アイテムごとに複製されます。

では、リスト項目ごとに異なるビューを提供するにはどうすればよいでしょうか? それとも、その問題に対する別の解決策がありますか?

SimpleCursorAdapterwithを使用しViewBinderてリスト項目を埋めます。


    /***************************************
     ******** 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

答えは非常に単純なので、以前に見つけられなかったことを恥じています。
次のメソッドをオーバーライドするだけで十分です。

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は、 にこれ以上アイテムが表示されないようにするのに十分な大きさListViewです。

あと2つだけ制限があります:

  • これは、古いものを再利用せずに行ごとに新しいリスト項目を作成することを強制するため、まったく効率的ではありません。
  • この手法でViewHolderは、リスト項目が再び使用されないため、パターンを作成する必要はありません
于 2013-07-21T07:16:19.033 に答える