在这里插入图片描述

前言

图片九宫格是社交应用中展示多图内容的标准布局方式。根据图片数量的不同,九宫格需要自适应调整布局结构,单图全宽展示,双图并排,三图及以上采用网格布局。本文将详细讲解如何在Flutter和OpenHarmony平台上实现智能自适应的图片九宫格组件。

Flutter九宫格实现

首先实现根据图片数量自动调整布局的核心逻辑。

class ImageGrid extends StatelessWidget {
  final List<String> images;
  final Function(int) onImageTap;
  final double spacing;
  
  const ImageGrid({
    Key? key,
    required this.images,
    required this.onImageTap,
    this.spacing = 4.0,
  }) : super(key: key);

ImageGrid组件接收图片URL列表和点击回调。spacing参数控制图片之间的间距,默认4像素。onImageTap回调传递被点击图片的索引,用于实现图片预览功能。

  
  Widget build(BuildContext context) {
    if (images.isEmpty) return SizedBox.shrink();
    
    final count = images.length;
    
    if (count == 1) {
      return _buildSingleImage();
    }
    
    return GridView.builder(
      shrinkWrap: true,
      physics: NeverScrollableScrollPhysics(),
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: count == 4 ? 2 : 3,
        mainAxisSpacing: spacing,
        crossAxisSpacing: spacing,
      ),
      itemCount: count > 9 ? 9 : count,
      itemBuilder: (context, index) {
        return _buildGridItem(index);
      },
    );
  }

build方法根据图片数量选择不同的布局策略。单图使用专门的方法处理,多图使用GridView。crossAxisCount根据图片数量动态调整,4张图使用2列布局更美观,其他情况使用3列。shrinkWrap和NeverScrollableScrollPhysics确保GridView在Column中正确工作。

  Widget _buildSingleImage() {
    return GestureDetector(
      onTap: () => onImageTap(0),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(8),
        child: AspectRatio(
          aspectRatio: 16 / 9,
          child: Image.network(
            images[0],
            fit: BoxFit.cover,
          ),
        ),
      ),
    );
  }

单图布局使用AspectRatio保持16:9的宽高比,这是社交应用中常见的图片展示比例。ClipRRect添加圆角效果,GestureDetector处理点击事件。单图全宽展示能够最大化利用屏幕空间,给用户更好的视觉体验。

  Widget _buildGridItem(int index) {
    final isLast = index == 8 && images.length > 9;
    
    return GestureDetector(
      onTap: () => onImageTap(index),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(4),
        child: Stack(
          fit: StackFit.expand,
          children: [
            Image.network(
              images[index],
              fit: BoxFit.cover,
            ),
            if (isLast)
              Container(
                color: Colors.black54,
                child: Center(
                  child: Text(
                    '+${images.length - 9}',
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 24,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
              ),
          ],
        ),
      ),
    );
  }
}

_buildGridItem构建网格中的单个图片项。当图片超过9张时,最后一个位置显示剩余数量的遮罩层,点击可查看全部图片。Stack实现图片和遮罩的叠加,StackFit.expand让子元素填满整个区域。这种设计在微信朋友圈等主流社交应用中广泛使用。

OpenHarmony ArkTS实现

鸿蒙系统上的九宫格实现。

@Component
struct ImageGrid {
  @Prop images: string[] = []
  @Prop spacing: number = 4
  onImageTap: (index: number) => void = () => {}
  
  build() {
    if (this.images.length === 0) {
      return
    }
    
    if (this.images.length === 1) {
      this.SingleImage()
    } else {
      this.MultipleImages()
    }
  }

组件根据图片数量选择不同的构建方法。ArkTS的条件渲染直接在build方法中使用if语句,语法更加直观。

  @Builder
  SingleImage() {
    Image(this.images[0])
      .width('100%')
      .aspectRatio(16 / 9)
      .objectFit(ImageFit.Cover)
      .borderRadius(8)
      .onClick(() => this.onImageTap(0))
  }

@Builder装饰器定义单图布局方法。aspectRatio设置宽高比,objectFit确保图片填充整个区域。onClick绑定点击事件。

  @Builder
  MultipleImages() {
    Grid() {
      ForEach(this.images.slice(0, 9), (url: string, index: number) => {
        GridItem() {
          Stack() {
            Image(url)
              .width('100%')
              .height('100%')
              .objectFit(ImageFit.Cover)
              .borderRadius(4)
            
            if (index === 8 && this.images.length > 9) {
              Column() {
                Text(`+${this.images.length - 9}`)
                  .fontSize(24)
                  .fontWeight(FontWeight.Bold)
                  .fontColor(Color.White)
              }
              .width('100%')
              .height('100%')
              .backgroundColor('#00000088')
              .justifyContent(FlexAlign.Center)
            }
          }
          .onClick(() => this.onImageTap(index))
        }
      })
    }
    .columnsTemplate(this.getColumnsTemplate())
    .rowsGap(this.spacing)
    .columnsGap(this.spacing)
    .width('100%')
    .height(this.getGridHeight())
  }

Grid组件实现多图网格布局。ForEach遍历图片列表,slice(0, 9)限制最多显示9张。Stack实现图片和遮罩的叠加,条件渲染在最后一张图片上显示剩余数量。columnsTemplate和height根据图片数量动态计算。

  getColumnsTemplate(): string {
    const count = this.images.length
    if (count === 2) return '1fr 1fr'
    if (count === 4) return '1fr 1fr'
    return '1fr 1fr 1fr'
  }
  
  getGridHeight(): number {
    const count = Math.min(this.images.length, 9)
    const rows = Math.ceil(count / (count === 4 ? 2 : 3))
    return rows * 100 + (rows - 1) * this.spacing
  }
}

getColumnsTemplate根据图片数量返回列模板字符串,1fr表示等分剩余空间。getGridHeight计算网格高度,考虑行数和间距。这种动态计算确保不同数量的图片都能有合适的展示效果。

图片预览功能扩展

在Flutter中实现图片预览:

void _showImagePreview(BuildContext context, int initialIndex) {
  Navigator.push(
    context,
    MaterialPageRoute(
      builder: (context) => ImagePreviewPage(
        images: images,
        initialIndex: initialIndex,
      ),
    ),
  );
}

点击图片时调用此方法跳转到预览页面,传递图片列表和初始索引。预览页面通常支持左右滑动切换、双指缩放、保存图片等功能。

总结

本文详细介绍了图片九宫格组件在Flutter和OpenHarmony两个平台上的实现。九宫格是社交应用展示多图内容的标准方式,需要根据图片数量智能调整布局。两个平台都提供了灵活的网格布局组件,开发者可以根据需求扩展图片预览、长按保存等功能。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