Placeholder Editor

How can I have a placeholder in an Editor in the same way as I can in an Entry field ?

Regards

Best Answer

Answers

  • MohammadAkbarMohammadAkbar FRUniversity
    edited January 2015

    No, you can't. The only solution is add a litle label just above your Editor to describe that Editor.

  • JMarcusJMarcus USMember ✭✭✭

    For android you can implement a custom renderer that inherits from EditorRenderer and sets Hint on the underlying EditText.

  • DarioLipariDarioLipari USMember ✭✭

    Hi,

    I written a MyEditor class that extend Editor base class in a XamarinForm portable project.
    I written a EditorRenderer for MyEditor that manage UITextViewDelegate editing events to create a placeholder.

    Placeholder works, but binding to and from xamarin form MyEditor instance is broken...

    Create a placeholder for UITextView in native iOS implementation is done by create a class that extend UITextViewDelegate and set an instance of that class as delegate of UITextView instance.
    This doesn't work in a Renderer.

    Can anyone tell me why?

    `

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using Foundation;
        using UIKit;
        using Xamarin.Forms;
        using Xamarin.Forms.Platform.iOS;
        using CoreGraphics;
    
        [assembly: ExportRenderer(typeof(SecureDrive.MyEditor), typeof(SecureDrive.iOS.EditorRender))]
    
        namespace SecureDrive.iOS
        {
            public class EditorRender : EditorRenderer
            {
                protected override void OnElementChanged(ElementChangedEventArgs<Editor> e) {
                    base.OnElementChanged(e);
                    var field = this.Control;
                    var del = new myTextViewDelegate();
                    del.Placeholder = "Scrivi il tuo messaggio";
                    field.Delegate = del;
                    field.TextColor = UIColor.LightGray;
                    field.Text = del.Placeholder;
                    field.Tag = 1000;
                }
            }
    
            public class myTextViewDelegate : UITextViewDelegate
            {
                public string Placeholder { get; set; }
    
                public override void EditingStarted(UITextView textView) {
                    if (textView.Text == Placeholder) {
                        textView.Text = "";
                        textView.TextColor = UIColor.Black;
                    }
                    textView.BecomeFirstResponder();
    
                    UIView view = getRootSuperView(textView);
    
                    CGRect rect = view.Frame;
    
                    rect.Y -= 80;
    
                    view.Frame = rect;
    
                }
    
                private UIView getRootSuperView(UIView view) {
                    if (view.Superview == null)
                        return view;
                    else
                        return getRootSuperView(view.Superview);
                }
    
                public override void EditingEnded(UITextView textView) {
                    if (textView.Text == "") {
                        textView.Text = Placeholder;
                        textView.TextColor = UIColor.LightGray;
                    }
                    textView.ResignFirstResponder();
    
                    UIView view = getRootSuperView(textView);
    
                    CGRect rect = view.Frame;
    
                    rect.Y += 80;
    
                    view.Frame = rect;
    
                }
            }
        }
    

    `

  • I have fixed a problem in you code. And It work!

    public class PlaceholderEditorRenderer : EditorRenderer
    {
        UILabel labelPlaceHolder;
        UITextView replacingControl;
    
        protected override void OnElementChanged(ElementChangedEventArgs<Editor> e) {
                base.OnElementChanged(e);
                        replacingControl = new UITextView (Control.Bounds);
                        var adelegate = new myTextViewDelegate();
                        var element = this.Element as PlaceholderEditor;
    
                        adelegate.Placeholder = element.Placeholder;
    
                        replacingControl.Delegate = adelegate;
                        replacingControl.TextColor = UIColor.LightGray;
                        replacingControl.Text = adelegate.Placeholder;
    
                        this.SetNativeControl (replacingControl);
    
                }
        }
    
        public class myTextViewDelegate : UITextViewDelegate
        {
            public string Placeholder { get; set; }
    
            public override void EditingStarted(UITextView textView) {
                if (textView.Text == Placeholder) {
                    textView.Text = "";
                    textView.TextColor = UIColor.Black;
                }
                textView.BecomeFirstResponder();
    
                UIView view = getRootSuperView(textView);
    
                CGRect rect = view.Frame;
    
                rect.Y -= 80;
    
                view.Frame = rect;
    
            }
    
            private UIView getRootSuperView(UIView view) {
                if (view.Superview == null)
                    return view;
                else
                    return getRootSuperView(view.Superview);
            }
    
            public override void EditingEnded(UITextView textView) {
                if (textView.Text == "") {
                    textView.Text = Placeholder;
                    textView.TextColor = UIColor.LightGray;
                }
                textView.ResignFirstResponder();
    
                UIView view = getRootSuperView(textView);
    
                CGRect rect = view.Frame;
    
                rect.Y += 80;
    
                view.Frame = rect;
    
            }
    }
    
  • AndyBarajasAndyBarajas USMember ✭✭
    edited November 2015

    The code above worked for a bit then I encountered a problem related to this thread: https://forums.xamarin.com/discussion/39470/installed-5-9-build-431-event-registration-is-overwriting-existing-delegate-error/p1 (Overwriting delegates)

    I was able to rewrite the code and simplify to this:

    public class PlaceholderEditorRenderer : EditorRenderer
        {
            private string Placeholder { get; set; }
    
            protected override void OnElementChanged(ElementChangedEventArgs<Editor> e) {
                base.OnElementChanged(e);
                var element = this.Element as PlaceholderEditor;
    
                if (Control != null && element != null) {
                    Placeholder = element.Placeholder;
                    Control.TextColor = UIColor.LightGray;
                    Control.Text = Placeholder;
    
                    Control.ShouldBeginEditing += (UITextView textView) => { 
                        if (textView.Text == Placeholder) {
                            textView.Text = "";
                            textView.TextColor = UIColor.Black; // Text Color
                        }
    
                        return true; 
                    };
    
                    Control.ShouldEndEditing += (UITextView textView) => {
                        if (textView.Text == "") {
                            textView.Text = Placeholder;
                            textView.TextColor = UIColor.LightGray; // Placeholder Color
                        }
    
                        return true;
                    };
                }
            }
        }
    
    
  • Hi,

    This is working fine in Android and iOS. But how to do in Windows and how to write a renderer in windows?

  • farhatfarhat INMember

    @dpedrinha your answer is life saver...and i agree with your point
    "And if there are not placeholders on native components, why not implement this solution to forms? Simple, flawless and elegant."

  • You can do the same with Focused and UnFocused attributes of an editor field in the Xamarin Forms:

            content.Children.Add(new Label
                        {
                            Text = "Hours Per Day",
                            HorizontalOptions = LayoutOptions.CenterAndExpand,
                            WidthRequest = deltaWidth,
                            HeightRequest = deltaHt,
                            FontSize = 20,
                            VerticalTextAlignment = TextAlignment.Center
                        });
                        Editor editor = new Editor
                        {
                            TextColor = Color.Aqua,
                            Text = "Placeholder",
                            WidthRequest = deltaWidth,
                            HeightRequest = Constant.ScreenHeight * 0.35f,
                            HorizontalOptions = LayoutOptions.CenterAndExpand,
                        };
                        editor.Focused += (object sender, FocusEventArgs e) => { 
                            Editor edit = ((Editor)sender);
                            if (edit.Text == "Placeholder")
                            {
                                edit.Text = "";
                                edit.TextColor = Color.Black;
                            }
                        };
                        editor.Unfocused += (sender, e) => { 
                            Editor edit = ((Editor)sender);
                            if (edit.Text == "")
                            {
                                edit.Text = "Placeholder";
                                edit.TextColor = Color.Aqua;
                            }
                        };
                        content.Children.Add(editor);
    
  • iOS renderer with UILabel as Placeholder.

    public class ExtendedEditorRenderer : EditorRenderer
    {
        private UIColor DefaultPlaceholderColor { get; set; } = Color.FromRgb(199, 199, 205).ToUIColor();
        private UILabel PlaceholderLabel { get; set; }
    
        protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
        {
            base.OnElementChanged(e);
    
            if (Control == null) return;
    
            if (PlaceholderLabel != null) return;
    
            var element = Element as ExtendedEditor;
    
            PlaceholderLabel = new UILabel
            {
                Text = element?.Placeholder,
                TextColor = DefaultPlaceholderColor,
                BackgroundColor = UIColor.Clear
            };
    
            var edgeInsets = Control.TextContainerInset;
            var lineFragmentPadding = Control.TextContainer.LineFragmentPadding;
    
            Control.AddSubview(PlaceholderLabel);
    
            var vConstraints = NSLayoutConstraint.FromVisualFormat(
                "V:|-" + edgeInsets.Top + "-[PlaceholderLabel]-" + edgeInsets.Bottom + "-|", 0, new NSDictionary(),
                NSDictionary.FromObjectsAndKeys(
                    new NSObject[] { PlaceholderLabel }, new NSObject[] { new NSString("PlaceholderLabel") })
            );
    
            var hConstraints = NSLayoutConstraint.FromVisualFormat(
                "H:|-" + lineFragmentPadding + "-[PlaceholderLabel]-" + lineFragmentPadding + "-|",
                0, new NSDictionary(),
                NSDictionary.FromObjectsAndKeys(
                    new NSObject[] { PlaceholderLabel }, new NSObject[] { new NSString("PlaceholderLabel") })
            );
    
            PlaceholderLabel.TranslatesAutoresizingMaskIntoConstraints = false;
    
            Control.AddConstraints(hConstraints);
            Control.AddConstraints(vConstraints);
        }
    
        protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
    
            if (e.PropertyName == "Text")
            {
                PlaceholderLabel.Hidden = !string.IsNullOrEmpty(Control.Text);
            }
        }
    }
    
  • HaenggHaengg INMember ✭✭

    @dpedrinha you answer work but it cause below issue.

    when we focused editor appearing to have focus with a flashing cursor. but editor needs tapping a second time before the keyboard is presented.

    Any Solution of that ?

  • LongNguyen.6612LongNguyen.6612 USMember

    @Carl-Johan Lindgren, you are my life-saver. Thank you, it works!

  • yasiralijavedyasiralijaved PKUniversity ✭✭

    Set the placeholder string to your Editor's Text in Xaml
    Then in Code behind file:

    InitializeComponent();
    
    var placeholder = myEditor.Text;
    
    myEditor.Focused += (sender, e) =>
    {
         // Set the editor's text empty on focus, only if the place 
         // holder is present
         if (myEditor.Text.Equals(placeholder))
         {
              myEditor.Text = string.Empty;
              // Here You can change the text color of editor as well
              // to active text color
         }
    };
    
    myEditor.Unfocused += (sender, e) => 
    {
         // Set the editor's text to place holder on unfocus, only if 
         // there is no data entered in editor
        if (string.IsNullOrEmpty(myEditor.Text.Trim()))
        {
            myEditor.Text = placeholder;
            // Here You can change the text color of editor as well
            // to dim text color (Text Hint Color)
        }
    };
    
  • rugairugai BRMember ✭✭

    @dtaylorus said:
    Here you go (Android control and renderer):

    public class PlaceholderEditor : Editor
    {
        public static readonly BindableProperty PlaceholderProperty =
            BindableProperty.Create<PlaceholderEditor, string>(view => view.Placeholder, String.Empty);
    
        public PlaceholderEditor()
        {
        }
    
        public string Placeholder
        {
            get
            {
                return (string)GetValue(PlaceholderProperty);
            }
    
            set
            {
                SetValue(PlaceholderProperty, value);
            }
        }
    }
    
    public class PlaceholderEditorRenderer : EditorRenderer
    {
        public PlaceholderEditorRenderer()
        {
        }
    
        protected override void OnElementChanged(
            ElementChangedEventArgs<Editor> e)
        {
            base.OnElementChanged(e);
    
            if (e.NewElement != null)
            {
                var element = e.NewElement as PlaceholderEditor;
                this.Control.Hint = element.Placeholder;
            }
        }
    
        protected override void OnElementPropertyChanged(
            object sender,
            PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
    
            if (e.PropertyName == PlaceholderEditor.PlaceholderProperty.PropertyName)
            {
                var element = this.Element as PlaceholderEditor;
                this.Control.Hint = element.Placeholder;
            }
        }
    }
    

    Also, I added this this.Control.SetHintTextColor(element.TextColor.ToAndroid()); so that we have the same placeholder color as TextColor

  • HimelNathHimelNath USMember

    @Haengg said:
    @dpedrinha you answer work but it cause below issue.

    when we focused editor appearing to have focus with a flashing cursor. but editor needs tapping a second time before the keyboard is presented.

    Any Solution of that ?

    Same issue

  • Sanjay_RajputSanjay_Rajput USMember ✭✭
    edited November 2017

    :) thank you

  • NickTsimourtosNickTsimourtos USMember ✭✭

    hello...
    is there any example with placeholder editor?
    because i try to make one but i have error with brake state

  • ShrutiGoyal.5169ShrutiGoyal.5169 USMember ✭✭
    edited February 2018

    @NickTsimourtos

    IN PCL
    public class PlaceholderEditor : Editor
    {
    public static readonly BindableProperty PlaceholderProperty =
    BindableProperty.Create<PlaceholderEditor, string>(view => view.Placeholder, String.Empty);

        public PlaceholderEditor()
        {
           // this.TextChanged += (sender, e) => { this.InvalidateMeasure(); }; 
        }
    
        public string Placeholder
        {
            get
            {
                return (string)GetValue(PlaceholderProperty);
            }
    
            set
            {
                SetValue(PlaceholderProperty, value);
            }
        }
    }
    

    **
    In Android**

    public class PlaceholderEditorRenderer: EditorRenderer
    {
    public PlaceholderEditorRenderer()
    {

        }
    
        protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
        {
            base.OnElementChanged(e);
            if (e.NewElement != null)
            {
                var element = e.NewElement as PlaceholderEditor;
                this.Control.Hint = element.Placeholder;
                this.Control.SetHintTextColor(Android.Graphics.Color.ParseColor("#727272"));
                Control.Gravity = Android.Views.GravityFlags.Start;
                Control.SetBackgroundColor(global::Android.Graphics.Color.Transparent);
                Control.SetPadding(0, 0, 0, 0);
    
                var nativeEditText = (global::Android.Widget.EditText)Control;
                //While scrolling inside Editor stop scrolling parent view.
                nativeEditText.OverScrollMode = OverScrollMode.Always;
                nativeEditText.ScrollBarStyle = ScrollbarStyles.InsideInset;
                nativeEditText.SetOnTouchListener(new DroidTouchListener());
    
                //For Scrolling in Editor innner area
                Control.VerticalScrollBarEnabled = true;
                Control.MovementMethod = ScrollingMovementMethod.Instance;
                Control.ScrollBarStyle = Android.Views.ScrollbarStyles.InsideInset;
                //Force scrollbars to be displayed
                Android.Content.Res.TypedArray a = Control.Context.Theme.ObtainStyledAttributes(new int[0]);
                InitializeScrollbars(a);
                a.Recycle();
            }
        }
    
    }
    

    Add Class in android fro scrolling in editor

    public class DroidTouchListener : Java.Lang.Object, View.IOnTouchListener
    {
    public bool OnTouch(View v, MotionEvent e)
    {
    v.Parent?.RequestDisallowInterceptTouchEvent(true);
    if ((e.Action & MotionEventActions.Up) != 0 && (e.ActionMasked & MotionEventActions.Up) != 0)
    {
    v.Parent?.RequestDisallowInterceptTouchEvent(false);
    }
    return false;
    }
    }

    In iOS

    public class PlaceholderEditorRenderer : EditorRenderer
    {
    private UIColor DefaultPlaceholderColor { get; set; } = Color.FromRgb(199, 199, 205).ToUIColor();
    private UILabel PlaceholderLabel { get; set; }

        protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
        {
            base.OnElementChanged(e);
    
            if (Control == null) return;
    
            if (PlaceholderLabel != null) return;
    
            var element = Element as PlaceholderEditor;
            Control.ScrollEnabled = true;
            PlaceholderLabel = new UILabel
            {
                Text = element?.Placeholder,
                TextColor = DefaultPlaceholderColor,
                BackgroundColor = UIColor.Clear
            };
    
            var edgeInsets = Control.TextContainerInset;
            var lineFragmentPadding = Control.TextContainer.LineFragmentPadding;
    
            Control.AddSubview(PlaceholderLabel);
    
            var vConstraints = NSLayoutConstraint.FromVisualFormat(
                "V:|-" + edgeInsets.Top + "-[PlaceholderLabel]-" + edgeInsets.Bottom + "-|", 0, new NSDictionary(),
                NSDictionary.FromObjectsAndKeys(
                    new NSObject[] { PlaceholderLabel }, new NSObject[] { new NSString("PlaceholderLabel") })
            );
    
            var hConstraints = NSLayoutConstraint.FromVisualFormat(
                "H:|-" + lineFragmentPadding + "-[PlaceholderLabel]-" + lineFragmentPadding + "-|",
                0, new NSDictionary(),
                NSDictionary.FromObjectsAndKeys(
                    new NSObject[] { PlaceholderLabel }, new NSObject[] { new NSString("PlaceholderLabel") })
            );
    
            PlaceholderLabel.TranslatesAutoresizingMaskIntoConstraints = false;
    
            Control.AddConstraints(hConstraints);
            Control.AddConstraints(vConstraints);
        }
    
        protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
    
            if (e.PropertyName == "Text")
            {
                PlaceholderLabel.Hidden = !string.IsNullOrEmpty(Control.Text);
            }
        }
    }
    

    This code worked for me.Try Once

  • MuthuramMuthuram Member ✭✭

    Hi Try This One.
    `public MainPage ()
    {

            InitializeComponent ();
            NotesEditor.Text = "Notes";
            NotesEditor.TextColor = Color.Blue;
    
        }
        private void NotesFocused(Object sender, FocusEventArgs e)
        {
            NotesEditor.Text = "";
            NotesEditor.TextColor = Color.Green;
        }
        private void NotesUnFocusedd(object sender, FocusEventArgs e)
        {
            if (NotesEditor.Text.Equals(""))
            {
                NotesEditor.Text = "Notes";
                NotesEditor.TextColor = Color.Blue;
            }
        }`
    
  • AmroOsama.1516AmroOsama.1516 SAMember ✭✭

    @Haengg, @HimelNath
    for those who have a problem with the keyboard dissapearing after clearing the text in the Editor_Focused event,

    after clearing the text, just show the keyboard manually.

    in my PCL project, I have an interface, with a method called ShowKeyboard,

    In the Android project, I implement the interface and the method is as following:

    public void KeyboardShow()
    {
        var context = CrossCurrentActivity.Current.Activity;//Forms.Context;
    
        var inputMgr = context?.GetSystemService(Context.InputMethodService) as InputMethodManager;
    
        var token = context?.CurrentFocus?.WindowToken;
    
        inputMgr?.ShowSoftInputFromInputMethod(token,  ShowFlags.Forced);
    }
    

    for IOS:

    public void KeyboardShow()
    {
        UIApplication.SharedApplication.KeyWindow.BecomeFirstResponder();
    }
    
  • truXtontruXton Member

    without write custom renderer

                                <Grid>
    
                                    <Editor
                                        Grid.Row="0"
                                        x:Name="myEditor"
                                        AutoSize="TextChanges"
                                        TextColor="Black"
                                        FontSize="15"
                                        FontFamily="{StaticResource OpenSans}">
                                    </Editor>
    
                                    <Label
                                        Grid.Row="0"                                        
                                        Text="Hello from Xamarin"
                                        TextColor="Grey"
                                        FontSize="15"
                                        FontFamily="{StaticResource OpenSans}"
                                        IsVisible="False"
                                        InputTransparent="True"
                                        VerticalOptions="Center">
    
                                        <Label.Triggers>
                                            <DataTrigger
                                                TargetType="Label"
                                                Binding="{Binding Source={x:Reference myEditor}, Path=Text, TargetNullValue=''}"
                                                Value="">
                                                <Setter
                                                    Property="IsVisible"
                                                    Value="True">
                                                </Setter>
                                            </DataTrigger>
                                        </Label.Triggers>
    
                                    </Label>
    
                                </Grid>
    
Sign In or Register to comment.