1
votes

I have a Xamarin Forms Android application with the Material Design Visual. That seems to override the cursor color to black. Now I would like to create a dark theme. On IOS the cursor color changes with the font color to white. But on Android it stays black which makes it barely visible. Is there a way that I can override the color set as the cursor color?

Based on this Forum discussion I tried this Effect: https://forums.xamarin.com/discussion/42823/change-entry-cursor

    protected override void OnAttached()
    {
        try
        {
            IntPtr IntPtrtextViewClass = JNIEnv.FindClass(typeof(TextView));
            IntPtr mCursorDrawableResProperty = JNIEnv.GetFieldID(IntPtrtextViewClass, "mCursorDrawableRes", "I");
            JNIEnv.SetField(Control.Handle, mCursorDrawableResProperty, Resource.Drawable.custom_cursor);
        }
        catch (Exception e) {
            Console.WriteLine(e);
        }
    }

cursor drawable:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">

  <solid android:color="@color/colorAccent"></solid>
  <size android:width="2dp" />

</shape>

But with that the app crashes with the following error in the output:

JNI DETECTED ERROR IN APPLICATION: jfieldID int android.widget.TextView.mCursorDrawableRes not valid for an object of class md5a6256f8d5bc17d3565a450e514d4a6e7.MaterialFormsTextInputLayout
1
Xamarin Forms doesn't expose any api for control cursor color, you would have to create an Effect to change that behavoir.FabriBertani
@FabriBertani Thanks for your response! I tried to create an effect, but so far no success. I added the last version to my original post. Maybe you have an idea what is wrong.NPadrutt
Could you please post the demo of the effect you have you tried ?Jessie Zhang -MSFT

1 Answers

0
votes

I ended up with a custom renderer for the entry.

[assembly: ExportRenderer(typeof(Entry), typeof(CustomEntryRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
namespace MoneyFox.Droid.Renderer
{
    public class CustomEntryRenderer : MaterialEntryRenderer
    {
        public CustomEntryRenderer(Context context) : base(context) {
        }

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

            // set cursor color
            IntPtr IntPtrtextViewClass = JNIEnv.FindClass(typeof(TextView));
            IntPtr mCursorDrawableResProperty = JNIEnv.GetFieldID(IntPtrtextViewClass, "mCursorDrawableRes", "I");

            JNIEnv.SetField(Control.EditText.Handle, mCursorDrawableResProperty, Resource.Drawable.CustomCursor);

            // try set cursor pointer color
            try
            {
                TextView textViewTemplate = new TextView(Control.EditText.Context);

                var field = textViewTemplate.Class.GetDeclaredField("mEditor");
                field.Accessible = true;
                var editor = field.Get(Control.EditText);

                String[]
                    fieldsNames = { "mTextSelectHandleLeftRes", "mTextSelectHandleRightRes", "mTextSelectHandleRes" },
                    drawablesNames = { "mSelectHandleLeft", "mSelectHandleRight", "mSelectHandleCenter" };

                for (Int32 index = 0; index < fieldsNames.Length && index < drawablesNames.Length; index++)
                {
                    String
                        fieldName = fieldsNames[index],
                        drawableName = drawablesNames[index];

                    field = textViewTemplate.Class.GetDeclaredField(fieldName);
                    field.Accessible = true;
                    Int32 handle = field.GetInt(Control.EditText);

                    Drawable handleDrawable = Resources.GetDrawable(handle, null);

                    handleDrawable.SetColorFilter(Color.Accent.ToAndroid(), PorterDuff.Mode.SrcIn);

                    field = editor.Class.GetDeclaredField(drawableName);
                    field.Accessible = true;
                    field.Set(editor, handleDrawable);
                }
            } 
            catch (Exception ex)
            {
                LogManager.GetCurrentClassLogger().Error(ex);
            }
        }
    }
}

There I was able to call Control.EditText.Handle, which accesses the native control. Unfortunately this is not accessible for effects.