You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Xam.Plugin.Media创建Xamarin.Forms图片画廊

嘿,Jimmy!我看你正在用Xamarin.Forms开发拍照上传的应用,现在卡在了自定义图片画廊的实现上——无限滚动的2x2网格布局对吧?别担心,我一步步给你捋清楚怎么做,结合你现有的代码来调整。

第一步:改造XAML布局,实现2x2网格画廊

你现在的XAML是用StackLayout展示单张图片,我们需要把它改成ScrollView嵌套带BindableLayout的Grid,这样就能动态绑定图片列表,自动排成2列的网格。

替换你的XAML代码成这样:

<ScrollView Margin="20">
    <!-- 保留拍照和同步按钮,放在画廊上方 -->
    <StackLayout>
        <StackLayout Orientation="Horizontal" Margin="0,0,0,20">
            <Button x:Name="CameraButton" BackgroundColor="#95c241" Text="Foto aufnehmen" TextColor="White" Clicked="CameraButton_Clicked" HorizontalOptions="Start" />
            <Button x:Name="SyncButton" BackgroundColor="#95c241" Clicked="SyncButton_Clicked" Text="Synchronisierung" TextColor="White" HorizontalOptions="EndAndExpand" />
        </StackLayout>

        <!-- 核心:2x2网格画廊 -->
        <Grid x:Name="PhotoGalleryGrid" ColumnDefinitions="*,*" RowSpacing="10" ColumnSpacing="10">
            <BindableLayout.ItemTemplate>
                <DataTemplate>
                    <Image Source="{Binding}" Aspect="AspectFill" HeightRequest="150" />
                </DataTemplate>
            </BindableLayout.ItemTemplate>
        </Grid>
    </StackLayout>
</ScrollView>

这里的关键是用BindableLayout把Grid和图片数据源绑定,ColumnDefinitions="*,*"会自动把Grid分成宽度均分的两列,图片会自动填充到网格里。

第二步:从数据库读取图片路径,生成图片源集合

你已经把图片路径存在PhotoTable里了,现在需要从数据库取出所有记录,转换成List<ImageSource>,然后绑定到Grid的数据源上。

在你的MainPage.xaml.cs里添加一个加载画廊数据的方法:

private async Task LoadPhotoGalleryAsync()
{
    // 从数据库获取所有图片记录,按拍摄时间倒序排列
    var photoRecords = await HelperDB.Instance.conn.Table<PhotoTable>()
        .OrderByDescending(p => p.Created_At)
        .ToListAsync();
    
    // 将本地文件路径转换成ImageSource
    var photoSources = new List<ImageSource>();
    foreach (var record in photoRecords)
    {
        // 用FromFile比FromStream更适合本地文件,加载更高效
        var imageSource = ImageSource.FromFile(record.Filename);
        photoSources.Add(imageSource);
    }
    
    // 绑定到Grid的数据源
    BindableLayout.SetItemsSource(PhotoGalleryGrid, photoSources);
}

然后在页面加载时调用这个方法,比如在OnAppearing生命周期里:

protected override async void OnAppearing()
{
    base.OnAppearing();
    await LoadPhotoGalleryAsync();
}

另外,拍完照片保存到数据库后,记得刷新画廊,在saveMediaFile方法的最后加上:

await LoadPhotoGalleryAsync();

这样新拍的照片就能立刻显示在画廊里了。

第三步:实现无限滚动(分页加载)

如果你的图片数量很多,一次性加载所有可能会卡顿,这时候可以做分页加载:

  1. 数据库查询时用Skip和Take实现分页,比如每次加载20张
  2. 监听ScrollView的滚动事件,当滚动到接近底部时加载下一页
  3. 把新的图片源添加到现有集合,而不是替换

示例滚动事件代码:

// 先在XAML的ScrollView上添加Scrolled事件:Scrolled="ScrollView_Scrolled"
private int currentPage = 0;
private const int pageSize = 20;

private async void ScrollView_Scrolled(object sender, ScrolledEventArgs e)
{
    var scrollView = sender as ScrollView;
    // 判断是否滚动到距离底部100像素以内
    var isNearBottom = e.ScrollY + scrollView.Height >= scrollView.ContentSize.Height - 100;
    
    if (isNearBottom)
    {
        currentPage++;
        // 加载下一页数据
        var nextPagePhotos = await HelperDB.Instance.conn.Table<PhotoTable>()
            .OrderByDescending(p => p.Created_At)
            .Skip(currentPage * pageSize)
            .Take(pageSize)
            .ToListAsync();
        
        if (nextPagePhotos.Count > 0)
        {
            var existingSources = (List<ImageSource>)BindableLayout.GetItemsSource(PhotoGalleryGrid);
            foreach (var record in nextPagePhotos)
            {
                existingSources.Add(ImageSource.FromFile(record.Filename));
            }
            // 通知UI更新数据源
            BindableLayout.SetItemsSource(PhotoGalleryGrid, null);
            BindableLayout.SetItemsSource(PhotoGalleryGrid, existingSources);
        }
    }
}

第四步:图片加载优化(避免内存溢出)

Xamarin.Forms自带的Image控件加载大量图片可能会导致内存不足,推荐用FFImageLoading第三方库,它支持缓存、压缩、懒加载,非常适合画廊场景。

先安装NuGet包:Xamarin.FFImageLoading和Xamarin.FFImageLoading.Forms

然后把XAML里的Image换成CachedImage:

<ffimageloading:CachedImage Source="{Binding}" Aspect="AspectFill" HeightRequest="150" 
                            DownsampleToViewSize="True" CacheDuration="30" />

记得在XAML顶部添加命名空间:

xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"

最后几点小提示

  • 确保你的自定义文件夹路径正确,ImageSource.FromFile能找到对应的图片文件,可以打印路径到调试窗口验证
  • 测试时确认Storage权限已经申请并授予,否则无法读取本地文件
  • 如果图片显示异常,检查文件是否被正确保存,路径是否包含特殊字符

这样一步步调整后,你就能实现目标中的2x2无限滚动画廊啦!如果还有细节问题,随时调整就行~

内容的提问来源于stack exchange,提问作者Jimmy Steam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:24:37