简体   繁体   中英

How do I implement Android.Text.ISpannable on a Android.Widget.EditText inside of Xamarin.Forms?

How do I implement Android.Text.ISpannable on a Android.Widget.EditText inside of Xamarin.Forms?

I've looked into Previous Post but the native java implementation is very different compared to Xamarin. And I don't know how to code it correctly. I found the solution for iOS but haven't found one for Android.

The Goal: On tap of the text entry control: I want to do any of the following:

  • Nothing
  • move the cursor to start or end (move the cursor)
  • Select all text. If you tap the cell and start typing, you erase the contents and replace it with the new text.

Is this possible?

Also, the link for the repository in question. See "EntryCellRender" on android and iOS.

public class EntryCell :  : CellBaseView, Android.Text.ITextWatcher, Android.Widget.TextView.IOnFocusChangeListener, Android.Widget.TextView.IOnEditorActionListener
{
    AiEditText _EditText;
    ...
    void EntryCell_Focused( object sender, EventArgs e )
    {
        _EditText.RequestFocus();

        // https://stackoverflow.com/questions/20838227/set-cursor-position-in-android-edit-text/20838295
        switch ( _EntryCell.OnSelectAction )
        {
            case AiEntryCell.SelectAction.None:
                break;

            case AiEntryCell.SelectAction.Start:
                Selection.SetSelection(_EditText, 0); // Xamarin requires Android.Text.ISpannable implementation.

                break;

            case AiEntryCell.SelectAction.End:
                int position = _EditText.Length();
                Selection.SetSelection(_EditText, position); // Xamarin requires Android.Text.ISpannable implementation.

                break;

            case AiEntryCell.SelectAction.All:
                _EditText.SelectAll();

                break;

            default: throw new ArgumentOutOfRangeException();
        }

        ShowKeyboard(_EditText);
    }

    ...
}

The implementation of AiEditText.

[Android.Runtime.Preserve(AllMembers = true)]
internal class AiEditText : Android.Widget.EditText, Android.Text.ISpannable
{
    public System.Action ClearFocusAction { get; set; }

    public AiEditText( Context context ) : base(context) { }

    public override bool OnKeyPreIme( Keycode keyCode, KeyEvent e )
    {
        if ( keyCode != Keycode.Back ||
             e.Action != KeyEventActions.Up ) return base.OnKeyPreIme(keyCode, e);

        ClearFocus();
        ClearFocusAction?.Invoke();

        return base.OnKeyPreIme(keyCode, e);
    }

    public void RemoveSpan( Java.Lang.Object what )
    {
        throw new NotImplementedException();
    }
    public void SetSpan( Java.Lang.Object what,
                         int start,
                         int end,
                         [GeneratedEnum] Android.Text.SpanTypes flags )
    {
        switch ( flags )
        {
            case SpanTypes.Composing: break;

            case SpanTypes.ExclusiveExclusive: break;

            case SpanTypes.ExclusiveInclusive: break;

            case SpanTypes.InclusiveExclusive: break;

            case SpanTypes.InclusiveInclusive: break;

            case SpanTypes.Intermediate: break;

            case SpanTypes.Paragraph: break;

            case SpanTypes.Priority: break;

            case SpanTypes.PriorityShift: break;

            case SpanTypes.User: break;

            case SpanTypes.UserShift: break;

            default: throw new ArgumentOutOfRangeException(nameof(flags), flags, null);
        }
    }
    public int GetSpanEnd( Java.Lang.Object tag )
    {
        throw new NotImplementedException();
    }
    [return: GeneratedEnum]
    public SpanTypes GetSpanFlags( Java.Lang.Object tag )
    {
        throw new NotImplementedException();
    }
    public Java.Lang.Object[] GetSpans( int start, int end, Class type )
    {
        throw new NotImplementedException();
    }
    public int GetSpanStart( Java.Lang.Object tag )
    {
        throw new NotImplementedException();
    }
    public int NextSpanTransition( int start, int limit, Class type )
    {
        throw new NotImplementedException();
    }
    public char CharAt( int index ) => Text[index];
    public ICharSequence SubSequenceFormatted( int start, int end )
    {
        throw new NotImplementedException();
    }
    public IEnumerator<char> GetEnumerator() { return Text.GetEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}

How about using custom EntryRenderer to achieve that.

Create a custom Entry( MyEntry ):

public class MyEntry : Entry
{
}

Used in Xaml :

<ContentPage ...
    xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
    ...>
    ...
    <local:MyEntry Text="In Shared Code" />
    ...
</ContentPage>

Then create a custom renderer( CustomEntryRenderer ) in Android to use SpannableString .

public class CustomEntryRenderer:EntryRenderer
{
    public CustomEntryRenderer(Context context) : base(context)
    {
    }

    protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged(e);

        if (Control != null)
        {
            //Control.SetBackgroundColor(global::Android.Graphics.Color.LightGreen);

            SpannableString ss = new SpannableString("green call bold deleteline underline Italic BackgroundColorSpan");

            //color of font
            ss.SetSpan(new ForegroundColorSpan(Android.Graphics.Color.Green), 0, 5, SpanTypes.ExclusiveExclusive);

            //telephone- link
            ss.SetSpan(new URLSpan("tel:4155551212"), 6, 10, SpanTypes.ExclusiveExclusive);

            //bold
            ss.SetSpan(new StyleSpan(TypefaceStyle.Bold), 11, 15, SpanTypes.ExclusiveExclusive);

            //deleteline
            ss.SetSpan(new StrikethroughSpan(), 16, 26, SpanTypes.ExclusiveExclusive);

            //underline
            ss.SetSpan(new UnderlineSpan(), 27, 36, SpanTypes.ExclusiveExclusive);
            ss.SetSpan(new ForegroundColorSpan(Android.Graphics.Color.Red), 25, 34, SpanTypes.ExclusiveExclusive);

            //image
            //Drawable d = Resources.GetDrawable(Resource.Drawable.notification_template_icon_low_bg);
            //d.SetBounds(0, 0, d.IntrinsicWidth, d.IntrinsicHeight);
            //ImageSpan span = new ImageSpan(d,SpanAlign.Baseline);
            //ss.SetSpan(span, 35, 40, SpanTypes.ExclusiveExclusive);  //load image

            //Italic
            ss.SetSpan(new StyleSpan(TypefaceStyle.Italic), 37, 43, SpanTypes.ExclusiveExclusive);
            //BackgroundColorSpan
            ss.SetSpan(new BackgroundColorSpan(Android.Graphics.Color.Yellow), 44, 63, SpanTypes.ExclusiveExclusive);


            //text worked in EditText 
            Control.SetText(ss,TextView.BufferType.Editable);
            Control.MovementMethod = LinkMovementMethod.Instance;
        }
    }
}

The effect:

在此处输入图像描述

entry cell action on tap works on android.

public class EntryCell :  : CellBaseView, Android.Text.ITextWatcher, Android.Widget.TextView.IOnFocusChangeListener, Android.Widget.TextView.IOnEditorActionListener
{
    AiEditText _EditText;
    ...
    public EntryCellView( Context context, Cell cell ) : base(context, cell)
    {
        ...
        Click += EntryCellView_Click;
        _EditText.Click += EditTextOnClick;
        ...
    }
    
    private void EditTextOnClick( object sender, EventArgs e ) { PerformSelectAction(); }

    private void EntryCellView_Click( object sender, EventArgs e )
    {
        _EditText.RequestFocus();
        PerformSelectAction();
        ShowKeyboard(_EditText); // EntryCellView_Click
    }
    protected void PerformSelectAction()
    {
        _EditText.Cell = _EntryCell;
        switch ( _EntryCell.OnSelectAction )
        {
            case AiEntryCell.SelectAction.None: break;

            case AiEntryCell.SelectAction.Start:
                _EditText.SetSelection(0, 0);

                break;

            case AiEntryCell.SelectAction.End:
                _EditText.SetSelection(_EditText.Length(), _EditText.Length());

                break;

            case AiEntryCell.SelectAction.All:
                _EditText.SelectAll();

                break;

            default: throw new ArgumentOutOfRangeException();
        }
    }
    ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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