简体   繁体   English

AutoCompleteTextView:检测何时关闭下拉菜单并且未选择项目

[英]AutoCompleteTextView: detecting when dropdown is dismissed and item is NOT selected

I need to know when the user taps outside of the AutoCompleteTextView dropdown in order to dismiss it (ie they dismiss the popup with selecting an item in the list).我需要知道用户何时在AutoCompleteTextView下拉列表之外点击以将其关闭(即他们通过选择列表中的项目来关闭弹出窗口)。 I've setup the setOnDismissListener() as shown here:我已经设置了setOnDismissListener() ,如下所示:

    mAutoView.setOnDismissListener(new AutoCompleteTextView.OnDismissListener() {
        @Override
        public void onDismiss() {
            CharSequence msg = "isPerformingCompletion = " + mAutoView.isPerformingCompletion() +
                    "   Item selected at = " + mAutoView.getListSelection();
            Toast.makeText(getContext(), msg, Toast.LENGTH_LONG).show();
        }
    });

And an OnItemClickListener like this:还有一个像这样的 OnItemClickListener:

 private AdapterView.OnItemClickListener mAutocompleteClickListener
        = new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        // get selected item and pass it to result callback
    }
};

The onDismiss event fires before the onItemClick event, and unfortunately, neither the "isPerformingCompletion()" nor the "getListSelection()" methods return a value until the onItemClick event fires. onDismiss事件在onItemClick事件之前触发,不幸的是,在onItemClick事件触发之前,“isPerformingCompletion()”和“getListSelection()”方法都不会返回值。

Can anyone suggest an approach to detecting a dismiss without a list selection?任何人都可以建议一种在没有列表选择的情况下检测解雇的方法吗?

Below piece of code will detect that if user dismiss the dropdown of autocompletetextview, Then onDismiss it will check the selected input using Geocode API, If it is having a result then selected input is valid otherwise input is not valid, So In that case, Entered text will be vanish in bit seconds.下面的代码将检测到如果用户关闭 autocompletetextview 的下拉菜单,然后 onDismiss 它将使用 Geocode API 检查所选输入,如果有结果则所选输入有效,否则输入无效,所以在这种情况下,输入文本将在几秒钟内消失。

mAutoView.setOnDismissListener {
    try {
        val fromLocationName = Geocoder(context).getFromLocationName(mAutoView.getText().toString(), 1)
        if (fromLocationName != null && fromLocationName.isNotEmpty()) {
            Log.d(TAG, "Address valid")
        } else {
            mAutoView.setText("")
            Log.d(TAG, "Address not valid")
        }
    } catch (e: Exception) {
        mAutoView.setText("")
        Log.d(TAG, "Address not valid with Exception")
    }
}

Means you need a kind of validator in OnDismiss, That will check the input text is valid or not, Based on validation you can indicate to user that entered input is valid or not.意味着您需要在 OnDismiss 中使用一种验证器,它将检查输入文本是否有效,基于验证您可以向用户指示输入的输入是否有效。

AutoCompleteTextView: detecting when dropdown is dismissed and item is NOT selected AutoCompleteTextView:检测何时关闭下拉菜单并且未选择项目

If I understood you well, you need to catch the event of dismissing the draopDown by touching outside of it instead of choosing an item.如果我理解你的话,你需要通过触摸它的外部而不是选择一个项目来捕捉解除 draopDown 的事件。

For some reason, the setOnDismissListener doesn't work for me.出于某种原因, setOnDismissListener对我不起作用。 I couldn't find a clue without touching the inner ListPopupWindow which get called on either event (item click or touch outside).如果不触摸在任一事件(项目单击或触摸外部)上调用的内部ListPopupWindow ,我就找不到线索。

The event is differentiated by registering an inner OnItemClickListener listener to set the tag of the view to some value that indicates that BY_ITEM_CLICK ;通过注册内部OnItemClickListener侦听器来区分事件,以将视图的标记设置为指示BY_ITEM_CLICK的某个值; if the tag is anything else;如果标签是其他东西; it will be considered a touch outside event.它将被视为触摸外部事件。

Here is a custom AutoCompleteTextView that can be used for that:这是一个可用于此的自定义AutoCompleteTextView

import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.KeyEvent
import android.view.View
import android.widget.AdapterView
import android.widget.AutoCompleteTextView
import android.widget.ListPopupWindow
import androidx.appcompat.widget.AppCompatAutoCompleteTextView


class OnDismissAutoCompleteTextView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : AppCompatAutoCompleteTextView(context, attrs), AdapterView.OnItemClickListener {

    interface OnMenuDismissListener {
        fun onTouchOutside()
        fun onItemClick()
        fun onBackPressed()
    }

    companion object {
        // set the tag to this value when an item is clicked to dismiss the menu
        const val BY_ITEM_CLICK = "BY_ITEM_CLICK"
        // set the tag to this value when the back is pressed to dismiss the menu
        const val BY_BACK_PRESSED = "BY_BACK_PRESSED"
    }

    init {
        super.setOnItemClickListener(this)
    }

    var onMenuDismissListener: OnMenuDismissListener? = null

    private var consumerListener: AdapterView.OnItemClickListener? = null


    @SuppressLint("DiscouragedPrivateApi")
    private fun getPopup(): ListPopupWindow? {
        try {
            val field = AutoCompleteTextView::class.java.getDeclaredField("mPopup")
            field.isAccessible = true
            return field.get(this) as ListPopupWindow
        } catch (e: NoSuchFieldException) {
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            e.printStackTrace()
        }
        return null
    }

    private fun setupDismissListener() {
        getPopup()?.let {
            it.setOnDismissListener {

                when (tag) {
                    BY_ITEM_CLICK -> onMenuDismissListener?.onItemClick() // Menu dismissal Event of clicking on the menu item
                    BY_BACK_PRESSED -> onMenuDismissListener?.onBackPressed()
                    else -> onMenuDismissListener?.onTouchOutside() // Menu dismissal Event of touching outside the menu
                }
                // reset the tag for the next dismissal
                tag = null
            }

        }
    }

    override fun onPreDraw(): Boolean {
        // Registering the mPopup window OnDismissListener
        setupDismissListener()
        return super.onPreDraw()
    }

    override fun onItemClick(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
        tag = BY_ITEM_CLICK
        if (consumerListener != null) {
            consumerListener!!.onItemClick(p0, p1, p2, p3); }
    }

    override fun setOnItemClickListener(l: AdapterView.OnItemClickListener?) {
        // DO NOT CALL SUPER HERE
//        super.setOnItemClickListener(l)
        consumerListener = l
    }

    override fun onKeyPreIme(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode == KeyEvent.KEYCODE_BACK && isPopupShowing)
            tag = BY_BACK_PRESSED
        return super.onKeyPreIme(keyCode, event)
    }

}

Usage:用法:

myAutoCompleteTV.onMenuDismissListener = object :
    OnDismissAutoCompleteTextView.OnMenuDismissListener {
    override fun onTouchOutside() {
        // Menu dismiss is due to touch outside event
        Toast.makeText(context, "touch outside", Toast.LENGTH_SHORT).show()
    }

    override fun onItemClick() {
        // Menu dismiss is due to clicking on an item
        Toast.makeText(context, "item clicked", Toast.LENGTH_SHORT).show()
    }

    override fun onBackPressed() {
        Toast.makeText(context, "back pressed", Toast.LENGTH_SHORT).show()
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM