Baseflow / XF-Material-Library

A Xamarin Forms library for implementing Material Design
https://baseflow.com
MIT License
647 stars 161 forks source link

MaterialTextField can't set text property #295

Open pedroreglero opened 4 years ago

pedroreglero commented 4 years ago

🐛 Bug Report

You can't set the text value of the MaterialTextField, it crashes the APP. This doesn't happen in the Simulator. Bug happening in iPhone 6S 13.3.1 and with either XF.Material 1.6.0 or 1.5.8

Expected behavior

The text value of the MaterialTextField changes.

Reproduction steps

Created a new blank Xamarin Forms solution. MainPage.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:ui="clr-namespace:XF.Material.Forms.UI;assembly=XF.Material"
             mc:Ignorable="d"
             x:Class="App1.MainPage">

    <StackLayout>
        <!-- Place new controls here -->
        <ui:MaterialTextField x:Name="txt1"></ui:MaterialTextField>
    </StackLayout>

</ContentPage>

MainPage.xaml.cs

public MainPage()
        {
            InitializeComponent();
            new Thread(new ThreadStart(() =>
            {
                Thread.Sleep(2000);
                txt1.Text = "ofdfk";
            }));
        }

Configuration

Version: 1.x

Platform:

pedroreglero commented 4 years ago

Please any help with this. Makes the plugin unusable in my device.

Thank You.

Deepfreezed commented 4 years ago

Same issue. Cannot set the text property on iOS.

mr-rikhamba commented 4 years ago
We recently started getting this issue, not sure why now all of a sudden, but based on forum search it might be related to a Xamar.iOS update. So with some guidance from other users in the forum I fixed it like this:

`       
private void SetTextFieldValues(List<MaterialSetter> controls)
{
Device.BeginInvokeOnMainThread(() =>
{
controls.ForEach(x =>
{
x.MaterialTextField.Focus();
Thread.Sleep(100);
x.MaterialTextField.SetBinding(MaterialTextField.TextProperty, new Binding($"BindingContext.{x.Value}", source: this));
//x.MaterialTextField.Unfocus();
});

controls.FirstOrDefault().MaterialTextField.Focus();
});
}
class MaterialSetter
{

public MaterialSetter(MaterialTextField materialTextField, string value)
{
MaterialTextField = materialTextField;
Value = value;
}

public MaterialTextField MaterialTextField { get; }
public string Value { get; }
}
`

And this is how I call it:
`            
SetTextFieldValues(new List<MaterialSetter>
{
new MaterialSetter(FullName, "Details.FullNames"),

});
`
pedroreglero commented 4 years ago
We recently started getting this issue, not sure why now all of a sudden, but based on forum search it might be related to a Xamar.iOS update. So with some guidance from other users in the forum I fixed it like this:

`       
private void SetTextFieldValues(List<MaterialSetter> controls)
{
Device.BeginInvokeOnMainThread(() =>
{
controls.ForEach(x =>
{
x.MaterialTextField.Focus();
Thread.Sleep(100);
x.MaterialTextField.SetBinding(MaterialTextField.TextProperty, new Binding($"BindingContext.{x.Value}", source: this));
//x.MaterialTextField.Unfocus();
});

controls.FirstOrDefault().MaterialTextField.Focus();
});
}
class MaterialSetter
{

public MaterialSetter(MaterialTextField materialTextField, string value)
{
MaterialTextField = materialTextField;
Value = value;
}

public MaterialTextField MaterialTextField { get; }
public string Value { get; }
}
`

And this is how I call it:
`            
SetTextFieldValues(new List<MaterialSetter>
{
new MaterialSetter(FullName, "Details.FullNames"),

});
`

Hi, it doesn't work for me. In the project I had it doesn't crash but it doesn't change the text either. And in a new empty project it crashes.

pedroreglero commented 4 years ago
We recently started getting this issue, not sure why now all of a sudden, but based on forum search it might be related to a Xamar.iOS update. So with some guidance from other users in the forum I fixed it like this:

`       
private void SetTextFieldValues(List<MaterialSetter> controls)
{
Device.BeginInvokeOnMainThread(() =>
{
controls.ForEach(x =>
{
x.MaterialTextField.Focus();
Thread.Sleep(100);
x.MaterialTextField.SetBinding(MaterialTextField.TextProperty, new Binding($"BindingContext.{x.Value}", source: this));
//x.MaterialTextField.Unfocus();
});

controls.FirstOrDefault().MaterialTextField.Focus();
});
}
class MaterialSetter
{

public MaterialSetter(MaterialTextField materialTextField, string value)
{
MaterialTextField = materialTextField;
Value = value;
}

public MaterialTextField MaterialTextField { get; }
public string Value { get; }
}
`

