Android:如何限制用户只能选择自动完成建议中的内容?

33
我已经提供了一个AutoCompleteTextView来向用户显示建议。根据用户选择的项目,我正在获取该项目的ID并在数据库端使用它。现在我的问题是强制用户仅从AutoCompleteTextView中进行选择(即用户不应输入自己的文本)。这是客户的要求。如何实现这一点?

你的问题不够清晰。你想要限制哪个选择/用户还能在哪里进行选择? - stoilkov
1
你是否想限制用户编辑textView,以便他只能从自动完成选项中选择一个项目? - Drejc
你收到答案了吗? - vlio20
@Drejc 这个想法是创建一个下拉列表,随着用户的输入过滤建议。 - Max
1
@Max 七年后……当然可以 :) - Drejc
显示剩余2条评论
9个回答

34

以下是一个相当简单的解决方案:

您可以通过在AutoCompleteTextView中设置setOnItemClickListener来创建一个变量以存储所选值。然后,您可以通过向其添加TextWatcher来在用户在字段中键入时将该值设置为null。最后,在继续之前,您可以验证该变量不为null。

String my_var; //keep track!
AutoCompleteTextView tv = (AutoCompleteTextView) layout.findViewById(R.id.tv);
tv.setAdapter(my_adapter);  
tv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        my_var = my_adapter.getItem(position).toString();
    }
});
/**
 * Unset the var whenever the user types. Validation will
 * then fail. This is how we enforce selecting from the list.
 */
tv.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        my_var = null;
    }
    @Override
    public void afterTextChanged(Editable s) {}
});

2
但是,如果用户输入的值出现在列表中,则my_var不应为null! - dvrm
1
@dvrm 然后你需要根据用户输入的文本来搜索适配器,并在每次文本更改时从适配器中选择值。所以,假设用户在actv中输入了'name',你将会搜索'n'、'na'、'nam'、'name',当找到匹配项时,选择该值。这样,只要文本匹配,无论用户是否点击,列表中的项目都将被选择。 - regretoverflow
1
太棒了!现在我可以轻松地跟踪用户是否输入了列表中的内容! - Farhan Saikh
只需要添加以下内容,在 onItemClick() 中使用 my_var = parent.getItemAtPosition(position).toString(); 而不是 my_var = my_adapter.getItem(position).toString(); 也可以现在正常工作。 - ganjaam

21

我正在开发一个项目,需要这样的要求,我想与大家分享我实现所需的方法。

我为自动完成的文本视图添加了一个聚焦变化侦听器,并检查当用户从自动完成视图中更改聚焦时,处理该情况。

autoTextViewCountry.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View view, boolean b) {
            if(!b) {
                // on focus off
                String str = autoTextViewCountry.getText().toString();

                ListAdapter listAdapter = autoTextViewCountry.getAdapter();
                for(int i = 0; i < listAdapter.getCount(); i++) {
                    String temp = listAdapter.getItem(i).toString();
                    if(str.compareTo(temp) == 0) {
                        return;
                    }
                }

                autoTextViewCountry.setText("");

            }
        }
    });
所以我的实现方式是:如果输入的文本在数组适配器中不存在,那么在焦点改变时清空文本视图,在进行下一阶段(比如注册)时检查这个文本视图是否为空。
希望这种方法能帮助到某些人。
愉快地编码!

看起来非常整洁。如果可以使用addTextChangedListener来获取字符串列表,那么这种方法是有帮助的。 - AkshayT

4

NiceAutoCompleteTextView可以让你通过调用isSelectionFromPopup()方法,检查从下拉弹出窗口中是否选择了某个选项。


2

只需将此属性添加到您的AutoCompleteTextView中。

android:focusable="false"

我的代码如下:

        <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/menu"
        style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Mode">

        <AutoCompleteTextView
            android:id="@+id/mode"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:focusable="false"
            />

    </com.google.android.material.textfield.TextInputLayout>

在Java端:

AutoCompleteTextView mode = findViewById(R.id.mode);
   final List<String> modeList = new ArrayList();
    modeList.add("YEARLY");
    modeList.add("HALF-YEARLY");
    modeList.add("QUARTER-YEARLY");
    modeList.add("MONTHLY");
    mode.setAdapter(new ArrayAdapter(getApplicationContext(),R.layout.list_item,modeList));

获取AutoCompleteTextView的文本:

mode.getText().toString()

简单的解决方案,但我认为这会导致您无法使用next和它一起使用,但对于我的情况,这不是一个要求。 - Henrik Bøgelund Lavstsen

1

好的,我理解您想将用户输入限制为建议框中列出的项目列表中包含的文本。

例如,如果您有:

  • One
  • Two
  • Three

那么用户只能输入第一个字符“O”和“T”。 根据之前输入的文本,以此类推。

要实现这一点,您可以利用TextViewsetFilters方法:

editBox = (TextView) findViewById(R.id.editBox);
editBox.setFilters(getFilters());
editBox.addTextChangedListener(this);
editBox.setOnFocusChangeListener(this);

此外,您可能需要使用文本更改监听器和焦点监听器来响应并更新过滤列表,当输入新字符时...以及更新过滤器。
以下是我在项目中使用的十进制数字过滤器示例:
protected InputFilter[] getFilters()
    {
        InputFilter[] filters = new InputFilter[1];

        filters[0] = new InputFilter()
        {
            public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend)
            {
                // limit input to digits and decimal / thousand separator only
                // in case thousand separator is pressed, change it to decimal
                // separator instead
                String output = "";

                if (number.isFocused())
                {
                    for (int i = start; i < end; i++)
                    {
                        char c = source.charAt(i);

                        if (isDecimalOrThousandSeparator(c))
                        {
                            output = output + Character.toString(decimalSeparator);
                        }
                        else if (Character.isDigit(c))
                        {
                            output = output + Character.toString(c);
                        }
                    }

                    return output == "" ? null : output;
                }

                return null;
            }
        };

        return filters;
    }

1
一个简单的解决方案是检查当前输入是否为适配器中的项之一。您可以像这样执行它:
val AutoCompleteTextView.isValid: Boolean
    get() {
        for (i in 0 until adapter.count) {
            if (adapter.getItem(i) == text.toString()) {
                return true
            }
        }

        return false
    }

1

这是另一种解决AutoCompleteTextView.Validator以确保有效值的方法。当编辑文本失去焦点时,将调用验证器。

autoCompleteTextView.validator = object : AutoCompleteTextView.Validator {
        override fun isValid(text: CharSequence?): Boolean {
            return optionsList.contains(text.toString())
        }

        override fun fixText(invalidText: CharSequence?): CharSequence {
            return ""
        }
    }

其中 optionsList 是有效值的列表。


1
我有相同的需求,这是我的实现方式:
autoCompleteTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                autoCompleteTextView.showDropDown();
            }
        });

在xml设置中,将focusable=falsefocusableInTouchMode=false。祝编程愉快。

0
为了拥有一个不可编辑的AutoCompleteTextView变体,您应该禁用AutoCompleteTextView中的用户输入。这可以通过在AutoCompleteTextView上设置android:inputType="none"来实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接