Flutter仿照微信实现九宫格头像

一、效果图

2、主要代码

c 复制代码
import 'dart:io';
import 'dart:math';

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';

class ImageGrid extends StatelessWidget {
  final List<String> imageUrls; // 假设这是你的图片URL列表
  final double containerSize = 72.0; // 容器大小
  final double padding = 3.0; // 图片距离容器的宽度
  final double spacing = 2.0; // 图片之间的间隔

  ImageGrid({required this.imageUrls});

  double calculateImageWidth(int count) {
    double containerWidth = 72;
    double padding = 3;
    double gap = 2;

    if (count <= 4) {
      return (containerWidth - padding * 2 - gap) / 2;
    } else {
      return (containerWidth - padding * 2 - gap * 2) / 3;
    }
  }

  Widget _buildGrid() {
    double imageWidth = calculateImageWidth(imageUrls.length);
    int imageCount = imageUrls.length > 9 ? 9 : imageUrls.length;
    if (imageCount == 1) {
      // 一张图片铺满
      return Center(
        child: Container(
          width: containerSize,
          height: containerSize,
          child: Image.network(
            imageUrls[0],
            fit: BoxFit.cover,
          ),
        ),
      );
    } else {
      int rowCount = 1; //几行
      int firstNumber = 0; //第一行显示几个0不做特别处理
      int cellCount = 1; //几列
      if (imageCount == 2) {
        rowCount = 1;
        cellCount = 2;
      } else if (imageCount == 4 || imageCount == 6) {
        rowCount = 2;
        cellCount = imageCount == 4 ? 2 : 3;
      } else if (imageCount == 9) {
        rowCount = 3;
        cellCount = 3;
      } else if (imageCount == 3) {
        rowCount = 2;
        firstNumber = 1;
        cellCount = 2;
      } else if (imageCount == 5) {
        rowCount = 2;
        firstNumber = 2;
        cellCount = 3;
      } else if (imageCount == 7) {
        rowCount = 3;
        firstNumber = 1;
        cellCount = 3;
      } else if (imageCount == 8) {
        rowCount = 3;
        firstNumber = 2;
        cellCount = 3;
      }
      // 两张图片并排
      return Padding(
        padding: EdgeInsets.all(spacing),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            if (firstNumber != 0)
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: List.generate(firstNumber, (cellIndex) {
                  return Row(
                    children: [
                      getImageWidget(cellIndex, imageWidth),
                      if (cellIndex != firstNumber - 1)
                        SizedBox(width: spacing),
                    ],
                  );
                }),
              ),
            if (firstNumber != 0 && rowCount > 1) SizedBox(height: spacing),
            ...List.generate(rowCount - (firstNumber != 0 ? 1 : 0), (rowIndex) {
              return Column(
                children: [
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: List.generate(cellCount, (cellIndex) {
                      int index =
                          firstNumber + rowIndex * cellCount + cellIndex;
                      return Row(
                        children: [
                          getImageWidget(index, imageWidth),
                          if (cellIndex != cellCount - 1)
                            SizedBox(width: spacing),
                        ],
                      );
                    }),
                  ),
                  if (rowIndex != rowCount - (firstNumber != 0 ? 2 : 1))
                    SizedBox(height: spacing),
                ],
              );
            }),
          ],
        ),
      );
    }
  }

//生成 图片wrapper
  getImageWidget(int index, double width) {
    if (!imageUrls[index].contains("http")) {
      return Image.file(File(imageUrls[index]),
          width: width, height: width, fit: BoxFit.cover);
    } else {
      return CachedNetworkImage(
        imageUrl: imageUrls[index],
        width: width,
        height: width,
        fit: BoxFit.cover,
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(6),
      child: Container(
        width: containerSize,
        height: containerSize,
        decoration: BoxDecoration(
          //  color: Color(0xFFEEEEEE),
          color: Color.fromARGB(255, 243, 4, 4),
          borderRadius: BorderRadius.circular(6),
        ),
        child: _buildGrid(),
      ),
    );
  }
}
相关推荐
Geek_Vison5 小时前
保险APP已经用了Flutter,还能接入小程序吗?
flutter·小程序·uni-app·mpaas·小程序容器
FungLeo5 小时前
成为全栈·Flutter App 篇·go_router 与四 Tab App Shell:保留导航状态、深链和登录回跳
flutter·移动开发·成为全栈·go_router·路由设计·深链接
m0_738185826 小时前
Flutter 鸿蒙化实战:screen_protector 适配 OpenHarmony,防截屏/防泄露
flutter·华为·harmonyos·鸿蒙
梦想的颜色11 小时前
【编程实战】AI 时代 APP 开发全栈硬核指南:技术选型 + AI 架构 + 模型落地全维度决策
python·flutter·react native·react.js·ai·桌面应用·milvus
9624561 天前
微信第三方平台 component_access_token 间歇性过期故障技术复盘
微信
yuanlaile1 天前
2026年全新Flutter 跨平台开发全栈学习资料整理
flutter·getx·鸿蒙 next·flutter开发鸿蒙·flutter入门实战·flutter全栈
恋猫de小郭2 天前
Genkit Dart 1.0 发布,Flutter 原生的 AI Agent 终于完整了
android·前端·flutter
第10086个小白2 天前
flutter桌面端打包方式(Inno Setup Compiler)版本
前端·flutter
加我攻城狮2 天前
当大模型把「景区」定位到附近公共厕所:我的 AI 旅行小程序踩坑实录
后端·微信
陆断枫2 天前
Flutter 3.47 动画引擎盘点:Impeller 全平台,和那些"新特性"
flutter