第二十一章:變換(五)
規模變換
VisualElement類定義名為Scale的屬性,您可以使用該屬性更改元素的呈現大小。 Scale屬性不會影響佈局(將在ButtonScaler程式中演示)。它不會影響元素的get-only Width和Height屬性,也不會影響包含Width和Height值的get-only Bounds屬性。對Scale屬性的更改不會導致觸發SizeChanged事件。
縮放影響渲染視覺元素的座標,但與TranslationX和TranslationY的方式完全不同。兩個轉換屬性將值新增到座標,而Scale屬性是乘法。 Scale的預設值為1.大於1的值會增加元素的大小。例如,值3使元素的大小為正常大小的三倍。小於1的值會減小尺寸。 Scale值為0是合法的,但會導致元素不可見。如果您正在使用Scale並且您的元素似乎已經消失,請檢查它是否以某種方式獲得Scale值為0。
小於0的值也是合法的,並且除了改變尺寸之外,還使元件旋轉180度。
您可以使用SimpleScaleDemo程式試驗縮放設定。 (該程式有一個簡單的字首,因為它不包括AnchorX和AnchorY屬性的影響,這將很快討論。)XAML類似於TranslationDemo程式:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleScaleDemo.SimpleScaleDemoPage"> <StackLayout Padding="20, 10"> <Frame x:Name="frame" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" OutlineColor="Accent"> <Label Text="TEXT" FontSize="Large" /> </Frame> <Slider x:Name="scaleSlider" Minimum="-10" Maximum="10" Value="{Binding Source={x:Reference frame}, Path=Scale}" /> <Label Text="{Binding Source={x:Reference scaleSlider}, Path=Value, StringFormat='Scale = {0:F1}'}" HorizontalTextAlignment="Center" /> </StackLayout> </ContentPage>
這是在行動。 請注意Android手機上的負面比例設定:
在Windows 10移動顯示器上,框架已縮放到如此大,以至於您無法看到其左側和右側。
在現實生活中,您可能希望使用“縮放”在單擊“按鈕”時向用戶提供一些反饋。 按鈕可以短暫地擴大尺寸並再次恢復正常。 但是,Scale不是更改Button大小的唯一方法。 您還可以通過增加和減少FontSize屬性來更改Button大小。 但是,這兩種技術非常不同:Scale屬性不會影響佈局,但FontSize屬性會影響佈局。
ButtonScaler程式說明了這種差異。 XAML檔案由兩個夾在兩對BoxView元素之間的Button元素組成:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="ButtonScaler.ButtonScalerPage"> <StackLayout> <!-- "Animate Scale" Button between two BoxViews. --> <BoxView Color="Accent" HeightRequest="4" VerticalOptions="EndAndExpand" /> <Button Text="Animate Scale" FontSize="Large" BorderWidth="1" HorizontalOptions="Center" Clicked="OnAnimateScaleClicked" /> <BoxView Color="Accent" HeightRequest="4" VerticalOptions="StartAndExpand" /> <!-- "Animate FontSize" Button between two BoxViews. --> <BoxView Color="Accent" HeightRequest="4" VerticalOptions="EndAndExpand" /> <Button Text="Animate FontSize" FontSize="Large" BorderWidth="1" HorizontalOptions="Center" Clicked="OnAnimateFontSizeClicked" /> <BoxView Color="Accent" HeightRequest="4" VerticalOptions="StartAndExpand" /> </StackLayout> </ContentPage>
這是頁面通常的樣子:
程式碼隱藏檔案實現了一種有點通用的動畫方法。 在某種意義上,它是通用的,引數包括兩個值,表示動畫的起始值和結束值。 這兩個值通常稱為從值和值到值。 動畫引數還包括動畫的持續時間和回撥方法。 回撥方法的引數是“from”值和“to”值之間的值,並且呼叫方法可以使用該值來執行實現動畫所需的任何操作。
但是,這種動畫方法並不完全一般化。 它實際上在動畫的前半部分計算從值到值的值,然後在動畫的後半部分計算從值到值的值。 這有時被稱為倒車動畫。
該方法稱為AnimateAndBack,它使用Task.Delay呼叫來調整動畫,並使用.NET Stopwach物件來確定已用時間:
public partial class ButtonScalerPage : ContentPage
{
public ButtonScalerPage()
{
InitializeComponent();
}
void OnAnimateScaleClicked(object sender, EventArgs args)
{
Button button = (Button)sender;
AnimateAndBack(1, 5, TimeSpan.FromSeconds(3), (double value) =>
{
button.Scale = value;
});
}
void OnAnimateFontSizeClicked(object sender, EventArgs args)
{
Button button = (Button)sender;
AnimateAndBack(button.FontSize, 5 * button.FontSize,
TimeSpan.FromSeconds(3), (double value) =>
{
button.FontSize = value;
});
}
async void AnimateAndBack(double fromValue, double toValue,
TimeSpan duration, Action<double> callback)
{
Stopwatch stopWatch = new Stopwatch();
double t = 0;
stopWatch.Start();
while (t < 1)
{
double tReversing = 2 * (t < 0.5 ? t : 1 - t);
callback(fromValue + (toValue - fromValue) * tReversing);
await Task.Delay(16);
t = stopWatch.ElapsedMilliseconds / duration.TotalMilliseconds;
}
stopWatch.Stop();
callback(fromValue);
}
}