Xamarin.forms: [Bug] iOS - Horizontal scroll bar appears on editor unnecessarily

Created on 6 Mar 2020  路  16Comments  路  Source: xamarin/Xamarin.Forms

Description

When adding an editor to a blank app and giving it a certain amount of text a horizontal scroll bar is renderered when there is no text to scroll to

Steps to Reproduce

  1. Create a new forms app
  2. Add an editor to the content page with Text set to first paragraph of Lorem Ipsum
  3. Load the app in iOS and scroll horizontally

Expected Behavior

Editor shouldn't scroll horizontally

Actual Behavior

Editor does scroll horizontally

Basic Information

  • Version with issue: 4.3.0.908675
  • Last known good version: Unknown
  • IDE: Visual Studio 2019
  • Platform Target Frameworks:

    • iOS: 13.X

  • Nuget Packages:
  • Affected Devices: iPhone 11, iPhone 6s iOS 10

Screenshots


image

Reproduction Link


AutoSizeBug.zip

Workaround

editor 5 iOS 馃崕 bug

Most helpful comment

Thank you jensbrobak !
The solution above does not display correctly the placeholder when set though, so I modified it as below ;)

```C#
private UILabel placeholderLabel;
private NSLayoutConstraint[] vConstraints;
private NSLayoutConstraint[] hConstraints;

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        if (e.PropertyName != nameof(CustomEditor.Text))
            return;

        if (Element == null || Control == null)
            return;

        CustomEditor editor = (CustomEditor)Element;
        if (editor.Text != "")
        {
            if (placeholderLabel == null)
                FixHorizontalScroll();
        }
        else
        {
            if (placeholderLabel != null)
                UndoFixHorizontalScroll();
        }
    }

    private void UndoFixHorizontalScroll()
    {
        placeholderLabel.RemoveFromSuperview();
        placeholderLabel = null;

        Control.RemoveConstraints(vConstraints);
        vConstraints = null;

        Control.RemoveConstraints(hConstraints);
        hConstraints = null;
    }

    private void FixHorizontalScroll()
    {
        placeholderLabel = new UILabel();

        UIEdgeInsets edgeInsets = Control.TextContainerInset;
        nfloat lineFragmentPadding = Control.TextContainer.LineFragmentPadding;

        Control.AddSubview(placeholderLabel);

        vConstraints = NSLayoutConstraint.FromVisualFormat(
            "V:|-" + edgeInsets.Top + "-[PlaceholderLabel]-" + edgeInsets.Bottom + "-|", 0, new NSDictionary(),
            NSDictionary.FromObjectsAndKeys(
                new NSObject[] { placeholderLabel }, new NSObject[] { new NSString("PlaceholderLabel") })
        );

        hConstraints = NSLayoutConstraint.FromVisualFormat(
            "H:|-" + lineFragmentPadding + "-[PlaceholderLabel]-" + lineFragmentPadding + "-|",
            0, new NSDictionary(),
            NSDictionary.FromObjectsAndKeys(
                new NSObject[] { placeholderLabel }, new NSObject[] { new NSString("PlaceholderLabel") })
        );

        placeholderLabel.TranslatesAutoresizingMaskIntoConstraints = true;

        Control.AddConstraints(hConstraints);
        Control.AddConstraints(vConstraints);

        Control.SetNeedsLayout();
        Control.LayoutIfNeeded();
    }

```

All 16 comments

Still happening on 4.5.

I am seeing the same thing. Does anyone know if this is in process or if there is a work around?

Additional learnings:

  1. The vertical scroll is broken so if your text is longer than the Editor, it will not scroll vertically
  2. If the user adds a return or you insert '\n' to the text, it behaves correctly.
  3. If you roll back to Xamarin Forms 4.2 (currently on 4.5), the horizontal scroll goes away, but the vertical scroll still does not work

Hm this reminds me a little of this issue too #8569 maybe the simple workaround is to not use a placeholder if you have any?

I am also dealing with the same issue. I don't have any placeholder In my Editor. but still when I add long text in the editor I am getting horizontal scroll bar instead of vertical in iOS. My Xamarin Forms version is 4.4.0.991640. This makes my editor unusable. Please help me in resolving this

Hey jfversluis - I am also not using placeholder text - even tried setting placeholder text to "" in the TextChanged event which didn't help either.

Setting RemovePlaceholderConstraints="True" helped me to resolve this.

Hi sathyadg - Thanks for the input! Is that a property of the Editor class? Can you give me any more information on how to do that?

This is affecting us in production, is there a timeline on when it will be fixed?

We're able to prevent horizontal scrolling by messing about with ContentOffset and ShowsHorizontalScrollIndicator, however it's still not possible to scroll vertically. As you can imagine, this is a showstopping bug for an app that relies heavily on text entry.

