フォームにダイヤルパッドを実装したい。今、私のXAMLでボタンをテストしています:XAML
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.Microsoft.com/winfx/2009/xaml"
x:Class="MyXFDemo001.Views.NewItemPage"
Title="New Item">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Save" Clicked="Save_Clicked" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout Spacing="20" Padding="15">
<Button
x:Name="buttonSelectContact"
Clicked="buttonSelectContact_Clicked"
Text="CLICK" BackgroundColor="#0080ff" />
</StackLayout>
</ContentPage.Content>
そして私のコードビハインドには、メソッドがありますbuttonSelectContact_Clicked:
private async void buttonSelectContact_Clicked(object sender, EventArgs e)
{
Button btn = (Button)sender;
btn.BackgroundColor = Color.FromHex("#22ac38");
await Task.Delay(500);
btn.BackgroundColor = Color.FromHex("#0080ff");
}
それは動作しますが、静かに私が望むほど滑らかではありません。このBackgroundColorの代わりにアニメーションを追加することを提案できますか?
https://forums.xamarin.com/discussion/58818/how-to-animate-change-of-background-color によると、コードは次のようになります
XAML
<StackLayout Spacing="20" Padding="15">
<Grid>
<Button
x:Name="buttonSelectContactSecond"
Text="CLICK" BackgroundColor="#22ac38" />
<Button
x:Name="buttonSelectContact"
Clicked="buttonSelectContact_Clicked"
Text="CLICK" BackgroundColor="#0080ff" />
</Grid>
</StackLayout>
コードビハインドで
private async void buttonSelectContact_Clicked(object sender, EventArgs e)
{
StartAnimation();
}
private async void StartAnimation()
{
await Task.Delay(200);
await buttonSelectContact.FadeTo(0, 250);
await Task.Delay(200);
await buttonSelectContact.FadeTo(1, 250);
}
より良い選択は、それを行うための再利用可能な機能を作成することだと思います。 xamarin.forms のアニメーションリソースを利用できます。
たとえば、FadeTo
やTranslateTo
...など、どこでも再利用できる素敵で簡単な方法を提供する拡張メソッドを作成できます。
この特定のケースで色をスムーズに変更するロジックを除いて、非常に簡単です。コードは次のとおりです。
public static class AnimationExtensions
{
public static Task<bool> ChangeBackgroundColorTo(this Button self, Color newColor, uint length = 250, Easing easing = null)
{
Task<bool> ret = new Task<bool>(() => false);
if (!self.AnimationIsRunning(nameof(ChangeBackgroundColorTo)))
{
Color fromColor = self.BackgroundColor;
try
{
Func<double, Color> transform = (t) =>
Color.FromRgba(fromColor.R + t * (newColor.R - fromColor.R),
fromColor.G + t * (newColor.G - fromColor.G),
fromColor.B + t * (newColor.B - fromColor.B),
fromColor.A + t * (newColor.A - fromColor.A));
ret = TransmuteColorAnimation(self, nameof(ChangeBackgroundColorTo), transform, length, easing);
}
catch (Exception ex)
{
// to supress animation overlapping errors
self.BackgroundColor = fromColor;
}
}
return ret;
}
private static Task<bool> TransmuteColorAnimation(Button button, string name, Func<double, Color> transform, uint length, Easing easing)
{
easing = easing ?? Easing.Linear;
var taskCompletionSource = new TaskCompletionSource<bool>();
button.Animate(name, transform, (color) => { button.BackgroundColor = color; }, 16, length, easing, (v, c) => taskCompletionSource.SetResult(c));
return taskCompletionSource.Task;
}
}
このクラスのインポート(using namespace
参照)以下のように使用できます。
XAML
ボタンの宣言:
<Button Text="Nice button ;)"
BackgroundColor="Gray"
x:Name="btnTeste"
Clicked="btnTest_Click"/>
コードビハインドでのクリックの処理:
private async void btnTest_Click(object sender, EventArgs args)
{
#region You will not need this block, it is just to choose a random color for change to
var colors = new[] { Color.Red, Color.Pink, Color.Silver, Color.Yellow, Color.Black, Color.Green };
var rnd = new Random();
var actualColor = btnTeste.BackgroundColor;
var randomColor = colors.Where(c => c != actualColor).ToArray()[rnd.Next(0, colors.Length - 2)];
#endregion
// Here is the effective use of the smooth background color change animation
await btnTeste.ChangeBackgroundColorTo(randomColor, 150, Easing.CubicOut);
await btnTeste.ChangeBackgroundColorTo(actualColor, 100, Easing.SinOut);
}
編集:
結果は次のとおりです(gifはクリックとダブルクリックを示しているため、多くのスムーズな変更を確認できます)。
アニメーションを使用してユニバーサルカスタムコントロールを作成することもできます。
このサンプルでは、Imageコントロールを使用しましたが、ボタン、ラベルなどを使用できます。
public class NativeImage : Image
{
public static readonly BindableProperty CommandProperty =
BindableProperty.Create(
nameof(Command),
typeof(ICommand),
typeof(NativeImage),
default(ICommand));
public ICommand Command
{
get => (ICommand) GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
public static readonly BindableProperty CommandParameterProperty =
BindableProperty.Create(
nameof(Command),
typeof(object),
typeof(NativeImage));
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
private ICommand TransitionCommand
{
get
{
return new Command(async () =>
{
AnchorX = 0.48;
AnchorY = 0.48;
await this.ScaleTo(0.8, 50, Easing.Linear);
await Task.Delay(100);
await this.ScaleTo(1, 50, Easing.Linear);
Command?.Execute(CommandParameter);
});
}
}
public NativeImage()
{
Initialize();
}
public void Initialize()
{
GestureRecognizers.Add(new TapGestureRecognizer
{
Command = TransitionCommand
});
}
}