Android 以编程方式自动完成TextView项选择

Android 以编程方式自动完成TextView项选择,android,adapter,autocompletetextview,Android,Adapter,Autocompletetextview,我有一个AutoCompleteTextView,其中充满了来自sqlite数据库的城市,该数据库在单击项目时调用AsyncTask,最近我添加了一个选项,使用gps检测我的位置,所以问题是我可以检测城市(即贝鲁特)设置AutoCompleteTextView的文本,但问题是下拉过滤器会打开,显示贝鲁特(这是正确的),但我仍然需要单击列表项来调用侦听器,如何以编程方式进行调用 如何: 输入活动(完成) 检测位置(完成) 设置文本视图的文本(完成) 显示文本视图下拉列表(完成) 选择要返回的项目

我有一个
AutoCompleteTextView
,其中充满了来自sqlite数据库的城市,该数据库在单击项目时调用
AsyncTask
,最近我添加了一个选项,使用gps检测我的位置,所以问题是我可以检测城市(即贝鲁特)设置
AutoCompleteTextView
的文本,但问题是下拉过滤器会打开,显示贝鲁特(这是正确的),但我仍然需要单击列表项来调用侦听器,如何以编程方式进行调用

如何:

  • 输入活动(完成)
  • 检测位置(完成)
  • 设置文本视图的文本(完成)
  • 显示文本视图下拉列表(完成)
  • 选择要返回的项目,因为它只返回一个城市(未完成)

尝试在AutoCompleteTextview中的setText()之后添加以下内容:-

autoCompleteTV.setSelection(position);
更新:

这将在具有下拉功能的
微调器
自动完成文本视图
中工作,但不适用于
编辑文本

在这里,您可以在此链接中检查
AbsSpinner
的文档:
问题在于您正在设置文本,而
自动完成文本视图
仅显示与该文本匹配的单词。解决这个问题的一个不优雅的方法是设置一个高阈值(至少是城市名称的最大长度),强制Android向您显示列表中的所有值(该阈值是字段必须搜索相似性的字符数).

在深入研究android源代码上的AutoCompleteTextView代码后,我发现:

fun AutoCompleteTextView.selectItem(text: String, position: Int = 0) {
  this.setText(text)
  this.showDropDown()
  this.setSelection(position)
  this.listSelection = position
  this.performCompletion()
}

我面临着一个类似的问题,这解决了我的问题。重要的是调用
setText(,)
,以避免使用给定的文本过滤,并将第二个参数设置为
false
。文本将从下拉适配器中获取

解决方案片段:

automCompleteTextView.setText(automCompleteTextView.getAdapter().getItem(position).toString(), false);

明确地说,塔诺的解决方案足以回答这个问题。但是,如果其他人遇到与我相同的用例,这里有一些可能帮助您的更多背景

我在尝试创建一个不可编辑的文件并以编程方式设置其初始值时遇到了这个问题。创建此类“下拉菜单”的文档可以在“公开的下拉菜单”部分找到,该部分建议使用
TextInputLayout
AutocompleteTextView
(即使您不需要自动完成功能)

失败的解决方案1: 乍一看,
setListSelection()
getListSelection()
似乎他们可以做到这一点。但是经过多次试验,我了解到它们可能不够,因为它们只在列表弹出时起作用。例如,如果您只想设置初始选择,而不必首先显示列表弹出窗口,那么这将不起作用

失败的解决方案2: 然后我尝试了
setText()
,它在我的文本框中显示了正确的文本。耶!但是等等!当我点击文本视图时,出于某种原因,弹出列表中只显示了选项的子集。为什么会这样?这里需要记住的关键是,由于这是一个自动完成的文本视图,因此默认情况下,它根据文本视图中的文本过滤出选项。这可能并不明显,尤其是如果您只是为了制作一个简单的不可编辑的下拉选择器而使用此控件

解决方案: 这就引出了我们的实际解决方案(由Tano提出)
setText()
filter
一起作为
false
将关闭筛选功能,并且不会更改列表弹出窗口的内容

autoCompleteTextView.setText(myText, false);

解决方案是您不需要更改API级别

automCompleteTextView.setAdapter(adapter);        
// set default selection, filtering is active so all items is not visible in drop-down menu
automCompleteTextView.setText(automCompleteTextView.getAdapter().getItem(0).toString());
// change filtering for the adapter so all items can be visible in drop-down menu
adapter.getFilter().filter(null);
同一作业的一个线性程序,但需要更高的API级别

