如何创建一个条形区域,该条形区域从左到右缓慢填充5、10或???秒? [英] How can I create a bar area that slowly fills from left to right over 5, 10 or ?? seconds?

查看:103
本文介绍了如何创建一个条形区域,该条形区域从左到右缓慢填充5、10或???秒?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有计时器的应用程序,该计时器可以计时1到300秒.目前,我将剩余时间显示为一个每秒倒数的数字.通过绑定标签vm.Timer

I have an application with a timer that can time anything from 1 - 300 seconds. Currently I show time remaining as a number that counts down every one second. It's done through the binding label vm.Timer

        App.Timer1Seconds = 10; // the value is set in code
                                // just using 10 as an example here

        while (App.Timer1Seconds > 0)
        {
            vm.Timer = App.Timer1Seconds.ToString();
            try
            {
                await Task.Delay(1000, App.tokenSource1.Token);
            }
            catch (TaskCanceledException)
            {
                App.Timer1Seconds = 0;
            }
            App.Timer1Seconds--;
        }

我想做的是将其替换为位于屏幕顶部和网格内的栏区域 ,这样看起来像这样:

What I would like to do is to replace this with a bar area at the top of the screen and inside a grid so that it looks like this:

*********************

然后

********************

然后

*******************

然后

******************

随着时间的流逝,条形的填充百分比将从完全填充线性变为完全填充,这可能是300到3秒之间的任何时间.类似于网页浏览器中检索页面时的进度条,但在这种情况下,我知道活动的确切时间.

With the % of the bar filled in going from fully filled to nothing in a linear manner over the course of the time which could be anything from 300 to 3 seconds. Something a bit similar to the progress bar in a web browser when it retrieves a page but in this case I know the exact time of the activity.

有人对如何创建它有任何想法吗?请注意,如果它需要自定义渲染器,那么我对该解决方案还可以.

Does anyone have any ideas as to how this could be created? Note that if it needs a custom renderer than I am okay with that solution.

更新:

我已经实现了Sharada的解决方案,但是我有两个小问题:

I have implemented the solution by Sharada but there are two small questions I have:

这是我的XAML代码:

Here's the code I have for my XAML:

<Grid Grid.Row="3" Grid.Column="0" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" BackgroundColor="Aqua" RowSpacing="0" Padding="0">
   <Grid.RowDefinitions>
      <RowDefinition Height="2" />
   </Grid.RowDefinitions>
   <Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
   </Grid.ColumnDefinitions>
   <local:TimerView Grid.Row="0" Grid.Column="0" StartTimerCommand="{Binding TimerStartCommand}" RemainingTime="{Binding TimeLeft}" HorizontalOptions="FillAndExpand" />
</Grid>

当它运行时,我希望进度条从右到左占据全屏.但是,它似乎只使用了大约10%的空间,如下所示:

When it runs I would like the progress bar to occupy the full screen from right to left. However it seems to only use about 10% of the space like this:

|******                                                         |
|*****                                                          |
|****                                                           |
|***                                                            |
|**                                                             |
|*                                                              |

您能建议我如何使动画从屏幕的一侧移到另一侧,然后像这样减小尺寸吗?

Can you suggest how I might be able to make the animation go from one side of the screen to another and then reduce in size like this:

|***************************************************************|
|************************************************************** |
|*************************************************************  |

...

|**                                                             |
|*                                                              |
|                                                               |

我注意到后面的代码中没有定义timerView.这是我添加的内容:

I notice there is no definition for timerView in the code behind. Here's what I added:

var timerView = new TimerView();

让我知道是否可以.

更新2:

这是页面的完整代码.对于为什么标签不能从页面的一侧填充到另一侧,我仍然感到困惑:

Here's the full code for the page. I am still confused as to why the label does not fill from one side of the page to the other:

