【问题标题】:Android Spinner with multiple choice具有多项选择的 Android Spinner
【发布时间】:2011-02-16 11:11:22
【问题描述】:

如何创建允许选择多个项目的微调器,即带有复选框的微调器?

【问题讨论】:

  • AFAIK Spinner 没有多项选择模式。
  • 以及如何在微调器中显示选定的值
  • 我的意思是我该如何实现这个:像微调器一样工作但显示带有复选框的对话框并允许多项选择的小部件。

标签: android android-spinner


【解决方案1】:

我已经编写了 MultiSpinner 的自定义实现。它看起来类似于普通微调器,但它有复选框而不是单选按钮。选定的值显示在微调器上,除以逗号。默认情况下检查所有值。试试看:

package cz.destil.settleup.gui;

public class MultiSpinner extends Spinner implements
        OnMultiChoiceClickListener, OnCancelListener {

    private List<String> items;
    private boolean[] selected;
    private String defaultText;
    private MultiSpinnerListener listener;

    public MultiSpinner(Context context) {
        super(context);
    }

    public MultiSpinner(Context arg0, AttributeSet arg1) {
        super(arg0, arg1);
    }

    public MultiSpinner(Context arg0, AttributeSet arg1, int arg2) {
        super(arg0, arg1, arg2);
    }

    @Override
    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
        if (isChecked)
            selected[which] = true;
        else
            selected[which] = false;
    }

    @Override
    public void onCancel(DialogInterface dialog) {
        // refresh text on spinner
        StringBuffer spinnerBuffer = new StringBuffer();
        boolean someSelected = false;
        for (int i = 0; i < items.size(); i++) {
            if (selected[i] == true) {
                spinnerBuffer.append(items.get(i));
                spinnerBuffer.append(", ");
                someSelected = true;
            } 
        }
        String spinnerText;
        if (someSelected) {
            spinnerText = spinnerBuffer.toString();
            if (spinnerText.length() > 2)
                spinnerText = spinnerText.substring(0, spinnerText.length() - 2);
        } else {
            spinnerText = defaultText;
        }
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
                android.R.layout.simple_spinner_item,
                new String[] { spinnerText });
        setAdapter(adapter);
        listener.onItemsSelected(selected);
    }

    @Override
    public boolean performClick() {
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        builder.setMultiChoiceItems(
                items.toArray(new CharSequence[items.size()]), selected, this);
        builder.setPositiveButton(android.R.string.ok,
                new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                });
        builder.setOnCancelListener(this);
        builder.show();
        return true;
    }

    public void setItems(List<String> items, String allText,
            MultiSpinnerListener listener) {
        this.items = items;
        this.defaultText = allText;
        this.listener = listener;

        // all selected by default
        selected = new boolean[items.size()];
        for (int i = 0; i < selected.length; i++)
            selected[i] = true;

        // all text on the spinner
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
                android.R.layout.simple_spinner_item, new String[] { allText });
        setAdapter(adapter);
    }

    public interface MultiSpinnerListener {
        public void onItemsSelected(boolean[] selected);
    }
}

您可以像这样在 XML 中使用它:

<cz.destil.settleup.gui.MultiSpinner android:id="@+id/multi_spinner" />

然后你用 Java 像这样向它传递数据:

MultiSpinner multiSpinner = (MultiSpinner) findViewById(R.id.multi_spinner);
multiSpinner.setItems(items, getString(R.string.for_all), this);

另外你需要实现监听器,它会返回相同长度的数组,用真或假来显示选中到未选中..

public void onItemsSelected(boolean[] selected);

【讨论】:

  • 如何从组件中获取选定的索引?我可以使用它,但我怎样才能获得选定的项目?谢谢
  • 只需通过公共 getter 公开数组 selected[]。
  • 效果很好!一段很棒的代码。感谢您发布完整列表。
  • @Destil 我想要DropDown 视图而不是对话框。有可能吗?
  • 如何提供搜索功能?有链接吗?
【解决方案2】:

我只想展示@Destil 的 MultiSpinner 的替代版本(感谢您的启发性代码),它允许在 xml 中使用“android:entries”,就像微调器一样。

它最初不显示默认文本,例如“选择一个”,但您可以通过在构造函数中设置额外的ArrayAdapter 轻松获得它。

MultiSpinner.java

package com.example.helloworld;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.ArrayAdapter;
import android.widget.Spinner;

/**
 * Inspired by: http://stackoverflow.com/a/6022474/1521064
 */
public class MultiSpinner extends Spinner {

    private CharSequence[] entries;
    private boolean[] selected;
    private MultiSpinnerListener listener;

