title author date CreateTime categories
win10 uwp 异步进度条
lindexi
2018-2-13 17:23:3 +0800
2018-2-13 17:23:3 +0800
Win10 UWP

本文主要讲我设计的几个进度条,还有如何使用异步控制进度条,如何使用动画做进度。

进度条可以参见:http://edi.wang/post/2016/2/25/windows-10-uwp-modal-progress-dialog

进度条其实异步就是使用后台变化,然后 value 绑定,异步绑定很简单,参见绑定的文章。

我使用一个ProgressBar 需要设置他的各个值,如果不设置,一般最大值为100,最小为0,所以可以表示百分数,其中Value是double,绑定后台就好。


<ProgressBar Maximum="100" Value="{x:Bind View.Value,Mode=OneWay}" Height="20" Width="100"></ProgressBar>

绑定到我们的 ViewModel ,一般如果后台线程操作界面是不能直接,但是我用了下面代码,把异步的线程放在同步

             await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,

                () =>

                {

                });

代码参见:https://github.com/lindexi/UWP/tree/master/uwp/control/Progress,项目所有代码都会发出,所以可以看我的网站

我们使用 Task 异步,我们因为没有什么耗时的,就Task.Delay(1000).Wait();我们进度会等一秒,当然自己也可以设置多些。也可以写 await Task.Dalay(1000);

ViewModel

        public ViewModel()
{ new Task(() =>
{
while (Value < 90)
{
Value += 10;
Task.Delay(1000).Wait();
}
}).Start();
} public double Value
{
set
{
_value = value;
OnPropertyChanged();
}
get
{
return _value;
}
} private double _value;

默认进度条设置最大值,

我还自己的控件,一个值从0到100的圆形的,可以看下面

圆形进度条

参见:http://www.cnblogs.com/ms-uap/p/4641419.html

先说怎么用我的,首先去我源代码https://github.com/lindexi/UWP,打开我的进度条文件夹,里面有View文件夹

我在View有一个控件RountProgress复制他到你的解决方案,如果我的控件大小和你不一样,很简单调整,我就不说。

那么我的控件只需要指定Value就好啦,Value其实是从0到100,如果叫别的应该好,但是我不改,如果你觉得不想要,自己改

   xmlns:view="using:lindexi.uwp.control.RountProgress.View"
<view:RountProgress Value="{x:Bind Value,Mode=OneWay}"></view:RountProgress>

我来说下怎么做

我们要知道StrokeDashArray,这个是一个数组,是循环的,也就是依此读取,知道超过长度。

首先我们需要有Thickness,宽度,StrokeDashArray的每一个都是宽度的倍数

首先取第一个元素,把这个元素乘以宽度,作为显示的大小,然后取第二个元素,乘以宽度,作为不显示的大小

然后循环获取第三个……,如果不存在第三个,那么循环拿第一做第三,n=n==max?0:n+1,n就是第n个元素

一个显示一个不显示,循环

记得长度乘以是值*宽度

那么我们如果有一个值*宽度的到大小比我们的宽度还大,那么就会截断。

假如我们宽度 3,StrokeDashArray 1,2,0.5,总长度为5,那么

第一个是大小 1*3显示,然后是2*3不显示,因为到第一个只有长度为2,第二个大小为6,所以会截断,3显示然后2不显示

我们可以用第一个为一个值,然后第二个为一个比总长度还大的值,这样会让宽度显示为我们第一个的值,而其他为空,因为第二个比最大还大

我们要做一个30%,我们需要算

长=圆*30%/宽度

圆=PI*(总长度-宽度)

         <Ellipse x:Name="Rount" Stroke="DeepSkyBlue" Height="100" Width="100" 

                 StrokeThickness="3" 

                 RenderTransformOrigin="0.5,0.5"/>

那么我们第一个值 (总长度100 - 宽度3) \* PI / 宽度3

因为我们需要算我们的宽度不是直接总长度,是总长度-宽度

第二个最好是Double.Max

我们想要一个可以用户进度,那么可以绑定一个属性,在我们控件

我们需要这个为double,然后绑定

因为我们需要两个值,所以转换

假如我们的转换是固定的总长度,宽度,那么可以使用

        public object Convert(object value, Type targetType, object parameter, string language)

        {

            double thine = 3;

            double w = 100 - thine;

            double n = Math.PI * w/thine * (double)value / 100;

            DoubleCollection temp = new DoubleCollection()

            {

               n,

                1000

            };

            return temp;

        }

