在焦点侦听器中更改复合可绘制时,EditText会无限地触发焦点更改事件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在焦点侦听器中更改复合可绘制时,EditText会无限地触发焦点更改事件相关的知识,希望对你有一定的参考价值。

我有一个自定义的edittext控件,当它处于焦点并有文本时,右侧有一个清晰的(x)图标。单击清除图标将从textbox中删除文本。不幸的是,当你点击进入textbox时,焦点变化事件无限激发,因为在drawable中更改复合focus change listener似乎会激活两个focus change events,第一个关闭焦点,第二个重点关注。知道如何在没有无限循环的情况下让它工作吗?

这是代码:

public class CustomEditText : EditText {
        private Drawable clearButton;

        protected CustomEditText (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {
        }

        public CustomEditText (Context context) : base (context) {
            Init ();
        }

        public CustomEditText (Context context, IAttributeSet attrs) : base (context, attrs) {
            Init (attrs);
        }

        public CustomEditText (Context context, IAttributeSet attrs, int defStyle) : base (context, attrs, defStyle) {
            Init (attrs);
        }

        protected void Init (IAttributeSet attrs = null) {
            // Set up clear button
            SetupClearButton ();
            SetupEvents ();
        }

        private void SetupClearButton () {
            clearButton = ContextCompat.GetDrawable (android.App.Application.Context, Resource.Drawable.forms_edit_text_clear_gray);
            clearButton.SetBounds (0, 0, clearButton.IntrinsicWidth, clearButton.IntrinsicHeight);
        }

        private void SetupEvents () {
            // Handle clear button visibility
            this.TextChanged += (sender, e) => {
                if (this.HasFocus)
                    UpdateClearButton ();
            };
            this.FocusChange += (object sender, FocusChangeEventArgs e) => {
                UpdateClearButton (e.HasFocus);// Gets called infinitely
            };

            // Handle clearing the text
            this.Touch += (sender, e) => {
                if (this.GetCompoundDrawables ()[2] != null && 
                    e.Event.Action == MotionEventActions.Up &&
                    e.Event.GetX () > (this.Width - this.PaddingRight - clearButton.IntrinsicWidth)) {
                    this.Text = "";
                    UpdateClearButton ();
                    e.Handled = true;
                } else
                    e.Handled = false;
            };
        }

        private void UpdateClearButton (bool hasFocus = true) {
            var compoundDrawables = this.GetCompoundDrawables ();
            var compoundDrawable = this.Text.Length == 0 || !hasFocus ? null : clearButton;
            if (compoundDrawables[2] != compoundDrawable)
                this.SetCompoundDrawables (compoundDrawables[0], compoundDrawables[1], compoundDrawable, compoundDrawables[3]);
        }
    }
答案

我将DroidParts的ClearableEditText移植到Xamarin.Android以便在使用Android的支持库时使用小部件是不合适的。

注意:DroidParts在Apache 2.0许可下,所以我无法将我的C#衍生物全部发布到StackOverflow,但避免连续焦点更改的关键在于OnTouchOnFocusChange方法以及将侦听器添加到基础EditText Widget的事实。

完整代码@ https://gist.github.com/sushihangover/01a7965aae75d8ef0589697aa8f0e750

public bool OnTouch(View v, MotionEvent e)
{
    if (GetDisplayedDrawable() != null)
    {
        int x = (int)e.GetX();
        int y = (int)e.GetY();
        int left = (loc == Location.LEFT) ? 0 : Width - PaddingRight - xD.IntrinsicWidth;
        int right = (loc == Location.LEFT) ? PaddingLeft + xD.IntrinsicWidth : Width;
        bool tappedX = x >= left && x <= right && y >= 0 && y <= (Bottom - Top);
        if (tappedX)
        {
            if (e.Action == MotionEventActions.Up)
            {
                Text = "";
                if (listener != null)
                {
                    listener.DidClearText();
                }
            }
            return true;
        }
    }
    if (l != null)
        return l.OnTouch(v, e);
    return false;
}

public void OnFocusChange(View v, bool hasFocus)
{
    if (hasFocus)
        SetClearIconVisible(!string.IsNullOrEmpty(Text));
    else
        SetClearIconVisible(false);
    if (f != null)
        f.OnFocusChange(v, hasFocus);
}

enter image description here

enter image description here

enter image description here

原始StackOverflow Q / A:How to create EditText with cross(x) button at end of it?

另一答案

在我看来,我最简单的实现是这样的:

