Flutter分屏加载两张服务器图片时第二张覆盖第一张如何解决
问题根因
你遇到的第二张图片选中后第一张丢失的核心原因是选择图片后的跳转逻辑错误:
- 你在选中图片后调用
Navigator.of(context).pushReplacement销毁了当前页面,重新创建了一个BeforeAfter2页面,且只传入了当前选中的单张图片参数,另一张图片没有传值,新页面的对应参数默认是null,自然就丢失了上一次选择的图片。 - 同时你还存在大量重复代码、全局变量滥用、没必要的页面销毁重建问题,性能和可维护性都很差。
最优实现方案
完全不需要跳转页面,直接在当前页面的State中维护选中的图片状态,选图列表用底部弹窗承载,选中后直接更新当前页面状态即可,核心实现代码如下:
import 'dart:convert'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:lifetb/constants/my_colors.dart'; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; // 全局变量仅保留用户基础信息,页面状态全部存在State中 var id; var username; var email; class BeforeAfter2 extends StatefulWidget { const BeforeAfter2({Key? key}) : super(key: key); @override _BeforeAfter2State createState() => _BeforeAfter2State(); } class _BeforeAfter2State extends State<BeforeAfter2> { // 两张选中的图片状态存储在当前页面State中 String? imageSelected1; String? imageSelected2; // 标记当前要选择的是第几区的图片 int? _currentSelectIndex; // 缓存用户图片列表,避免每次选图都重复请求接口 List? _imageList; @override void initState() { super.initState(); // 进入页面预加载用户信息和图片列表 _loadImageList(); } Future<void> _loadUserInfo() async { SharedPreferences preferences = await SharedPreferences.getInstance(); username = preferences.getString("username"); id = preferences.getString("id"); email = preferences.getString("email"); } Future<void> _loadImageList() async { await _loadUserInfo(); if (id == null) return; var url = "http://10.0.2.2/641984.php"; var data = {"user_id": "$id"}; var response = await http.post(Uri.parse(url), body: data); if (mounted) { setState(() { _imageList = jsonDecode(response.body); }); } } // 统一的选图弹窗,一套逻辑支持两个区域选图,无需写两套重复代码 void _showImagePicker(int selectIndex) { setState(() { _currentSelectIndex = selectIndex; }); showModalBottomSheet( context: context, isScrollControlled: true, builder: (context) { if (_imageList == null) { return const Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Text('加载中...'), Center(child: CircularProgressIndicator()) ], ); } else if (_imageList!.isEmpty) { return const Padding( padding: EdgeInsets.all(15), child: Text("你还没有上传任何图片") ); } return GridView.builder( padding: const EdgeInsets.all(10), itemCount: _imageList!.length, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, crossAxisSpacing: 10, mainAxisSpacing: 10 ), itemBuilder: (context, i) { final imagePath = _imageList![i]["post_image"]; return InkWell( onTap: () { // 选中图片后直接更新当前页面状态,无需跳转 setState(() { if (_currentSelectIndex == 1) { imageSelected1 = imagePath; } else { imageSelected2 = imagePath; } }); Navigator.pop(context); }, child: Container( decoration: BoxDecoration( border: Border.all(color: Colors.deepPurple.shade500, width: 2), borderRadius: BorderRadius.circular(35), image: DecorationImage( fit: BoxFit.cover, image: NetworkImage("http://10.0.2.2/upload/$imagePath"), ) ), ), ); }, ); }, ); } @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( body: Column( children: [ Expanded( flex: 1, child: SizedBox( width: double.infinity, child: imageSelected1 == null ? _buildAddArea(1, "添加第一张图片") : Image.network("http://10.0.2.2/upload/$imageSelected1", fit: BoxFit.cover), ), ), Expanded( flex: 1, child: SizedBox( width: double.infinity, child: imageSelected2 == null ? _buildAddArea(2, "添加第二张图片") : Image.network("http://10.0.2.2/upload/$imageSelected2", fit: BoxFit.cover), ), ), ], ), ) ); } Widget _buildAddArea(int index, String text) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(text), const SizedBox(height: 26), FloatingActionButton( heroTag: "addBtn$index", child: const Icon(Icons.add, color: white, size: 45), onPressed: () => _showImagePicker(index), ) ], ); } }
核心优化点
- 移除了不必要的页面跳转逻辑,选中图片直接更新当前页面状态,两张图片的选中状态不会互相覆盖
- 合并了重复的选图逻辑,一套代码支持两个区域使用,大幅降低维护成本
- 预加载图片列表,不用每次触发选图都重新请求接口,性能更优
- 所有页面相关状态都存储在当前页面的State中,没有滥用全局变量,避免出现状态污染问题
内容的提问来源于stack exchange,提问作者NoOoR
相关产品推荐
相关产品推荐