<?xml version="1.0" encoding="UTF-8"?>
<Frame xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Japanese;assembly=Japanese" x:Class="Japanese.PhrasesFrame" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="Transparent" Padding="0" HasShadow="false">
    <StackLayout x:Name="phrasesFrameStackLayout" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" IsVisible="false">
        <Grid x:Name="phraseGrid" BackgroundColor="Transparent" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Margin="0,20,0,0" RowSpacing="0">
            <Grid.RowDefinitions>
                <RowDefinition Height="8*" />
                <RowDefinition Height="70*" />
                <RowDefinition Height="8*" />
                <RowDefinition Height="4*" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Grid Grid.Row="0" RowSpacing="5" Grid.Column="0" BackgroundColor="#EEEEEE" Padding="10,10,10,10" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
                <Grid IsVisible="{Binding InfoGridVisible, Converter={StaticResource InverseBoolConverter} }" VerticalOptions="FillAndExpand">
                </Grid>
                <Grid IsVisible="{Binding InfoGridVisible}">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="10*" />
                        <ColumnDefinition Width="10*" />
                        <ColumnDefinition Width="60*" />
                        <ColumnDefinition Width="5*" />
                        <ColumnDefinition Width="10*" />
                        <ColumnDefinition Width="5*" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="50*" />
                        <RowDefinition Height="50*" />
                    </Grid.RowDefinitions>
                    <Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" />
                    <Label Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="2" x:Name="statLabel" Style="{StaticResource smallLabel}" VerticalOptions="FillAndExpand" VerticalTextAlignment="Center" Text="{Binding StatLabel}" />
                    <Label Grid.Row="0" Grid.Column="3" Grid.ColumnSpan="3" x:Name="cvmLabel" Style="{StaticResource smallLabel}" VerticalOptions="FillAndExpand" VerticalTextAlignment="Center" Text="{Binding CvmLabel}" />
                    <Label Grid.Row="1" Grid.Column="0" x:Name="faveLabel" Style="{StaticResource smallIcon}" FontFamily="FontAwesome" VerticalOptions="FillAndExpand" VerticalTextAlignment="Center" />
                    <Label Grid.Row="1" Grid.Column="1" x:Name="hiddenLabel" Style="{StaticResource smallIcon}" FontFamily="FontAwesome" VerticalOptions="FillAndExpand" VerticalTextAlignment="Center" />
                    <Label Grid.Row="1" Grid.Column="2" x:Name="wordTypeLabel" Style="{StaticResource smallLeftLabel}" HorizontalTextAlignment="Start" Text="{Binding WordType}" />
                    <Label Grid.Row="1" Grid.Column="3" x:Name="points1" Style="{StaticResource smallLabel}" Text="{Binding Points1}" HorizontalTextAlignment="Start" />
                    <Label Grid.Row="1" Grid.Column="4" x:Name="points2" Style="{StaticResource smallLabel}" Text="{Binding Points2}" HorizontalTextAlignment="Start" />
                    <Label Grid.Row="1" Grid.Column="5" x:Name="timer" Style="{StaticResource smallLabel}" Text="{Binding Timer}" HorizontalTextAlignment="Start" />
                </Grid>
            </Grid>
            <Grid Grid.Row="1" Grid.Column="0" Padding="10,0,10,0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="#EEEEEE">
                <Frame CornerRadius="10" HasShadow="false">
                    <Grid>
                        <Grid IsVisible="{Binding WordGridVisible}" Padding="10" BackgroundColor="White">
                            <Grid.GestureRecognizers>
                                <TapGestureRecognizer Command="{Binding WordGridClickedCommand}" />
                            </Grid.GestureRecognizers>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="45*" />
                                <RowDefinition Height="55*" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <Grid Grid.Row="0" Grid.Column="0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
                                <Label x:Name="textLabel" Style="{StaticResource bigLabel}" XAlign="Center" VerticalOptions="Center" LineBreakMode="WordWrap" Text="{Binding TextLabel}" />
                            </Grid>
                            <Grid Grid.Row="1" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Padding="10,0,10,0" IsVisible="{Binding DetailGridVisible}">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto" />
                                    <RowDefinition Height="Auto" />
                                    <RowDefinition Height="Auto" />
                                </Grid.RowDefinitions>
                                <Label x:Name="detail1" Grid.Row="0" Style="{StaticResource bigLabel}" Text="{Binding Detail1}" />
                                <Label x:Name="detail2" Grid.Row="1" Style="{StaticResource bigLabel}" Text="{Binding Detail2}" />
                                <Label x:Name="detail3" Grid.Row="2" Style="{StaticResource bigLabel}" Text="{Binding Detail3}" />
                            </Grid>
                        </Grid>
                        <Grid IsVisible="{Binding EmptyGridVisible}" Padding="10" BackgroundColor="White">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="50*" />
                                <RowDefinition Height="50*" />
                            </Grid.RowDefinitions>
                            <Grid Grid.Row="0">
                                <Label FontSize="15" XAlign="Start" TextColor="Gray" VerticalOptions="Center" HorizontalOptions="FillAndExpand" Text="{Binding EmptyLabel1}" />
                            </Grid>
                            <Grid Grid.Row="1">
                                <Label FontSize="15" XAlign="Start" TextColor="Gray" VerticalOptions="Center" HorizontalOptions="FillAndExpand" Text="{Binding EmptyLabel2}" />
                            </Grid>
                        </Grid>
                    </Grid>
                </Frame>
            </Grid>
            <Grid Grid.Row="2" x:Name="buttonGrid" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="#EEEEEE">
                <Grid IsVisible="{Binding EmptyFooterGridVisible }" Padding="10, 0" VerticalOptions="FillAndExpand" BackgroundColor="#EEEEEE">
                </Grid>
                <Grid IsVisible="{Binding ButtonGridVisible}" Padding="0" BackgroundColor="#EEEEEE" VerticalOptions="FillAndExpand">
                    <Grid IsVisible="{Binding CustomPointsSwitch}" VerticalOptions="FillAndExpand" Padding="10">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Button Grid.Column="0" x:Name="aButton" Style="{StaticResource pointButton}" Text="Don't Know" BackgroundColor="#ff3b30" BorderColor="#ff3b30" TextColor="White" Command="{Binding AButtonClickedCommand}" />
                        <Button Grid.Column="1" x:Name="bButton" Style="{StaticResource pointButton}" Text="Very Hard" BackgroundColor="#FF9500" BorderColor="#FF9500" TextColor="White" Command="{Binding BButtonClickedCommand}" />
                        <Button Grid.Column="2" x:Name="cButton" Style="{StaticResource pointButton}" Text="Hard" BackgroundColor="#FFCC00" BorderColor="#FFCC00" TextColor="White" Command="{Binding CButtonClickedCommand}" />
                        <Button Grid.Column="3" x:Name="dButton" Style="{StaticResource pointButton}" Text="Easy" BackgroundColor="#4cd964" BorderColor="#4cd964" TextColor="White" Command="{Binding DButtonClickedCommand}" />
                    </Grid>
                    <Grid IsVisible="{Binding CustomPointsSwitch, Converter={StaticResource InverseBoolConverter} }" VerticalOptions="FillAndExpand" Padding="10">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Button Grid.Column="0" VerticalOptions="FillAndExpand" Style="{StaticResource pointButton}" Text="Don't Know" BackgroundColor="#ff3b30" BorderColor="#ff3b30" TextColor="White" Command="{Binding NButtonClickedCommand}" />
                        <Button Grid.Column="1" VerticalOptions="FillAndExpand" Style="{StaticResource pointButton}" Text="Easy" BackgroundColor="#4cd964" BorderColor="#4cd964" TextColor="White" Command="{Binding YButtonClickedCommand}" />
                    </Grid>
                </Grid>
                <Grid IsVisible="{Binding ResetGridVisible}" Padding="10">
                    <Button Text="Reset All Points to Zero" TextColor="White" BackgroundColor="#4cd964" HorizontalOptions="FillAndExpand" VerticalOptions="StartAndExpand" Command="{Binding ResetButtonClickedCommand}" />
                </Grid>
            </Grid>
            <!--            <Grid x:Name="tapGrid" Grid.Row="3" Grid.Column="0" Padding="5,0,0,0" HorizontalOptions="FillAndExpand" VerticalOptions="Center">
                <Label x:Name="tapScreenLabel" Style="{StaticResource smallLabel}" />
            </Grid>-->
            <Grid Grid.Row="3" Grid.Column="0" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" BackgroundColor="Aqua" RowSpacing="0" Padding="0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="5" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <local:TimerView Grid.Row="0" Grid.Column="0" StartTimerCommand="{Binding TimerStartCommand}" RemainingTime="{Binding TimeLeft}" HorizontalOptions="FillAndExpand" />
            </Grid>
        </Grid>
    </StackLayout>