如果觉得固定不好,可以在我们转换写属性,然后在界面把我们的宽度给属性,然后换为我们的宽度算,这个简单

代码在https://github.com/lindexi/UWP/tree/master/uwp/control/Progress/Progress/View/RountProgress.xaml

那么进度条如果不需要进度,那么我有一些好的,例如我之前的博客有说的,还有一个简单,也是上面改,我们一个值是显示一个值是不显示,那么我们可以做

<UserControl

    x:Class="lindexi.uwp.control.RountProgress.View.IndeterminateProgress"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:local="using:lindexi.uwp.control.RountProgress.View"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d"

    d:DesignHeight="300"

    d:DesignWidth="400">

    <UserControl.Resources>

        <Style TargetType="ProgressRing">

            <Setter Property="Background" Value="Transparent"/>

            <Setter Property="Foreground" Value="{ThemeResource SystemControlHighlightAccentBrush}"/>

            <Setter Property="IsHitTestVisible" Value="False"/>

            <Setter Property="HorizontalAlignment" Value="Center"/>

            <Setter Property="VerticalAlignment" Value="Center"/>

            <Setter Property="MinHeight" Value="20"/>

            <Setter Property="MinWidth" Value="20"/>

            <Setter Property="IsTabStop" Value="False"/>

            <Setter Property="Template">

                <Setter.Value>

                    <ControlTemplate TargetType="ProgressRing">

                        <Grid x:Name="Ring" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" FlowDirection="LeftToRight" MaxWidth="{Binding TemplateSettings.MaxSideLength, RelativeSource={RelativeSource Mode=TemplatedParent}}" MaxHeight="{Binding TemplateSettings.MaxSideLength, RelativeSource={RelativeSource Mode=TemplatedParent}}" Padding="{TemplateBinding Padding}" RenderTransformOrigin=".5,.5" >

                            <Grid.Resources>

                                <Style x:Key="ProgressRingEllipseStyle" TargetType="Ellipse">

                                    <Setter Property="Opacity" Value="0"/>

                                    <Setter Property="HorizontalAlignment" Value="Left"/>

                                    <Setter Property="VerticalAlignment" Value="Top"/>

                                </Style>

                            </Grid.Resources>

                            <VisualStateManager.VisualStateGroups>

                                <VisualStateGroup x:Name="SizeStates">

                                    <VisualState x:Name="Large">

                                        <Storyboard>

                                        </Storyboard>

                                    </VisualState>

                                    <VisualState x:Name="Small"/>

                                </VisualStateGroup>

                                <VisualStateGroup x:Name="ActiveStates">

                                    <VisualState x:Name="Inactive"/>

                                    <VisualState x:Name="Active">

                                        <Storyboard RepeatBehavior="Forever">

                                            <DoubleAnimation Storyboard.TargetName="Rount" Storyboard.TargetProperty="Angle"

                                                           BeginTime="0:0:0" Duration="0:0:5" From="0" To="360"  >

                                            </DoubleAnimation>

                                        </Storyboard>

                                    </VisualState>

                                </VisualStateGroup>

                            </VisualStateManager.VisualStateGroups>

                            <Ellipse  Stroke="DeepSkyBlue" Height="100" Width="100" 

                                      StrokeThickness="3"  

                                      RenderTransformOrigin="0.5,0.5"/>

                            <Ellipse  Stroke="DeepSkyBlue" Height="200" Width="200" 

                                      StrokeThickness="3" StrokeDashArray="50 50" 

                                      RenderTransformOrigin="0.5,0.5" >

                                <Ellipse.RenderTransform>

                                    <RotateTransform  x:Name="Rount" Angle="0"/>

                                </Ellipse.RenderTransform>

                            </Ellipse>

                        </Grid>

                    </ControlTemplate>

                </Setter.Value>

            </Setter>

        </Style>

    </UserControl.Resources>

    <Grid>

        <ProgressRing Width="200" Height="200" 

                      IsActive="True"></ProgressRing>

    </Grid>

</UserControl>

我们使用一个简单的修改,因为我们可以使用<RotateTransform x:Name="Rount" Angle="0"/>

我们使用

                                    <VisualState x:Name="Active">

                                        <Storyboard RepeatBehavior="Forever">

                                            <DoubleAnimation Storyboard.TargetName="Rount" Storyboard.TargetProperty="Angle"

                                                             Duration="0:0:5" From="0" To="360"  >

                                            </DoubleAnimation>

                                        </Storyboard>

                                    </VisualState>

