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:
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 :