A viable workaround in the meantime would also be useful.

We ended up releasing by adding a '\r' at the beginning of the text in the editor and then covering up to first 'line' of text in the editor with a label so the prepended CR wouldn't be visible. Awkward, but workable and for the most part not noticed by our clients. Shout out to Perry on my team for such a creative workaround!

We ended up releasing by adding a '\r' at the beginning of the text in the editor and then covering up to first 'line' of text in the editor with a label so the prepended CR wouldn't be visible. Awkward, but workable and for the most part not noticed by our clients. Shout out to Perry on my team for such a creative workaround!

Nice lateral thinking 馃憦

We've managed to fix this by taking a fork of Xamarin Forms and merging this PR (https://github.com/xamarin/Xamarin.Forms/pull/9710), which seems to have done the trick.

Hopefully it'll be merged and released on the official stream soon!

We ended up releasing by adding a '\r' at the beginning of the text in the editor and then covering up to first 'line' of text in the editor with a label so the prepended CR wouldn't be visible. Awkward, but workable and for the most part not noticed by our clients. Shout out to Perry on my team for such a creative workaround!

@WillSinger Can u elaborate it more. Can this be achieved via custom render-er for editor in iOS ?

@ngalicoco - we did not create a renderer but had to adapt the concept for each scenario. It boils down to an Editor inside of a Absolute layout with a BoxView covering the first line of the editor (we put a label on top of that as the 'prompt' for the Editor).

When populating the form, add a \r at the beginning of the text and take it off when saving.

We have been able to solve this issue by implementing a custom renderer of the EditorRenderer, have a look at the snippet below:

protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
        {
            Editor editor = Element;

            base.OnElementChanged(e);

            if (Control != null && editor != null)
            {
                UILabel placeholderLabel = new UILabel();

                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 = true;

                Control.AddConstraints(hConstraints);
                Control.AddConstraints(vConstraints);
            }

Hope this helps!

Thank you jensbrobak !
The solution above does not display correctly the placeholder when set though, so I modified it as below ;)

```C#
private UILabel placeholderLabel;
private NSLayoutConstraint[] vConstraints;
private NSLayoutConstraint[] hConstraints;

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        if (e.PropertyName != nameof(CustomEditor.Text))
            return;

        if (Element == null || Control == null)
            return;

        CustomEditor editor = (CustomEditor)Element;
        if (editor.Text != "")
        {
            if (placeholderLabel == null)
                FixHorizontalScroll();
        }
        else
        {
            if (placeholderLabel != null)
                UndoFixHorizontalScroll();
        }
    }

    private void UndoFixHorizontalScroll()
    {
        placeholderLabel.RemoveFromSuperview();
        placeholderLabel = null;

        Control.RemoveConstraints(vConstraints);
        vConstraints = null;

        Control.RemoveConstraints(hConstraints);
        hConstraints = null;
    }

    private void FixHorizontalScroll()
    {
        placeholderLabel = new UILabel();

        UIEdgeInsets edgeInsets = Control.TextContainerInset;
        nfloat lineFragmentPadding = Control.TextContainer.LineFragmentPadding;

        Control.AddSubview(placeholderLabel);

        vConstraints = NSLayoutConstraint.FromVisualFormat(
            "V:|-" + edgeInsets.Top + "-[PlaceholderLabel]-" + edgeInsets.Bottom + "-|", 0, new NSDictionary(),
            NSDictionary.FromObjectsAndKeys(
                new NSObject[] { placeholderLabel }, new NSObject[] { new NSString("PlaceholderLabel") })
        );

        hConstraints = NSLayoutConstraint.FromVisualFormat(
            "H:|-" + lineFragmentPadding + "-[PlaceholderLabel]-" + lineFragmentPadding + "-|",
            0, new NSDictionary(),
            NSDictionary.FromObjectsAndKeys(
                new NSObject[] { placeholderLabel }, new NSObject[] { new NSString("PlaceholderLabel") })
        );

        placeholderLabel.TranslatesAutoresizingMaskIntoConstraints = true;

        Control.AddConstraints(hConstraints);
        Control.AddConstraints(vConstraints);

        Control.SetNeedsLayout();
        Control.LayoutIfNeeded();
    }

```

I tested the above workarounds from @jensbrobak and @akatsukle. They both work if there is no initial Text loaded into the Editor, but neither worked for me if the Text property contains some text upon loading of the control.

@mpnow
I don't have an iOS device to test at the moment, but I believe you may able to fix your use case by overriding OnElementChanged.
```C#
protected override void OnElementChanged(ElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (Element == null)
return;

CustomEditor editor = (CustomEditor)Element;
if (editor.Text != "")
    FixHorizontalScroll();

}
```

Was this page helpful?
0 / 5 - 0 ratings