【发布时间】:2019-06-23 16:11:59
【问题描述】:
我正在尝试制作我认为对应用程序来说会很好的效果 - 一系列图像(想想壁纸)将在视图期间在背景中不断滚动。我开始在 Xamarin.Forms 中对此进行原型设计,创建自定义控件。计划进行对角线平移,但从最基本的方法开始,但很快就遇到了一些问题,即它并不完全平滑,因为它在这里和那里有点不稳定(即使使用缓存和只有 10kb 的图像)和 2 ) 如果用户执行的操作涉及更多,则可能会导致延迟,并且图像会比应有的更紧密地呈现在一起。有没有办法修复这种方法,使其尽可能平滑并且不会干扰(或受到干扰)其他 UI 元素,或者有没有一种更优越的方法来解决这样的问题 - 任何人都解决过这个问题?请告诉我,谢谢。
FlyingImageBackground.cs
public class FlyingImageBackground : ContentView
{
public static readonly BindableProperty FlyingImageProperty =
BindableProperty.Create(nameof(FlyingImage), typeof(ImageSource), typeof(FlyingImageBackground), default(ImageSource), BindingMode.TwoWay, propertyChanged: OnFlyingImageChanged);
public ImageSource FlyingImage
{
get => (ImageSource)GetValue(FlyingImageProperty);
set => SetValue(FlyingImageProperty, value);
}
private AbsoluteLayout canvas;
public FlyingImageBackground()
{
this.canvas = new AbsoluteLayout()
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand
};
this.canvas.SizeChanged += Canvas_SizeChanged;
Content = this.canvas;
}
~FlyingImageBackground() => this.canvas.SizeChanged -= Canvas_SizeChanged;
private static void OnFlyingImageChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (FlyingImageBackground)bindable;
control.BringToLife();
}
private void BringToLife()
{
if (this.canvas.Width <= 0 || this.canvas.Height <= 0)
return;
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
Device.BeginInvokeOnMainThread(async () =>
{
await SendImageWave();
});
return this.canvas.IsVisible;
});
}
private async Task SendImageWave()
{
var startingX = -100;
var endingX = this.canvas.Width;
if (endingX <= 0)
return;
endingX += 100;
var yPositions = Enumerable.Range(0, (int)this.canvas.Height).Where(x => x % 90 == 0).ToList();
var imgList = new List<CachedImage>();
foreach (var yPos in yPositions)
{
var img = new CachedImage
{
Source = FlyingImage,
HeightRequest = 50
};
imgList.Add(img);
this.canvas.Children.Add(img, new Point(startingX, yPos));
}
await Task.WhenAll(
imgList.Select(x => x.TranslateTo(endingX, 0, 10000)));
//.Concat(imgList.Select(x => x.TranslateTo(startingX, 0, uint.MinValue))));
imgList.ForEach(x =>
{
this.canvas.Children.Remove(x);
x = null;
});
imgList = null;
}
private void Canvas_SizeChanged(object sender, EventArgs e)
{
BringToLife();
}
}
用法示例:
只需将其与主要内容一起放入 ContentPage 中的 Grid 中即可: 例如:
<ContentPage.Content>
<Grid>
<controls:FlyingImageBackground FlyingImage="fireTruck.png" />
<StackLayout HorizontalOptions="Center">
<Button
Text="I'm a button!" />
<Label
FontAttributes="Bold,Italic"
Text="You're a good man, old sport!!!"
TextDecorations="Underline" />
</StackLayout>
</Grid>
</ContentPage.Content>
【问题讨论】:
-
只是一个建议:动画可能看起来不错,但从用户和设备的角度考虑。设备,如果它必须加载大量图像,它会首先将它们加载到内存中(你想要性能,对吧?)。另外,它需要为它们设置动画。这会消耗大量内存,使手机发热/降低性能。请记住,一个伟大的应用程序不是你不能添加更多功能的地方,一个伟大的应用程序是你不能从中取出现有功能的应用程序,因为它们是必需的。您可以做的一件事是,不要为太多图像制作动画,而是像这样创建一个 gif 并使用它。
-
感谢@Aousafrashid 的建议 - 是的,我完全明白这一点,但在这种情况下 1) 我在给定时间仅使用大约 50 个相同缓存图像的实例,2) 会很方便通过绑定更改图像(这是我最初概念的重点,例如,用户更改某个设置,然后在背景中飞行的图像无缝过渡到另一个,3)大多数设备都能够运行相当不错的 3D 游戏- 这是一个非常基本的动画,资产非常小,我希望它能够工作。
标签: c# performance user-interface animation xamarin.forms