</Frame>

推荐答案

按照@ hvaughan3的建议,

As @hvaughan3 suggested, ProgressBar control can be used.

但是,如果需要创建具有自定义外观和自定义动画的控件,则可以创建自己的自定义进度栏.

But if there is a need to create a control with customized look and feel, and custom animations then you can create your own custom progress-bar.

第一步是创建自定义动画处理Width动画.

public static class ViewExtensions
{
    public static Task<bool> WidthTo(this VisualElement self, double toWidth, uint length = 250, Easing easing = null)
    {
        easing = easing ?? Easing.Linear;
        var taskCompletionSource = new TaskCompletionSource<bool>();

        var animation = new Animation(
            callback: d => AbsoluteLayout.SetLayoutBounds(self, new Rectangle(0, 0, d, self.Height)),
            start: self.Width,
            end: toWidth,
            easing: easing);

        var offset = 1000;
        animation.Commit(self, "WidthTo", 
                         rate: Convert.ToUInt32(offset), 
                         length: length,
                         finished: (v, c) => taskCompletionSource.SetResult(c)
                        );

        return taskCompletionSource.Task;
    }
}

下一步是创建一个扩展了AbsoluteLayout并具有以下子控件的自定义控件:

Next step would be to create a custom control that extends AbsoluteLayout and has following child controls:

  1. 进度条视图:以条形表示剩余时间进度

  1. Progress-bar view: Represents time remaining progress as a bar