 public class ClearableEditext : EditText
{
    Context mContext;
    Drawable imgX;

    public ClearableEditext(Context context) : base(context)
    {
        init(context, null);
    }
    public ClearableEditext(Context context, Android.Util.IAttributeSet attrs) : base(context, attrs)
    {
        init(context, attrs);
    }
    public ClearableEditext(Context context, Android.Util.IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
    {
        init(context, attrs);
    }
    public ClearableEditext(Context context, Android.Util.IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
    {
        init(context, attrs);
    }

    public void init(Context ctx, Android.Util.IAttributeSet attrs)
    {
        mContext = ctx;
        imgX = ContextCompat.GetDrawable(ctx, Android.Resource.Drawable.PresenceOffline);
        imgX.SetBounds(0, 0, imgX.IntrinsicWidth, imgX.IntrinsicHeight);
        manageClearButton();
        this.SetOnTouchListener(new TouchHelper(this, imgX));
        this.AddTextChangedListener(new TextListener(this));
    }

    public void manageClearButton()
    {
        if (this.Text.ToString().Equals(""))
            removeClearButton();
        else
            addClearButton();
    }
    public void addClearButton()
    {
        this.SetCompoundDrawables(this.GetCompoundDrawables()[0],
                this.GetCompoundDrawables()[1],
                imgX,
                this.GetCompoundDrawables()[3]);
    }
    public void removeClearButton()
    {
        this.SetCompoundDrawables(this.GetCompoundDrawables()[0],
                this.GetCompoundDrawables()[1],
                null,
                this.GetCompoundDrawables()[3]);
    }
}

public class TouchHelper : Java.Lang.Object, View.IOnTouchListener
{
    ClearableEditext Editext;
    public ClearableEditext objClearable { get; set; }
    Drawable imgX;
    public TouchHelper(ClearableEditext editext, Drawable imgx)
    {
        Editext = editext;
        objClearable = objClearable;
        imgX = imgx;
    }
    public bool OnTouch(View v, MotionEvent e)
    {
        ClearableEditext et = Editext;

        if (et.GetCompoundDrawables()[2] == null)
            return false;
        // Only do this for up touches
        if (e.Action != MotionEventActions.Up)
            return false;
        // Is touch on our clear button?
        if (e.GetX() > et.Width - et.PaddingRight - imgX.IntrinsicWidth)
        {
            Editext.Text = string.Empty;
            if (objClearable != null)
                objClearable.removeClearButton();

        }
        return false;
    }
}

public class TextListener : Java.Lang.Object, ITextWatcher
{
    public ClearableEditext objClearable { get; set; }
    public TextListener(ClearableEditext objRef)
    {
        objClearable = objRef;
    }

    public void AfterTextChanged(IEditable s)
    {

    }

    public void BeforeTextChanged(ICharSequence s, int start, int count, int after)
    {

    }

    public void OnTextChanged(ICharSequence s, int start, int before, int count)
    {
        if (objClearable != null)
            objClearable.manageClearButton();
    }
}

可能寿司有更好的答案,但我建议你试试这个。

要将x图标更改为自定义图标,请在init()中更改图像

以上是关于在焦点侦听器中更改复合可绘制时,EditText会无限地触发焦点更改事件的主要内容,如果未能解决你的问题,请参考以下文章

在 EditText 背景外绘制复合可绘制对象

Android Edittext Drawable 点击卡住焦点

聚焦时如何隐藏edittext的线条颜色

Android如何判断控件获取焦点啊?

在 Android 的 EditText 中单击 drawableleft 的侦听器?

文本应该从editText的开头出现,而不是结尾