在 xamarin 中滚动 CollectionView 图片时它滞后,该怎么办?
When scrolling in CollectionView pictures in xamarin its laging, what to do?
当我在 CollectionView 中滚动时,它开始滞后,可能是在加载下一张图片。我能用它做什么?我该如何优化它?
这里是XAML:
<Grid BackgroundColor="#00aeef">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<CollectionView x:Name="myCollectionView" Grid.Row="0">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame Padding="0" BackgroundColor="#00d2ff" Margin="20" CornerRadius="30">
<StackLayout Padding="20">
<Label Text="{Binding Airline}" TextColor ="White" FontSize="30" HorizontalOptions="Center"/>
<Image Source="{Binding Url}" HeightRequest="200"/>
<Label Text="{Binding Plane, StringFormat='Plane: {0}'}" TextColor ="White" FontSize="15"/>
<Label Text="{Binding Airline, StringFormat='Airline: {0}'}" TextColor ="White" FontSize="15"/>
<Label Text="{Binding Livery, StringFormat='Livery: {0}'}" TextColor ="White" FontSize="15"/>
<Label Text="{Binding Registration, StringFormat='Reg: {0}'}" TextColor ="White" FontSize="15"/>
<Label Text="{Binding Airport, StringFormat='Airport: {0}'}" TextColor ="White" FontSize="15"/>
<Label Text="{Binding Date, StringFormat='Date: {0}'}" TextColor ="White" FontSize="15"/>
<Label Text="{Binding Comment, StringFormat='Comment: {0}'}" TextColor ="White" FontSize="15"/>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
这是我的代码:
public ShowPlanes()
{
InitializeComponent();
var db = new SQLiteConnection(_dbPath);
var data = db.Table<Airplane>().ToList();
myCollectionView.ItemsSource = data;
NavigationPage.SetHasNavigationBar(this, false);
}
如果您的图片非常大,超过 100KB(每张),那么您可以考虑为具有不同文件名和更小尺寸(例如 10-20KB)的相同图片创建缩略图。
这将提高您应用的速度。
要调整图像大小,您可以使用以下代码。该功能将保持原始图像的纵横比。此外,代码会将原始图像设置为 72dpi。结果将是一个经过优化的小文件,可以呈现给您的视图。
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
...
public static void CreatePreviewImage(string imageFullFilename, string previewFullFilename)
{
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
// Create an Encoder object based on the GUID
// for the Quality parameter category.
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
// Create an EncoderParameters object.
// An EncoderParameters object has an array of EncoderParameter
// objects. In this case, there is only one
// EncoderParameter object in the array.
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 75L); //default
myEncoderParameters.Param[0] = myEncoderParameter;
Bitmap originalimage = (Bitmap)System.Drawing.Image.FromFile(imageFullFilename, true);
originalimage.SetResolution(72, 72);
int w = originalimage.Width;
int h = originalimage.Height;
int pw = 0;
int ph = 0;
h = originalimage.Height * w / originalimage.Width;
if (w > h)
{
pw = 200;
ph = h * pw / w;
}
else
{
ph = 200;
pw = w * ph / h;
}
Bitmap previewImage = ImageHandlers.ResizeImage(originalimage, pw, ph);
previewImage.Save(previewFullFilename, jpgEncoder, myEncoderParameters);
}
public static Bitmap ResizeImage(Image image, int width, int height)
{
var h = image.Height;
var w = image.Width;
if (w > h)
{
height = h * width / w;
} else if( h < w )
{
width = w * height / h;
}
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
public static ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
如果您的图片很大,请尝试将其调整为您需要的尺寸,也许它会解决这个问题,下面是很好的参考。
https://docs.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/xamformsimageresize/
这是调整大小的工作代码:
var bitmap = SKBitmap.Decode(Path);
int h = bitmap.Height;
int w = bitmap.Width;
int newWidth = w;
int newHeight = h;
if (h > 1080 || w > 1080)
{
int rectHeight = 1080;
int rectWidth = 1080;
//aspect ratio calculation
float W = w;
float H = h;
float aspect = W / H;
await DisplayAlert("aspect", aspect.ToString() + w.ToString() + h.ToString(), "OK");
//new dimensions by aspect ratio
newWidth = (int)(rectWidth * aspect);
newHeight = (int)(newWidth / aspect);
await DisplayAlert("aspect", "h " + newHeight.ToString() + " w " + newWidth.ToString(), "OK");
//if one of the two dimensions exceed the box dimensions
if (newWidth > rectWidth || newHeight > rectHeight)
{
//depending on which of the two exceeds the box dimensions set it as the box dimension and calculate the other one based on the aspect ratio
if (newWidth > newHeight)
{
newWidth = rectWidth;
newHeight = (int)(newWidth / aspect);
}
else
{
newHeight = rectHeight;
newWidth = (int)(newHeight * aspect);
}
}
}
var resizedImage = bitmap.Resize(new SKImageInfo(newWidth, newHeight), SKBitmapResizeMethod.Lanczos3);
var image = resizedImage.Encode(SKEncodedImageFormat.Jpeg, 80);
var path = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var filepath = System.IO.Path.Combine(path, fileName);
string finalPath = filepath;
using (var stream = File.OpenWrite(filepath))
image.SaveTo(stream);
return finalPath;
}
当我在 CollectionView 中滚动时,它开始滞后,可能是在加载下一张图片。我能用它做什么?我该如何优化它?
这里是XAML:
<Grid BackgroundColor="#00aeef">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<CollectionView x:Name="myCollectionView" Grid.Row="0">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame Padding="0" BackgroundColor="#00d2ff" Margin="20" CornerRadius="30">
<StackLayout Padding="20">
<Label Text="{Binding Airline}" TextColor ="White" FontSize="30" HorizontalOptions="Center"/>
<Image Source="{Binding Url}" HeightRequest="200"/>
<Label Text="{Binding Plane, StringFormat='Plane: {0}'}" TextColor ="White" FontSize="15"/>
<Label Text="{Binding Airline, StringFormat='Airline: {0}'}" TextColor ="White" FontSize="15"/>
<Label Text="{Binding Livery, StringFormat='Livery: {0}'}" TextColor ="White" FontSize="15"/>
<Label Text="{Binding Registration, StringFormat='Reg: {0}'}" TextColor ="White" FontSize="15"/>
<Label Text="{Binding Airport, StringFormat='Airport: {0}'}" TextColor ="White" FontSize="15"/>
<Label Text="{Binding Date, StringFormat='Date: {0}'}" TextColor ="White" FontSize="15"/>
<Label Text="{Binding Comment, StringFormat='Comment: {0}'}" TextColor ="White" FontSize="15"/>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
这是我的代码:
public ShowPlanes()
{
InitializeComponent();
var db = new SQLiteConnection(_dbPath);
var data = db.Table<Airplane>().ToList();
myCollectionView.ItemsSource = data;
NavigationPage.SetHasNavigationBar(this, false);
}
如果您的图片非常大,超过 100KB(每张),那么您可以考虑为具有不同文件名和更小尺寸(例如 10-20KB)的相同图片创建缩略图。
这将提高您应用的速度。
要调整图像大小,您可以使用以下代码。该功能将保持原始图像的纵横比。此外,代码会将原始图像设置为 72dpi。结果将是一个经过优化的小文件,可以呈现给您的视图。
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
...
public static void CreatePreviewImage(string imageFullFilename, string previewFullFilename)
{
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
// Create an Encoder object based on the GUID
// for the Quality parameter category.
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
// Create an EncoderParameters object.
// An EncoderParameters object has an array of EncoderParameter
// objects. In this case, there is only one
// EncoderParameter object in the array.
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 75L); //default
myEncoderParameters.Param[0] = myEncoderParameter;
Bitmap originalimage = (Bitmap)System.Drawing.Image.FromFile(imageFullFilename, true);
originalimage.SetResolution(72, 72);
int w = originalimage.Width;
int h = originalimage.Height;
int pw = 0;
int ph = 0;
h = originalimage.Height * w / originalimage.Width;
if (w > h)
{
pw = 200;
ph = h * pw / w;
}
else
{
ph = 200;
pw = w * ph / h;
}
Bitmap previewImage = ImageHandlers.ResizeImage(originalimage, pw, ph);
previewImage.Save(previewFullFilename, jpgEncoder, myEncoderParameters);
}
public static Bitmap ResizeImage(Image image, int width, int height)
{
var h = image.Height;
var w = image.Width;
if (w > h)
{
height = h * width / w;
} else if( h < w )
{
width = w * height / h;
}
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
public static ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
如果您的图片很大,请尝试将其调整为您需要的尺寸,也许它会解决这个问题,下面是很好的参考。
https://docs.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/xamformsimageresize/
这是调整大小的工作代码:
var bitmap = SKBitmap.Decode(Path);
int h = bitmap.Height;
int w = bitmap.Width;
int newWidth = w;
int newHeight = h;
if (h > 1080 || w > 1080)
{
int rectHeight = 1080;
int rectWidth = 1080;
//aspect ratio calculation
float W = w;
float H = h;
float aspect = W / H;
await DisplayAlert("aspect", aspect.ToString() + w.ToString() + h.ToString(), "OK");
//new dimensions by aspect ratio
newWidth = (int)(rectWidth * aspect);
newHeight = (int)(newWidth / aspect);
await DisplayAlert("aspect", "h " + newHeight.ToString() + " w " + newWidth.ToString(), "OK");
//if one of the two dimensions exceed the box dimensions
if (newWidth > rectWidth || newHeight > rectHeight)
{
//depending on which of the two exceeds the box dimensions set it as the box dimension and calculate the other one based on the aspect ratio
if (newWidth > newHeight)
{
newWidth = rectWidth;
newHeight = (int)(newWidth / aspect);
}
else
{
newHeight = rectHeight;
newWidth = (int)(newHeight * aspect);
}
}
}
var resizedImage = bitmap.Resize(new SKImageInfo(newWidth, newHeight), SKBitmapResizeMethod.Lanczos3);
var image = resizedImage.Encode(SKEncodedImageFormat.Jpeg, 80);
var path = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var filepath = System.IO.Path.Combine(path, fileName);
string finalPath = filepath;
using (var stream = File.OpenWrite(filepath))
image.SaveTo(stream);
return finalPath;
}