修改我们旋转,时间0:0:5,5秒,从0到360,循环

因为是修改,所以可以放在Resource

<ProgressRing Width="200" Height="200" 

                      IsActive="True"></ProgressRing>

我觉得匀速不好,修改速度

  • BackEase

缓动函数,它在部分持续时间内向反方向更改主函数的值

  • BounceEase

弹跳

  • CircleEase

    加速

  • PowerEase

    次方

  • SineEase

    sin加速

  • QuadraticEase

    ^2

动画

移动元素

我们可以看到我们的元素位置可以修改 Margin,那么如何在动画修改Margin

UWP 动画 Margin可以

 <Storyboard TargetName="Rount">

    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Margin"

                                   BeginTime="00:00:00" EnableDependentAnimation="True"

                                   Duration="0:0:2" >

                 <DiscreteObjectKeyFrame KeyTime="00:00:00"  >

                     <DiscreteObjectKeyFrame.Value >

                         <Thickness>10,1,10,10</Thickness>

                     </DiscreteObjectKeyFrame.Value>

                   </DiscreteObjectKeyFrame>

                 <DiscreteObjectKeyFrame KeyTime="00:00:02">

                     <DiscreteObjectKeyFrame.Value >

                         <Thickness>10,200,10,10</Thickness>

                 </DiscreteObjectKeyFrame.Value>

         </DiscreteObjectKeyFrame>

    </ObjectAnimationUsingKeyFrames>

 </Storyboard>

Rount就是我们要修改的控件,我们看到这是在2就直接修改,没有从1到200,这样其实并不是我们直接就想从1然后两秒200

我们定义

                            <local:IndeterminateProgress  Margin="0,10,0,0" Width="200" Height="200" >

                                <local:IndeterminateProgress.RenderTransform>

                                    <TranslateTransform x:Name="Rount" Y="0"></TranslateTransform>

                                </local:IndeterminateProgress.RenderTransform>

                            </local:IndeterminateProgress>

<DoubleAnimation Storyboard.TargetName="Rount" Storyboard.TargetProperty="Y" From="0" To="100" Duration="0:0:2"></DoubleAnimation>

我们要让我们的进度弹起来,如果不知道我说什么,简单我有图

其实我们要让我们的元素移动,可以看林政大神的书


    <local:IndeterminateProgress Margin="0,10,0,0" Width="200" Height="200" >

       <local:IndeterminateProgress.RenderTransform>

               <TranslateTransform x:Name="Rount" Y="10" />

       </local:IndeterminateProgress.RenderTransform>

    </local:IndeterminateProgress>

在动画

                                              <DoubleAnimation Storyboard.TargetName="Rount"

                                                             Storyboard.TargetProperty="Y"

                                                             Duration="0:0:2" From="0" To="300">

                                                <DoubleAnimation.EasingFunction>

                                                    <BounceEase Bounces="2"></BounceEase>

                                                </DoubleAnimation.EasingFunction>

                                            </DoubleAnimation>

我们使用Rount,x,记得要给名字,然后两秒,从0到300,下面就是弹跳,我上面有说,这个在官方有说比我写还好,但是官方的我没法拿来

最新文章

  1. 判断js引擎是javascriptCore或者v8
  2. ubuntu终端窗口最大化(不是全屏)
  3. 页面加载时执行JQ代码
  4. COJ968 WZJ的数据结构(负三十二)
  5. 第4章 管道和FIFO
  6. jdk线程的死锁
  7. Android下结束进程的方法
  8. Java Access Levels(访问控制)
  9. 15.java.lang.InstantiationException
  10. Python下载Bing主页图片
  11. elf格式分析
  12. testng及JMeter使用之初体验
  13. EasyMock 简单使用
  14. Sublime Text3 远程 Linux
  15. linux dd指令
  16. 如何使用 Java 删除 ArrayList 中的重复元素
  17. 2:4 动态方法的调用(简化Action的配置)
  18. Oracle性能诊断艺术-读书笔记(范围分区)
  19. Maze dfs倒行
  20. Mysql update 索引

热门文章

  1. rsa加解密的内容超长的问题解决
  2. CSS user-select文本是否可复制
  3. Ubuntu18.04+windows10双系统时间同步教程
  4. 阿里云对象存储OSS支持版本管理特性
  5. Hdu 2522 hash
  6. 复习一下jdbc原始封装
  7. Python基础:10函数参数
  8. HZOJ 走格子
  9. 弹性FLEX布局
  10. rsa加密(非对称加密)