轨迹栏视图:代表全长

计时器标签视图:以文本标签表示剩余时间进度

Timer-label view: Represents time remaining progress as text label

自定义控件可以使用DeviceTimer来使标签保持更新,同时使用上面的动画(如我们所定义的)将进度条动画化为无.

The custom control can use DeviceTimer to keep the label updated, while using above animation (as we defined) to animate progress-bar to nothing.

最后一步是创建一个将触发计时器的命令.我们使用command属性,使其对MVVM友好(即也可以通过视图模型触发).

The last step is to create a command that will trigger the timer. We use a command property so that it is MVVM friendly (i.e. can be triggered through view model too).

public class TimerView : AbsoluteLayout
{
    public TimerView()
    {
        //Load view when size has been allocated
        SizeChanged += (sender, e) =>
        {
            if (Width == 0 || Height == 0)
                return;

            if (TrackBar == null || ProgressBar == null)
                return;


            Children.Clear();

            //ensure track-bar gets full width and height as parent
            SetLayoutFlags(TrackBar, AbsoluteLayoutFlags.SizeProportional);
            SetLayoutBounds(TrackBar, new Rectangle(0, 0, 1, 1));
            Children.Add(TrackBar);

            //ensure progress-bar gets full height, but width can be changed
            SetLayoutFlags(ProgressBar, AbsoluteLayoutFlags.None);
            SetLayoutBounds(ProgressBar, new Rectangle(0, 0, Width, Height));
            Children.Add(ProgressBar);

            //if timer-label available, ensure it gets full width and height
            if (TimerLabel != null)
            {
                SetLayoutFlags(TimerLabel, AbsoluteLayoutFlags.SizeProportional);
                SetLayoutBounds(TimerLabel, new Rectangle(0, 0, 1, 1));
                Children.Add(TimerLabel);

                TimerLabel.SetBinding(BindingContextProperty, new Binding(nameof(RemainingTime), source: this));
            }

            if (AutoStart != default(TimeSpan))
            {
                RemainingTime = AutoStart;
                StartTimerCommand.Execute(RemainingTime);
            }    
        };

        StartTimerCommand = new Command(async (timer) =>
        {
            if (!IsEnabled)
                return;

            //reset progress-bar width
            SetLayoutBounds(ProgressBar, new Rectangle(0, 0, Width, Height));
            if (timer != null && timer is TimeSpan)
                RemainingTime = (TimeSpan)timer;

            IsEnabled = false;

            //Start timer for label update
            var ctrlTobeUpdated = this;
            Device.StartTimer(TimeSpan.FromSeconds(1), () =>
            {
                var oneSecond = TimeSpan.FromSeconds(1);

                ctrlTobeUpdated.RemainingTime -= oneSecond;
                if (ctrlTobeUpdated.RemainingTime < oneSecond)
                {
                    ctrlTobeUpdated = null;
                    return false;
                }
                else
                    return true;
            });

            //Start animation
            await ProgressBar.WidthTo(0, Convert.ToUInt32(RemainingTime.TotalMilliseconds));
            IsEnabled = true;
        });

    }

    public static readonly BindableProperty TrackBarProperty =
        BindableProperty.Create(
            "TrackBar", typeof(View), typeof(TimerView),
            defaultValue: null);

    public View TrackBar
    {
        get { return (View)GetValue(TrackBarProperty); }
        set { SetValue(TrackBarProperty, value); }
    }

    public static readonly BindableProperty ProgressBarProperty =
        BindableProperty.Create(
            "ProgressBar", typeof(View), typeof(TimerView),
            defaultValue: null);

    public View ProgressBar
    {
        get { return (View)GetValue(ProgressBarProperty); }
        set { SetValue(ProgressBarProperty, value); }
    }

    public static readonly BindableProperty TimerLabelProperty =
        BindableProperty.Create(
            "TimerLabel", typeof(Label), typeof(TimerView),
            defaultValue: default(Label));

    public Label TimerLabel
    {
        get { return (Label)GetValue(TimerLabelProperty); }
        set { SetValue(TimerLabelProperty, value); }
    }

    public static readonly BindableProperty StartTimerCommandProperty =
        BindableProperty.Create(
            "StartTimerCommand", typeof(ICommand), typeof(TimerView),
            defaultBindingMode: BindingMode.OneWayToSource,
            defaultValue: default(ICommand));

    public ICommand StartTimerCommand
    {
        get { return (ICommand)GetValue(StartTimerCommandProperty); }
        set { SetValue(StartTimerCommandProperty, value); }
    }

    public static readonly BindableProperty RemainingTimeProperty =
        BindableProperty.Create(
            "RemainingTime", typeof(TimeSpan), typeof(TimerView),
            defaultBindingMode: BindingMode.OneWayToSource,
            defaultValue: default(TimeSpan));

    public TimeSpan RemainingTime
    {
        get { return (TimeSpan)GetValue(RemainingTimeProperty); }
        set { SetValue(RemainingTimeProperty, value); }
    }

    public static readonly BindableProperty AutoStartProperty =
        BindableProperty.Create(
            "AutoStart", typeof(TimeSpan), typeof(TimerView),
            defaultValue: default(TimeSpan));

    public TimeSpan AutoStart
    {
        get { return (TimeSpan)GetValue(AutoStartProperty); }
        set { SetValue(AutoStartProperty, value); }
    }
}

样品用量1

XAML

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="5" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <local:TimerView Grid.Column="0" Grid.Row="0" x:Name="timerView">
        <local:TimerView.ProgressBar>
            <BoxView BackgroundColor="Maroon" />
        </local:TimerView.ProgressBar>
        <local:TimerView.TrackBar>
            <BoxView BackgroundColor="Gray" />
        </local:TimerView.TrackBar>
    </local:TimerView>

    <Label Grid.Row="1" Text="{Binding Path=RemainingTime, StringFormat='{0:%s} seconds left', Source={x:Reference timerView}}" HorizontalOptions="Center" /> 
    <Button VerticalOptions="Start" Grid.Row="2" Text="Start Timer" x:Name="startBtn" Clicked="Handle_Clicked" />

</Grid>

隐藏代码

void Handle_Clicked(object sender, System.EventArgs e)
{
    timerView.StartTimerCommand.Execute(TimeSpan.FromSeconds(10));
}

XAML

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="5" />
        <RowDefinition Height="25" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
     <local:TimerView Grid.Row="1" x:Name="timerView">
        <local:TimerView.ProgressBar>
            <Frame HasShadow="false" Padding="0" Margin="0" BackgroundColor="Aqua" />
        </local:TimerView.ProgressBar>
        <local:TimerView.TrackBar>
            <Frame HasShadow="true" Padding="0" Margin="0" />
        </local:TimerView.TrackBar>
        <local:TimerView.TimerLabel>
            <Label Text="{Binding Path=., StringFormat='{0:%m}:{0:%s}'}" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" /> 
        </local:TimerView.TimerLabel>
    </local:TimerView>

    <Button VerticalOptions="Start" Grid.Row="2" Text="Start Timer" x:Name="startBtn" Clicked="Handle_Clicked" />
</Grid>

编辑-1

EDIT - 1

XAML

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="5" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <local:TimerView Grid.Row="0" StartTimerCommand="{Binding TimerStartCommand}" RemainingTime="{Binding TimeLeft}">
        <local:TimerView.ProgressBar>
            <BoxView BackgroundColor="Maroon" />
        </local:TimerView.ProgressBar>
        <local:TimerView.TrackBar>
            <BoxView BackgroundColor="Gray" />
        </local:TimerView.TrackBar>
    </local:TimerView>
    <Label Grid.Row="1" Text="{Binding Path=TimeLeft, StringFormat='{0:%s}'}" HorizontalOptions="Center" /> 
    <Button VerticalOptions="Start" Grid.Row="2" Text="Start Timer" Command="{Binding ButtonClickCommand}" />

