【问题标题】:How do I access a Spinner's selected item when I've dynamically added the Spinner to a ListView?当我将 Spinner 动态添加到 ListView 时,如何访问 Spinner 的选定项?
【发布时间】:2016-06-15 21:03:54
【问题描述】:

我正在尝试为应用创建一个简单的设置页面。

我想创建一个对象列表,我在 XML 文件中定义其布局。

在这些对象的布局中是一个标题 TextView、一个帮助 TextView 和一个 Spinner。

当我在代码中动态添加这些对象时,如何引用这些单独的 Spinner 视图以便获得选定的值?

我目前有一个设置对象(列表将被填充的内容):

public class Setting {

    private String name;
    private String description;
    private String[] values;

    public Setting(String name, String description, String[] values) {
        this.name = name;
        this.description = description;
        this.values = values;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public String[] getValues() {
        return values;
    }
}

自定义 ArrayAdapter 将设置对象转换为视图:

(R.layout.spinner_row_text_layout.xml 只是一个文本视图,用于定义微调器项目的布局)

public class SettingsAdapter extends ArrayAdapter<Setting> {

    public SettingsAdapter(Context context, ArrayList<Setting> settings) {
        super(context, 0, settings);
    }

    @Override
    // Takes the position in the array, the view to convert, and the parent of the view as parameters
    public View getView(int position, View convertView, ViewGroup parent) {

        // Get the item in this position
        Setting setting = getItem(position);

        // Check if a view is being reused, otherwise inflate the view (look at view recycling in lists)
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.settings_row_view, parent, false);
        }

        // findViewById in the given view to convert
        TextView title   = (TextView) convertView.findViewById(R.id.titleText);
        TextView help    = (TextView) convertView.findViewById(R.id.helpText);
        Spinner  spinner = (Spinner)  convertView.findViewById(R.id.spinner);

        ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(getContext(), R.layout.spinner_row_text_layout, setting.getValues());
        spinner.setAdapter(spinnerAdapter);

        title.setText(setting.getName());
        help.setText(setting.getDescription());

        return convertView;
    }
}

还有以下布局文件...

设置页面布局:

<RelativeLayout

    android:id="@+id/relativeLayout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.cgillions.counter.SettingsActivity">

    <ListView
        android:id="@+id/settingsList"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:choiceMode="singleChoice"
        android:divider="@color/black"
        android:dividerHeight="5dp"/>

</RelativeLayout>

每个 ListView 项的布局:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <TextView
            android:id="@+id/titleText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"

            android:text="Hello"
            android:textSize="20sp"
            android:textColor="@color/black"

            android:gravity="center_vertical"/>

        <TextView
            android:id="@+id/helpText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"

            android:text="@string/animation_settings_hint"
            android:textSize="12sp"
            />

    </LinearLayout>

    <Spinner
        android:id="@+id/spinner"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1.5"/>

</LinearLayout>

当我启动与设置页面布局对应的 Activity 时,出现以下错误:

在 junit.framework.Assert.assertNotNull(Assert.java:211)

在 com.example.cgillions.counter.SettingsActivity.onCreate(SettingsActivity.java:46)

在 android.app.Activity.performCreate(Activity.java:5990)

这是我的 onCreate() 方法:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_settings);

    setTitle("Settings");

    // Create a new Setting object in order to populate list
    animSetting = new Setting("Animation", getResources().getString(R.string.animation_settings_hint), getResources().getStringArray(R.array.anim_values));

    settings = new ArrayList<>();
    settings.add(animSetting);

    ListView settingsList = (ListView) findViewById(R.id.settingsList);
    assertNotNull(settingsList);
    settingsList.setAdapter(new SettingsAdapter(this, settings));

    animSpinner = (Spinner) settingsList.findViewById(R.id.spinner);
    assertNotNull(animSpinner);
}

错误发生在最后一行 - 例如找不到 ID 为“微调器”的视图(因此为空)。我错误地访问了 Spinner - 有人可以建议我应该如何做到这一点吗?

