Xamarin形成数字形式的动画增加/减少作为标签文本

时间:2018-12-19 01:57:16

标签: xamarin.forms

我有一个Label,其Text属性是一个数值。当该数字更改时,我想为数字更改添加动画效果。因此,例如,如果“文本”设置为100并更改为120,我想显示它每100毫秒从100递增到101到102等,直到达到新值120。

我可以在背后的代码中手动完成此操作,但是由于我使用的是MVVM,因此我想找到一种在XAML中执行此操作的方法(例如行为,效果等)。我确定我也可以通过使用自定义渲染器来做到这一点,但是感觉应该有一种我不知道的更简单的方法来做到这一点。有什么想法吗?

谢谢!

2 个答案:

答案 0 :(得分:0)

我有有效的代码,以防其他人使用。希望有人会发布更好的答案,但这至少现在对我有用。

我创建了一个行为,用于监视Label上的PropertyChanged事件。当Text属性更改时,我将标签的新值解析为long并将其与标签的先前值进行比较。如果两者之间存在差异,我将在每次等待时将Task.Delay(300)递增一次,以使计数减慢。我使用静态字典来跟踪先前的值。下面的工作代码-尽管仍在测试中...

public class LabelHighlightAndStepOnChangeBehavior : Behavior<Label>
{
    public int EndHighlightDuration { get; set; } = 3000;

    public string Property { get; set; }

    public static Dictionary<string, long> _previousValues = new Dictionary<string, long>();

    private bool _watchingTextChanges = true;

    protected override void OnAttachedTo(Label element)
    {
        try
        {
            element.PropertyChanged += Label_PropertyChanged;
            base.OnAttachedTo(element);
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, false);
        }
    }

    private async void Label_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        try
        {
            if (_watchingTextChanges && e.PropertyName == nameof(Label.Text))
            {
                _watchingTextChanges = false;
                var label = (Label)sender;
                var model = label.BindingContext as BaseModel;
                var key = model.Id + Property;

                if (_previousValues.ContainsKey(key) && _previousValues[key] != model.GetPropertyValue<long>(Property))
                {
                    // Change background color.
                    var originalBackgroundColor = label.BackgroundColor;
                    label.BackgroundColor = Color.Yellow;

                    // Step the number up or down to the new value.
                    var originalValue = _previousValues[key];
                    var newValue = model.GetPropertyValue<long>(Property);
                    _previousValues[key] = newValue;

                    if (originalValue < newValue)
                    {
                        var step = Math.Max(1, Convert.ToInt32((newValue - originalValue) / 50.0) - 1);
                        while (originalValue < newValue)
                        {
                            if ((originalValue + step) <= newValue)
                                originalValue += step;
                            else
                                originalValue = newValue;

                            model.SetPropertyValue<long>(Property, originalValue);
                            await Task.Delay(50);
                        }
                    }
                    else if (originalValue > newValue)
                    {
                        var step = -Math.Max(1, Convert.ToInt32((originalValue - newValue) / 50.0) - 1);
                        while (originalValue > newValue)
                        {
                            if ((originalValue + step) <= newValue)
                                originalValue += step;
                            else
                                originalValue = newValue;

                            model.SetPropertyValue<long>(Property, originalValue);
                            await Task.Delay(50);
                        }
                    }

                    // Change the background color back.
                    await Task.Delay(EndHighlightDuration);
                    label.BackgroundColor = originalBackgroundColor;
                }
                else if (!_previousValues.ContainsKey(key))
                {
                    _previousValues.Add(key, model.GetPropertyValue<long>(Property));
                }
            }
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, false);
        }
        finally
        {
            _watchingTextChanges = true;
        }
    }

    protected override void OnDetachingFrom(Label element)
    {
        try
        {
            element.PropertyChanged -= Label_PropertyChanged;
            base.OnDetachingFrom(element);
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, false);
        }
    }
}

答案 1 :(得分:0)

您可以使用Animation类在开始值和结束值之间更改数字,使用缓动功能指定数字更改的发生方式以及持续时间。

然后您可以将标签绑定到一个“金额”属性,设置一个_targetAmount,然后使用所需的动画属性在当前金额和_targetAmount之间设置“金额”动画。标签将通过绑定进行相应的更新。

要为视图模型上的属性设置动画,必须首先将视图模型类标记为IAnimatable。然后只需设置_targetAmount并调用AnimateAmountChange()即可以动画样式更新标签。

    private void AnimateAmountChange()
    {
        var change = new Animation(x => Amount = (int)x, Amount, _targetAmount);
        change.Commit(this, "ChangeAmount", 10, 300, Easing.SinOut);
    }

    #region IAnimatable
    public void BatchBegin()
    {
    }

    public void BatchCommit()
    {
    }
    #endregion