Xamarin.forms анимация и PropertyChanged
новичок в Xamarin. У меня есть представление Page.xaml содержащий:
<Label Text="{Binding GetValue}" />
В коде Page.xaml.cs при инициализации контекст устанавливается следующим образом:
BindingContext = PageViewModel
В классе PageViewModel есть свойство:
private string _value;
public string GetValue
{
get
{
return _value;
}
set
{
_value = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("GetValue"));
}
}
Если меняется свойство, то в представлении все нормально отображается изменение, но я никак не могу реализовать анимацию смены значения, например мне нужно что бы при смене GetValue, текст со старым значением плавно исчезал, потом новый плавно появлялся. Плавное появление я реализовал с помощью PropertyChanged у Label:
async void Label_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
var label = sender as Label;
if (e.PropertyName == "Text")
{
label.Opacity = 0;
await label.FadeTo(1, 2000, Easing.CubicInOut);
}
}
Значение мгновенно исчезает и новое плавно появляется. Так вот собственно вопрос, как реализовать плавное исчезновение Label до того как произойдет смена свойства и начнет работать приведенный выше код появления, не нарушая MVVM Pattern? Рассматривал вариант Behaviors и Triggers, но там ничего путного не нашел, такое чувство что во viewmodel до того как менять свойства нужно вызвать метод анимации и дождаться её окончания, но я никак не могу понять как это реализуется не нарушая MVVM. Рассматривал еще MessageCenter, что бы послать сообщение, но в данном случае непонятно как дождаться результат анимации.
Ответы (2 шт):
Данную функциональность можно реализовать с помощью такого класса поведения
public class LabelAnimationBehavior : Behavior<Label>
{
protected override void OnAttachedTo(Label label)
{
label.PropertyChanging += Label_PropertyChanging;
label.PropertyChanged += Label_PropertyChanged;
base.OnAttachedTo(label);
}
protected override void OnDetachingFrom(Label label)
{
label.PropertyChanging -= Label_PropertyChanging;
label.PropertyChanged -= Label_PropertyChanged;
base.OnDetachingFrom(label);
}
private async void Label_PropertyChanging(object sender, PropertyChangingEventArgs e)
{
if (e.PropertyName != "Text")
return;
await (sender as Label).Opacity = 0;
await Task.Delay(1000);
}
private async void Label_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName != "Text")
return;
await (sender as Label).FadeTo(1, 2000);
}
}
Разметка страницы такая
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:App1"
x:Class="App1.MainPage">
<ContentPage.BindingContext>
<vm:MainViewModel />
</ContentPage.BindingContext>
<Grid Padding="5" RowDefinitions="*,*">
<Label Grid.Row="0"
FontSize="Header"
HorizontalOptions="Center"
Text="{Binding Value}">
<Label.Behaviors>
<vm:LabelAnimationBehavior/>
</Label.Behaviors>
</Label>
<Button Text="Click Me"
Grid.Row="1"
Command="{Binding ClickCommand}"/>
</Grid>
</ContentPage>
Класс въюмодели
public class MainViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private static int _counter = 0;
public MainViewModel()
{
ClickCommand = new Command(() =>
{
++_counter;
Value = _counter.ToString();
});
}
private string _Value = _counter.ToString();
public string Value
{
get => _Value;
set
{
_Value = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
}
}
public ICommand ClickCommand { get; }
}
Еще вариант
public static class AnimationFadePropertyHelper
{
public static readonly BindableProperty TextProperty = BindableProperty.CreateAttached("Text", typeof(String), typeof(AnimationFadePropertyHelper), null, propertyChanged: OnTextChanged);
public static string GetText (BindableObject view)
{
return (string)view.GetValue(TextProperty);
}
public static void SetText(BindableObject view, string value)
{
view.SetValue(TextProperty, value);
}
async static void OnTextChanged(BindableObject view, object oldValue, object newValue)
{
if (view == null)
return;
var text = view as Label;
await text.FadeTo(0, 1500);
text.Text = (string)newValue;
await text.FadeTo(1, 1500);
}
}
Применение: <Label helper:AnimationFadePropertyHelper.Text="{Binding Word}" />