我想获取 Spinner 对象以获取所选项目。

【问题讨论】:

  • R.id.spinner不是listview内部的布局而是内部View的布局,每一行都有一个新的Spinner实例,为什么Activity中需要spinner ? (还有哪一个?第一行的那个?第二行?等等)
  • “是内部视图的布局”是什么意思?我知道你在说每一行都有一个新实例 - 我将如何访问每个单独的列表项?在这种情况下,我想要第一项的微调器(因为我在列表中只有一个设置...)
  • 我想在活动中使用微调器,以便我可以拉出所选项目并更改不同活动的行为。
  • 在您的代码中,您尝试在 Activity 的 onCreate 方法中获取每个微调器的选定项。那是您要阅读所选项目的地方吗?如果没有,您可以将回调对象传递给您的SettingsAdapter,并在微调器的setOnItemSelectedListener 中使用该对象。这将允许您在更改每个微调器时执行您希望执行的任何操作。
  • @Matthew 因此,在我的设置适配器中,我创建了一个 OnClickListener,每次创建一个项目时,我都会将它的监听器设置为这个变量。在这个变量中,我切换了单击视图的 TitleText(设置的标题),以便确定它是哪个项目。这(几乎)有效(我认为其他地方肯定存在错误,因为设置并不总是正确更改)。这是完成我想做的事情的“最佳”方式吗?它看起来很长,并且倾向于意大利面条代码 - 很多功能都无处不在。

标签: java android android-layout listview android-spinner


【解决方案1】:

你可能会尝试的东西。将 Spinner 实例添加到您的 Setting 类:

public class Setting {

    private String name;
    private String description;
    private String[] values;
    private Spinner spinner;

    public Setting(String name, String description, String[] values) {
        this.name = name;
        this.description = description;
        this.values = values;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public String[] getValues() {
        return values;
    }

    public void setSpinner(Spinner s) {
        spinner = s;
    }

    public Spinner getSpinner() {
        return spinner;
    }
}

然后,在您的 getView() 方法中,将 Spinner 提供给您的设置实例:

ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(getContext(), R.layout.spinner_row_text_layout, setting.getValues());
spinner.setAdapter(spinnerAdapter);
if (setting.getSpinner() == null) {
    setting.setSpinner(spinner);
}

然后,假设您可以访问设置列表,您可以访问与每个设置关联的微调器。如果您发现一个带有 null 微调器的设置,那么它就不会出现在 Activity 中,这意味着用户永远不会更改它。但我不知道这是否真的是你想要的。

这将允许您访问每个设置的微调器,但您没有用于存储用户选择或在微调器中设置所选项目的逻辑。即,如果微调器有选项 A、B 和 C,并且用户选择了 B,您现在可以读取 B,但您没有地方存储它。 Setting 类应该有一个用于保存所选值的字段。你的 getView() 方法应该调用spinner.setSelection() 告诉它显示 B 作为当前值。否则,无论用户之前选择了什么,它都会始终显示 A。

【讨论】:

  • 我喜欢这个解决方案。每个设置都有一个 Spinner 是有意义的。但是,当我尝试读取每个 Spinner 的值时,它们都具有相同的值(添加到列表中的 last Setting 的 Spinner 的值)。
  • 我目前有 2 个设置,动画和背景。以下几行: System.out.println(settings.get(0).getName()); System.out.println(settings.get(0).getSpinner().getSelectedItem().toString()); System.out.println(settings.get(1).getName()); System.out.println(settings.get(1).getSpinner().getSelectedItem().toString());打印动画\n 白色\n 背景\n 白色
  • 你解决了吗?如果没有,接下来我会尝试在 ListView 上设置onItemClick() 的测试。第三个参数是int pos,它为您提供 ListView 中被点击的行(从 0 开始)。当您在微调器中选择一个项目时,查看是否会引发 settingsList.onItemClick() 事件。如果这样做,请将微调器中选择的值保存在与settingsList.onItemClick() 事件关联的设置实例中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多