Xamarin Forms: Add Clear Entry

Viewed 10000

Can you point me into the right direction: How can I achieve in Xamarin.Forms a clear entry button with behavior. The behavior would be: When tapping to clear icon the entry's content on the android and iOS side the content will be deleted.

By default the entry control does't have this.

enter image description here

The result would be:

enter image description here

4 Answers

After some research I managed to do this with effects.

The downsize is that you must do it on the Android project and on iOS project separately.

Like Jason suggested it can be done with custom renderers too. But still you must implement it on each Android/iOS project.

On the android project side you can do this by adding an effect that looks like this:

Note: Before sharing the code I must inform you that you must have an icon into the Resources/drawable with the name of ic_clear_icon.png.

/// <summary>
    /// Adding a clear entry effect.
    /// </summary>
    public class ClearEntryEffect : PlatformEffect
    {
        /// <summary>
        /// Attach the effect to the control.
        /// </summary>
        protected override void OnAttached()
        {
            ConfigureControl();
        }

        protected override void OnDetached()
        {
        }

        private void ConfigureControl()
        {
            EditText editText = ((EditText)Control);
            editText.AddTextChangedListener(new OnTextChangedListener(editText));
            editText.FocusChange += EditText_FocusChange;
        }

        /// <summary>
        /// If the entry looses focus, delete the x icon.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void EditText_FocusChange(object sender, Android.Views.View.FocusChangeEventArgs e)
        {
            var editText = (EditText)sender;
            if (e.HasFocus == false)
                editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0);
        }
    }

    /// <summary>
    /// Adding an OnTextChangedListener to my entry.
    /// </summary>
    public class OnTextChangedListener : Java.Lang.Object, Android.Text.ITextWatcher
    {
        private EditText _editText;
        public OnTextChangedListener(EditText editText)
        {
            _editText = editText;
        }
        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 (count != 0)
            {
                _editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.ic_clear_icon, 0);
                _editText.SetOnTouchListener(new OnDrawableTouchListener());
            }
            else
                _editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0);
        }
    }

    /// <summary>
    /// Adding a Touch listener so it can be clicked in order to remove the text.
    /// </summary>
    public class OnDrawableTouchListener : Java.Lang.Object, Android.Views.View.IOnTouchListener
    {
        public bool OnTouch(Android.Views.View v, MotionEvent e)
        {
            if (v is EditText && e.Action == MotionEventActions.Up)
            {
                EditText editText = (EditText)v;

                if (editText.Text != null)
                    editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.ic_clear_icon, 0);

                if (editText.GetCompoundDrawables()[2] != null)
                {
                    //If the region on which i tapped is the region with the X the text will be cleaned
                    if (e.RawX >= (editText.Right - editText.GetCompoundDrawables()[2].Bounds.Width()))
                    {
                        editText.Text = string.Empty;
                        return true;
                    }
                }
            }

            return false;
        }
    }

On the iOS project side is more simple. Because it has it natively:

 public class ClearEntryEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            ConfigureControl();
        }

        protected override void OnDetached()
        {
        }

        private void ConfigureControl()
        {
            ((UITextField)Control).ClearButtonMode = UITextFieldViewMode.WhileEditing;
        }
    } 

Now you create an effect class on the PCL project in witch you reference the two ClearEntryEffect classes(from Android/iOS projects).

This effect class is needed so can it be refferenced from the XAML file where you declare your Entry.

public class ClearEntryEffect : RoutingEffect
    {
       public ClearEntryEffect() : base("Effects.ClearEntryEffect")
        {
        }
    }

Now you just refference it on the shared forms project(PCL in my case) into the xaml:

1) Refferencing the namespace where the effect is located: xmlns:effects="clr-namespace:YourNamespace.Common.Effects"

2) Adding the effect to the entry:

<Entry x:Name="OrderNo"
Text="{Binding OrderNo, Mode=TwoWay}"
   <Entry.Effects>
       <effects:ClearEntryEffect/>
   </Entry.Effects>
</Entry>

I think u need renderer for this and for example in android platform set android:drawableRight. On iOS platform set RightView property of UITextview.

Another option is wrap your Entry in Grid with Image.

   <Grid>
            <Entry></Entry>
            <Image Source="your image"
                   HeightRequest="24" // some height
                   WidthRequest="24" //some width
                   HorizontalOptions="End"
                   .... some margins>
            </Image>
   </Grid>

The ClearButtonVisibility property has been added in a new Xamarin.Forms, so there is no need for custom renderers right now. For example:

<Entry Text="Xamarin.Forms"
       ClearButtonVisibility="WhileEditing" />

See Display a clear button in Xamarin.Forms documentation.

Related