Flutter如何修改ListBuilder已创建的组件并实现图片上传Firebase?
问题核心原因
你当前的写法有两个核心问题导致无法修改已创建的组件:
- 不应该直接将渲染好的Widget存储在列表中,Flutter是状态驱动UI的框架,正确的做法是存储业务数据,由数据实时生成UI
- 你只用了一个全局的
_imagePickerFile变量存储选中的图片,所有列表项共用这一个变量,既无法区分每个项的图片,也无法触发已生成组件的更新
完整修改方案
1. 替换存储列表
将原来存Widget的列表替换为存每个位置对应图片的列表:
// 替换掉原来的 List<InkWell> _productFormList = [] List<PickedFile?> _productImages = [];
2. 修改新增按钮逻辑
新增的时候给图片列表添加一个空占位,代表该位置还未选择图片:
_addButton() { return Container( width: 200, height: 65, child: ElevatedButton( onPressed: () { setState(() { _productImages.add(null); }); }, child: Text( 'Add Container', ), )); }
3. 修改图片选择方法
新增index参数,用于标识当前要修改的是第几个列表项的图片:
Future<void> choosenImageWithPicker(int index) async { try { final _image = await _picker.getImage(source: ImageSource.gallery); setState(() { // 只更新对应位置的图片数据 _productImages[index] = _image; }); } catch (err) { print(err); } }
4. 修改组件生成方法
接收index参数,读取对应位置的图片数据生成组件:
_productForm(int index) { return InkWell( onTap: () { // 把当前项的index传到选图方法 choosenImageWithPicker(index); }, child: _productImages[index] == null ? Container( color: Colors.grey[300], width: 200, height: 200, child: Center(child: Text("No image"))) : Container( width: 200, height: 200, child: Image.network( _productImages[index]!.path, ), ), ); }
5. 修改ListView逻辑
不需要再读预存的组件列表,直接根据当前图片列表实时生成组件:
ListView.separated( scrollDirection: Axis.horizontal, shrinkWrap: true, itemBuilder: (context, index) { return _productForm(index); }, separatorBuilder: (BuildContext context, int index) { return SizedBox( width: 20, ); }, itemCount: _productImages.length, )
修改之后每次选择图片只会更新对应index位置的图片数据,setState触发重绘时会自动更新对应位置的组件,不需要手动修改已创建的组件。后续要上传到Firebase的时候,直接遍历_productImages列表读取所有图片文件即可。
内容的提问来源于stack exchange,提问作者Kevin Yang
相关产品推荐
相关产品推荐