    public MultiSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiSpinner);
        entries = a.getTextArray(R.styleable.MultiSpinner_android_entries);
        if (entries != null) {
            selected = new boolean[entries.length]; // false-filled by default
        }
        a.recycle();
    }

    private OnMultiChoiceClickListener mOnMultiChoiceClickListener = new OnMultiChoiceClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which, boolean isChecked) {
            selected[which] = isChecked;
        }
    };

    private DialogInterface.OnClickListener mOnClickListener = new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // build new spinner text & delimiter management
            StringBuffer spinnerBuffer = new StringBuffer();
            for (int i = 0; i < entries.length; i++) {
                if (selected[i]) {
                    spinnerBuffer.append(entries[i]);
                    spinnerBuffer.append(", ");
                }
            }

            // Remove trailing comma
            if (spinnerBuffer.length() > 2) {
                spinnerBuffer.setLength(spinnerBuffer.length() - 2);
            }

            // display new text
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
                    android.R.layout.simple_spinner_item,
                    new String[] { spinnerBuffer.toString() });
            setAdapter(adapter);

            if (listener != null) {
                listener.onItemsSelected(selected);
            }

            // hide dialog
            dialog.dismiss();
        }
    };

    @Override
    public boolean performClick() {
        new AlertDialog.Builder(getContext())
                .setMultiChoiceItems(entries, selected, mOnMultiChoiceClickListener)
                .setPositiveButton(android.R.string.ok, mOnClickListener)
                .show();
        return true;
    }

    public void setMultiSpinnerListener(MultiSpinnerListener listener) {
        this.listener = listener;
    }

    public interface MultiSpinnerListener {
        public void onItemsSelected(boolean[] selected);
    }
}

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MultiSpinner">
        <attr name="android:entries" />
    </declare-styleable>
</resources>

layout_main_activity.xml

<com.example.helloworld.MultiSpinner
    android:id="@+id/multispinner"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:entries="@array/multispinner_entries" />

【讨论】:

    【解决方案3】:

    据我所知Spinner 没有多选模式。相反,您可以创建一个ImageButton 并在右侧设置一个可绘制的向下箭头,然后在单击事件上您可以打开一个Dialog,其中包含多个复选框。

    【讨论】:

      【解决方案4】:

      感谢您的帖子!很好的解决方案。我对类(方法 setItems)做了一个小改动,以允许用户设置已选择的项目,而不是默认选择所有项目为 true。

      public void setItems(
          List<String> items,
          List<String> itemValues, 
          String selectedList,
          String allText,
          MultiSpinnerListener listener) {
              this.items = items;
              this.defaultText = allText;
              this.listener = listener;
      
              String spinnerText = allText;
      
              // Set false by default
              selected = new boolean[itemValues.size()];
              for (int j = 0; j < itemValues.size(); j++)
                  selected[j] = false;
      
              if (selectedList != null) {
                  spinnerText = "";
                  // Extract selected items
                  String[] selectedItems = selectedList.trim().split(",");
      
                  // Set selected items to true
                  for (int i = 0; i < selectedItems.length; i++)
                      for (int j = 0; j < itemValues.size(); j++)
                          if (selectedItems[i].trim().equals(itemValues.get(j))) {
                              selected[j] = true;
                              spinnerText += (spinnerText.equals("")?"":", ") + items.get(j);
                              break;
                      }
          }
      
              // Text for the spinner
              ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
                  android.R.layout.simple_spinner_item, new String[] { spinnerText });
              setAdapter(adapter);
      }
      

      【讨论】:

      • itemValues 列表中的含义是什么?
      • @eoinzy 假设你有一个国家列表。在 itemValues 中有 ID 的值(例如 "us","uk","de","ch" 或 "1","2","3","4"),在 items 中有描述(“美国、英国”、“德国”、“瑞士”)。
      • 我有多重微调器工作,但现在如何将选定的 itemValues 提取到逗号分隔字符串中? '1,2,4,7'
      • 请问如何获取选中的物品?
      【解决方案5】:

      你可以检查一个简单的库MultiSelectSpinner

      您可以简单地执行以下步骤:

      multiSelectSpinnerWithSearch.setItems(listArray1, new MultiSpinnerListener() {
          @Override
          public void onItemsSelected(List<KeyPairBoolData> items) {
              for (int i = 0; i < items.size(); i++) {
                  if (items.get(i).isSelected()) {
                      Log.i(TAG, i + " : " + items.get(i).getName() + " : " + items.get(i).isSelected());
                  }
              }
          }
      });
      

      listArray1 将是您的数组。

      How-To查看完整示例

      【讨论】:

      • 在 github @Hasini 上发布问题
      • 为什么需要使用 KeyPairBoolData?.. 我们不能在你的依赖中使用字符串数组吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多