</Grid>

查看模型

public class ProgressVM : BaseViewModel
{
    public Command TimerStartCommand { get; set; }
    public Command ButtonClickCommand => new Command(() => TimerStartCommand?.Execute(TimeSpan.FromSeconds(20)));

    private TimeSpan _timeLeft;
    public TimeSpan TimeLeft
    {
        get { return _timeLeft; }
        set
        {
            _timeLeft = value;
            OnPropertyChanged();
        }
    }
}

编辑-2:根据问题更新

EDIT - 2 : As per question update

如果您需要先在瞬间从左到右然后再从左到右的动画;通过对控件进行较小的更新也可以做到这一点.

If you need an animation that first goes from left to right in an instant and then goes back to left; that is also possible through a minor update in control.

然后,您将需要更新SizeChanged处理程序和StartTimer处理程序,如下所示:

Then, you will need to update SizeChanged handler, and StartTimer handler as following:

public class TimerView : AbsoluteLayout
{
    public TimerView()
    {
        SizeChanged += (sender, e) =>
        {
            if (Width == 0 || Height == 0)
                return;

            if (TrackBar == null || ProgressBar == null)
                return;


            Children.Clear();

            SetLayoutFlags(TrackBar, AbsoluteLayoutFlags.SizeProportional);
            SetLayoutBounds(TrackBar, new Rectangle(0, 0, 1, 1));
            Children.Add(TrackBar);

            SetLayoutFlags(ProgressBar, AbsoluteLayoutFlags.None);
            SetLayoutBounds(ProgressBar, new Rectangle(0, 0, 0, Height));
            Children.Add(ProgressBar);

            if(TimerLabel != null)
            {
                SetLayoutFlags(TimerLabel, AbsoluteLayoutFlags.SizeProportional);
                SetLayoutBounds(TimerLabel, new Rectangle(0, 0, 1, 1));
                Children.Add(TimerLabel);

                TimerLabel.SetBinding(BindingContextProperty, new Binding(nameof(RemainingTime), source: this));
            }
        };

        StartTimerCommand = new Command(async (timer) =>
        {
            if (!IsEnabled)
                return;

            if (timer != null && timer is TimeSpan)
                RemainingTime = (TimeSpan)timer;

            IsEnabled = false;

            var ctrlTobeUpdated = this;
            Device.StartTimer(TimeSpan.FromSeconds(1), () =>
            {
                var oneSecond = TimeSpan.FromSeconds(1);

                ctrlTobeUpdated.RemainingTime -= oneSecond;
                if (ctrlTobeUpdated.RemainingTime < oneSecond)
                {
                    ctrlTobeUpdated = null;
                    return false;
                }
                else
                    return true;
            });

            await ProgressBar.WidthTo(Width, Convert.ToUInt32(150));
            await ProgressBar.WidthTo(0, Convert.ToUInt32(RemainingTime.TotalMilliseconds - 150));
            IsEnabled = true;
        });

    }

EDIT-3 :删除了ProgressBarTimerBar的可绑定属性定义中的默认值的代码/支持.

EDIT - 3: Removed code/support for default values in bindable property definition for ProgressBar, and TimerBar.

编辑-4 :添加了对加载时自动启动计时器的支持.

EDIT - 4: Add support for auto-start timer on load.

XAML

<local:TimerView AutoStart="0:0:20"> <!-- timespan for 20 seconds or VM based AutoStart="{Binding SetTime}" -->
    <local:TimerView.ProgressBar>
        <BoxView BackgroundColor="Maroon" />
    </local:TimerView.ProgressBar>
    <local:TimerView.TrackBar>
        <BoxView BackgroundColor="Gray" />
    </local:TimerView.TrackBar>
</local:TimerView>

EDIT-5 :添加对计时器的暂停和停止命令的支持.还更新了计时器视图,以在设备方向更改方面更具弹性.

EDIT - 5: Add support for pause and stop commands for timer. Also updated timer view to be more resilient in terms of device-orientation changes.

  • src: TimerView.cs
  • src: TimerView.Properties.cs

这篇关于如何创建一个条形区域,该条形区域从左到右缓慢填充5、10或???秒?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