And this is how I call it:
`            
SetTextFieldValues(new List<MaterialSetter>
{
new MaterialSetter(FullName, "Details.FullNames"),

});
`

Hi, it doesn't work for me. In the project I had it doesn't crash but it doesn't change the text either. And in a new empty project it crashes.

Ok, so I downgraded to version 1.6.0 and changed:

x.MaterialTextField.SetBinding(MaterialTextField.TextProperty, new Binding($"BindingContext.{x.Value}", source: this));

with:

x.MaterialTextField.Text = x.Value;

and got it working. Than You for the help, very much appreciated

pedroreglero commented 4 years ago

Ok, so @mr-rikhamba 's workaround wasn't very stable, so I tried to fix the plugin in stead of hacking a workaround.

The problem was in the file XF-Material-Library-develop\XF.Material\UI\MaterialTextField.xaml.cs in the function AnimateToInactiveOrFocusedStateOnStart .

What I think was happening is that, this plugin uses an animation to move the placeholder to above the Entry. Becouse the page was still not loaded, the animation was making the app crash. I deleted the animation to translate the placeholder and it got fixed. The new function looks like this:

private void AnimateToInactiveOrFocusedStateOnStart(object startObject)
        {
            var placeholderEndY = -(entry.FontSize * 0.8);
            var placeholderEndFont = entry.FontSize * 0.75;

            if (!FloatingPlaceholderEnabled && string.IsNullOrEmpty(entry.Text))
            {
                placeholder.TextColor = PlaceholderColor;
            }

            if (startObject != null && !string.IsNullOrEmpty(Text))
            {
                if (placeholder.TranslationY == placeholderEndY)
                {
                    return;
                }
                entry.Opacity = 0;

                Device.BeginInvokeOnMainThread(() =>
                {

                    if (FloatingPlaceholderEnabled)
                    {
                        placeholder.TranslationY = placeholderEndY;
                        placeholder.TextColor = HasError ? ErrorColor : FloatingPlaceholderColor;
                        entry.Opacity = 1;
                    }

                    if (ShouldAnimateUnderline)
                    {
                        underline.Color = HasError ? ErrorColor : TintColor;
                        underline.HeightRequest = 1;
                        underline.HorizontalOptions = LayoutOptions.FillAndExpand;
                    }
                });

                entry.Opacity = 1;

                return;
            }

            if (startObject != null && string.IsNullOrEmpty(Text) && placeholder.TranslationY == placeholderEndY)
            {
                if (entry.IsFocused)
                {
                    return;
                }

                Device.BeginInvokeOnMainThread(() =>
                {
                    var anim = new Animation();

                    if (FloatingPlaceholderEnabled)
                    {
                        anim.Add(0.0, AnimationDuration, new Animation(v => placeholder.FontSize = v, placeholderEndFont, entry.FontSize, _animationCurve));
                        anim.Add(0.0, AnimationDuration, new Animation(v => placeholder.TranslationY = v, placeholder.TranslationY, 0, _animationCurve, () =>
                        {
                            placeholder.TextColor = PlaceholderColor;
                            entry.Opacity = 1;
                        }));
                    }

                    if (ShouldAnimateUnderline)
                    {
                        anim.Add(0.0, AnimationDuration, new Animation(v => underline.WidthRequest = v, Width, 0, _animationCurve, () => underline.HorizontalOptions = LayoutOptions.Center));
                    }

                    anim.Commit(this, "Anim2", rate: 2, length: (uint)(AnimationDuration * 1000), easing: _animationCurve);
                });
            }
        }

If any of the authors read this, you could modify it for the next release. Thank You.

mr-rikhamba commented 4 years ago

Ok great @pedroreglero , I'm glad you found the route cause for the issue, for now the hack has worked well for us but we are considering stripping it out all together in the future in favour of default XF Entry.

pedroreglero commented 4 years ago

Ok great @pedroreglero , I'm glad you found the route cause for the issue, for now the hack has worked well for us but we are considering stripping it out all together in the future in favour of default XF Entry.

I'm happy we figured this out, this plugin is great, i wanted to fix it before making a custom entry myself.

Thank you for the help.

martijn00 commented 4 years ago

@pedroreglero can you make a PR with the fix?