我们有一个应用程序想要显示大量图像(超过 30 个)。由于每个图像都有一些独特的功能,因此我们使用自定义控件实现了集合视图。
集合视图允许用户将列数从一调整为三。这样可以灵活地关注单个图像或查看所有图片的更广泛概览。
每个图像不会以链接形式存储在设备上;相反,它被保存为 SQLite 数据库中的 byte[]。
<CollectionView
x:Name="CollectionView"
HorizontalScrollBarVisibility="Always"
IsVisible="{Binding ShowAttachments}"
ItemsSource="{Binding Attachments}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="{Binding GirdColumns}" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="activity:Attachment">
<customControls:ImageControl
Title="{Binding Comment, Mode=TwoWay}"
ContainerHeightRequest="200"
FavoriteCommand="{Binding Path=UpdateFavoriteStateCommand, Source={RelativeSource AncestorType={x:Type activityDetail:ActivityDetailViewModel}}}"
FavoriteCommandParameter="{Binding .}"
Glyph="chat_bubble"
ImageDoubleTappedCommand="{Binding Path=GoToEditViewOnAttachmentDoubleTappedCommand, Source={RelativeSource AncestorType={x:Type activityDetail:ActivityDetailViewModel}}}"
ImageDoubleTappedCommandParameter="{Binding .}"
ImageSource="{Binding Data, Converter={StaticResource ByteArrayToImageSourceConverter}}"
ImageTappedCommand="{Binding Path=ShowAttachmentDetailCommand, Source={RelativeSource AncestorType={x:Type activityDetail:ActivityDetailViewModel}}}"
ImageTappedCommandParameter="{Binding .}"
ImageWidthRequest="180"
IsFavorite="{Binding IsFavorite}"
QuickActionCommand="{Binding Path=ShowChatCommand, Source={RelativeSource AncestorType={x:Type activityDetail:ActivityDetailViewModel}}}"
QuickActionCommandParameter="{Binding .}" />
</DataTemplate>
</CollectionView.ItemTemplate>
图像控制:
<Border
x:Class="SomeAwesomeNamespace.Controls.ImageControl"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Name="ImageControlItem"
Padding="5"
HeightRequest="330"
Stroke="Black"
StrokeShape="RoundRectangle 5">
<Grid BindingContext="{x:Reference ImageControlItem}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Aspect="AspectFit"
HorizontalOptions="Center"
MaximumHeightRequest="250"
Source="{Binding ImageSource}"
VerticalOptions="Start">
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding ImageTappedCommand}"
CommandParameter="{Binding ImageTappedCommandParameter}"
NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
<VerticalStackLayout
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
HorizontalOptions="End">
<Button
Margin="3"
Padding="0"
BackgroundColor="{StaticResource Primary}"
Command="{Binding ImageDoubleTappedCommand}"
CommandParameter="{Binding ImageDoubleTappedCommandParameter}"
HeightRequest="40"
VerticalOptions="Start"
WidthRequest="40">
<Button.ImageSource>
<FontImageSource
FontFamily="IconFont"
Glyph="edit"
Size="20" />
</Button.ImageSource>
</Button>
<Button
Margin="3"
Padding="0"
BackgroundColor="{StaticResource Primary}"
Command="{Binding FavoriteCommand}"
CommandParameter="{Binding FavoriteCommandParameter}"
HeightRequest="40"
VerticalOptions="Start"
WidthRequest="40">
<Button.ImageSource>
<FontImageSource
FontFamily="IconFont"
Glyph="{Binding IsFavorite, Converter={StaticResource VisibleInvisibleIconConverter}}"
Size="20" />
</Button.ImageSource>
</Button>
</VerticalStackLayout>
<Editor
Grid.Row="1"
Grid.Column="0"
BackgroundColor="White"
HeightRequest="80"
HorizontalTextAlignment="Start"
Opacity="0.7"
Placeholder="Notiz"
Text="{Binding Title, Mode=TwoWay}"
VerticalOptions="End" />
<Button
Grid.Row="1"
Grid.Column="1"
Padding="5"
BackgroundColor="{StaticResource Primary}"
Command="{Binding QuickActionCommand}"
CommandParameter="{Binding QuickActionCommandParameter}"
CornerRadius="15"
HeightRequest="30"
HorizontalOptions="End"
VerticalOptions="Center"
WidthRequest="30">
<Button.ImageSource>
<FontImageSource
FontFamily="IconFont"
Glyph="{Binding Glyph}"
Size="15"
Color="{StaticResource White}" />
</Button.ImageSource>
</Button>
</Grid>
此实现的问题是,如果我们有大量图像(超过 30 个),应用程序就会滞后。此外,当使用“MPowerKit.MediaPlugin”导入图像且数量超过 10 时,应用程序崩溃并出现以下错误:
安卓 例外 - 此事件 错误 02:59:52.000 下午 RuntimeException:画布:尝试使用回收的位图 android.graphics.Bitmap@446f22f 网络事件 信息 02:59:51.623 下午
{ 操作:NETWORK_CAPABILITIES_CHANGED, 下载带宽:28154, 网络类型:蜂窝网络, 上传带宽:20245, VPN_活动:假 } 例外 致命的 02:59:51.513 下午 画布:尝试使用回收的位图 android.graphics.Bitmap@446f22f Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics 警告 02:59:50.832 下午 指定的 x:DataType (Someawesome.nampespace.Features.Activities.Attachment) 与当前绑定上下文 (Someawesome.nampespace.UI.Controls.ImageControl) 不匹配。 Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics 警告 02:59:50.823 下午 指定的 x:DataType (Someawesome.nampespace.Features.Activities.Attachment) 与当前绑定上下文 (Someawesome.nampespace.UI.Controls.ImageControl) 不匹配。 Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics 警告 02:59:50.819 下午 指定的 x:DataType (Someawesome.nampespace.Features.Activities.Attachment) 与当前绑定上下文 (Someawesome.nampespace.UI.Controls.ImageControl) 不匹配。 Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics 警告 02:59:50.811 下午 指定的 x:DataType (Someawesome.nampespace.Features.Activities.Attachment) 与当前绑定上下文 (Someawesome.nampespace.UI.Controls.ImageControl) 不匹配。 Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics 警告 02:59:50.805 下午 指定的 x:DataType (Someawesome.nampespace.Features.Activities.Attachment) 与当前绑定上下文 (Someawesome.nampespace.UI.Controls.ImageControl) 不匹配。 Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics 警告 02:59:50.797 下午 指定的 x:DataType (Someawesome.nampespace.Features.Activities.Attachment) 与当前绑定上下文 (Someawesome.nampespace.UI.Controls.ImageControl) 不匹配。
ios WatchdogTermination:操作系统看门狗终止了您的应用程序,可能是因为它过度使用了 RAM。
我们似乎在显示新添加的数据时遇到问题。有没有一种有效的方法来处理集合视图中的许多图像?
谢谢您的帮助! <3
更新:
我更改了工作流程,以便将存储在数据库中的图像复制到应用程序的目录中。
private async Task LoadImagesToLocalStorage(Guid activityId, Attachment attachment)
{ if (!string.IsNullOrWhiteSpace(attachment.LocalPath) && File.Exists(attachment.LocalPath)) { 返回; }
// Ensure the directory exists
var cacheDir = FileSystem.Current.AppDataDirectory;
var localFilePath = Path.Combine(cacheDir, attachment.Name);
if (File.Exists(localFilePath))
{
attachment.LocalPath = localFilePath;
}
else
{
try
{
// create stream from byte array
using MemoryStream sourceStream = new MemoryStream(attachment.Data);
await using FileStream localFileStream = File.Open(localFilePath, FileMode.OpenOrCreate);
await sourceStream.CopyToAsync(localFileStream);
attachment.LocalPath = localFilePath;
}
catch (Exception e)
{
_logger.LogError(e, e.Message);
return;
}
}
await _attachmentDatabase.SaveAttachment(activityId, attachment, CancellationToken.None)
.ConfigureAwait(false);
}
性能差异巨大!所以效果很好。问题是,是否有“正确”的方式保存图像,或者是否有更好的方法来创建图像的本地副本
最大的性能改进是将ImageSource更改为路径。 为此,我们实现了一种方法,将本地副本保存到存储中。