本文主要講我設計的幾個進度條,還有如何使用異步控制進度條,如何使用動畫做進度。
進度條可以參見:http://edi.wang/post/2016/2/25/windows⑴0-uwp-modal-progress-dialog
進度條其實異步就是使用后臺變化,然后value綁定
我使用1個ProgressBar
需要設置他的各個值,如果不設置,1般最大值為100,最小為0,所以可以表示百分數,其中Value是double,綁定后臺就好。
“`
<ProgressBar Maximum="100" Value="{x:Bind View.Value,Mode=OneWay}" Height="20" Width="100"></ProgressBar>
綁定到我們的ViewModel,1般如果后臺線程操作界面是不能直接,但是我用了
```
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
});
代碼參見:https://github.com/lindexi/UWP/tree/master/uwp/control/Progress,項目所有代碼都會發出
我們使用Task異步,我們由于沒有甚么耗時的,就Task.Delay(1000).Wait();
我們進度會等1秒,固然自己也能夠設置多些。也能夠寫 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;
默許進度條設置最大值,
我還自己的控件,1個值從0到100的圓形的,可以看下面
##圓形進度條
參見:http://www.cnblogs.com/ms-uap/p/4641419.html
先說怎樣用我的,首先去我源代碼https://github.com/lindexi/UWP,打開我的進度條文件夾,里面有View文件夾
我在View有1個控件RountProgress
復制他到你的解決方案,如果我的控件大小和你不1樣,很簡單調劑,我就不說。
那末我的控件只需要指定Value就好啦,Value實際上是從0到100,如果叫別的應當好,但是我不改,如果你覺得不想要,自己改
xmlns:view="using:lindexi.uwp.control.RountProgress.View"
<view:RountProgress Value="{x:Bind Value,Mode=OneWay}"></view:RountProgress>
我來講下怎樣做
我們要知道StrokeDashArray,這個是1個數組,是循環的,也就是依此讀取,知道超太長度。
首先我們需要有Thickness,寬度,StrokeDashArray的每個都是寬度的倍數
首先取第1個元素,把這個元素乘以寬度,作為顯示的大小,然后取第2個元素,乘以寬度,作為不顯示的大小
然后循環獲得第3個……,如果不存在第3個,那末循環拿第1做第3,n=n==max?0:n+1,n就是第n個元素
1個顯示1個不顯示,循環
記得長度乘以是值*寬度
那末我們如果有1個值*寬度
的到大小比我們的寬度還大,那末就會截斷。
假設我們寬度 3,StrokeDashArray 1,2,0.5,總長度為5,那末
第1個是大小 1*3
顯示,然后是2*3
不顯示,由于到第1個只有長度為2,第2個大小為6,所以會截斷,3顯示然后2不顯示
我們可以用第1個為1個值,然后第2個為1個比總長度還大的值,這樣會讓寬度顯示為我們第1個的值,而其他為空,由于第2個比最大還大
我們要做1個30%
,我們需要算
長=圓*30%/寬度
圓=PI*(總長度-寬度)
<Ellipse x:Name="Rount" Stroke="DeepSkyBlue" Height="100" Width="100"
StrokeThickness="3"
RenderTransformOrigin="0.5,0.5"/>
那末我們第1個值 (總長度100 - 寬度3) \* PI / 寬度3
由于我們需要算我們的寬度不是直接總長度,是總長度-寬度
第2個最好是Double.Max
我們想要1個可以用戶進度,那末可以綁定1個屬性,在我們控件
我們需要這個為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
那末進度條如果不需要進度,那末我有1些好的,例如我之前的博客有說的,還有1個簡單,也是上面改,我們1個值是顯示1個值是不顯示,那末我們可以做
<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>
我們使用1個簡單的修改,由于我們可使用<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,下面就是彈跳,我上面有說,這個在官方有說比我寫還好,但是官方的我沒法拿來
本作品采取知識同享署名-非商業性使用-相同方式同享 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發布,但務必保存文章署名林德熙(包括鏈接:http://blog.csdn.net/lindexi_gd ),不得用于商業目的,基于本文修改后的作品務必以相同的許可發布。如有任何疑問,請與我聯系。