automCompleteTextView.setText(automCompleteTextView.getAdapter().getItem(0).toString(), false);
使用该解决方案可以做到:

with(autoComplete) {
    setAdapter(this@YourFragment.adapter)
    setText(itemText)
    showDropDown()
    listSelection = if (itemIndex > 0) itemIndex - 1 else 0 // Because AutoCompleteTextView shows the next row.
    performCompletion()
}
请注意,它将显示一个下拉列表,否则
listSelection
将不起作用。如果调用
dismissDropDown()
,则不会选择该项。如果不想显示下拉列表,可以使用
setOnTouchListener
捕获打开列表的内容,但这几乎没有帮助(应该解决过滤问题)


我使用了
autoCompleteTextView.setText(myText,false)解决方案,但有时会失败。我的意思是,它积极过滤结果,所以,当用户点击时,下拉列表中只有一个项目

此外,我还需要这个来处理自定义对象,这是我的解决方案:

binding.hourEditText.configureDropDownMenu(viewModel.hours) { it.hourString() }
    .subscribe {
        // Do whatever you need when on click.
    }
    .addTo(disposables)

fun <T> AutoCompleteTextView.configureDropDownMenu(list: List<T>, toString: ((T) -> String)? = null): Observable<T> {
    keyListener = null
    val textItems = toString?.let(list::map) ?: list.map { it.toString() }
    setAdapter(NonFilterArrayAdapter(context!!, android.R.layout.simple_spinner_dropdown_item, textItems))
    return itemClickEvents().map {
        list[it.position]
    }
}

private class NonFilterArrayAdapter<T>(context: Context, @LayoutRes resource: Int, objects: List<T>) : ArrayAdapter<T>(context, resource, objects) {

    override fun getFilter() = NonFilter()

    private class NonFilter : Filter() {
        override fun performFiltering(constraint: CharSequence?) = FilterResults()

        override fun publishResults(constraint: CharSequence?, results: FilterResults?) = Unit
    }
}
binding.hourEditText.configureDropDownMenu(viewModel.hours){it.hourString()}
.订阅{
//点击时做任何你需要的事情。
}
.addTo(一次性用品)
fun AutoCompleteTextView.configureDropDownMenu(列表:列表,toString:((T)->字符串)?=null):可观察{
keyListener=null
val textItems=toString?.let(list::map)?:list.map{it.toString()}
setAdapter(非FilterArrayAdapter(context!!,android.R.layout.simple\u微调器\u下拉菜单\u项,textItems))
return itemClickEvents().map{
列出[it.位置]
}
}
私有类非FilterArrayAdapter(上下文:context,@LayoutRes资源:Int,对象:List):ArrayAdapter(上下文,资源,对象){
重写getFilter()=非筛选器()
私有类非筛选器:筛选器(){
重写fun performFiltering(约束:CharSequence?=FilterResults()
覆盖fun publishResults(约束:CharSequence?,结果:FilterResults?)=单位
}
}

注意:这也包含一点Rx,但可以很容易地删除。

@HusseinYassine让我检查我的工作,然后返回解决方案。setSelection是光标放置位置的简写,不选择适配器中的项目。@Chris.Jenkins供您澄清,检查此链接,在初始化之后仍然没有获取
setOnTouchListener { _, event ->
    if (event.action == MotionEvent.ACTION_DOWN) {
        showDropDown()
        listSelection = if (itemIndex > 0) itemIndex - 1 else 0
        performCompletion()
        requestFocus()
    }
    false
}
binding.hourEditText.configureDropDownMenu(viewModel.hours) { it.hourString() }
    .subscribe {
        // Do whatever you need when on click.
    }
    .addTo(disposables)

fun <T> AutoCompleteTextView.configureDropDownMenu(list: List<T>, toString: ((T) -> String)? = null): Observable<T> {
    keyListener = null
    val textItems = toString?.let(list::map) ?: list.map { it.toString() }
    setAdapter(NonFilterArrayAdapter(context!!, android.R.layout.simple_spinner_dropdown_item, textItems))
    return itemClickEvents().map {
        list[it.position]
    }
}

private class NonFilterArrayAdapter<T>(context: Context, @LayoutRes resource: Int, objects: List<T>) : ArrayAdapter<T>(context, resource, objects) {

    override fun getFilter() = NonFilter()

    private class NonFilter : Filter() {
        override fun performFiltering(constraint: CharSequence?) = FilterResults()

        override fun publishResults(constraint: CharSequence?, results: FilterResults?) = Unit
    }
}