有没有办法在Flutter中创建一个图像网格(用户添加的图像),网格中的每个新图像都添加到添加按钮之前?

gcuhipw9  于 2023-04-13  发布在  Flutter
关注(0)|答案(2)|浏览(102)

我是Flutter的一部分新手。我试图实现一个对话框,它带有一个可扩展的图像网格(由用户添加的图像),每次用户添加图像(使用添加/加按钮)时,添加的图像都会插入到添加/加按钮之前。
用图画来表达我想要达到的目标:enter image description here
我希望我的问题/代码/图像是有意义的。提前感谢。
我当前的不完整代码:

List<Widget> getAttachFileDialogContent() {
    List<Widget> content = [];
    content.add(
      Column(
        children: [
          Container(
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(20),
                border: Border.all(
                  color: purple1.withOpacity(0.25),
                )),
            margin: const EdgeInsets.only(left: 16, right: 16, bottom: 8),
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
            width: double.infinity,
            height: 135,
            child: //I want to use the grid here,
                   //I tried to use GridView, but didn't know how to add/insert images
                   //Even if I had added images, I couldn't know how to add to specific index 
                     position
          ),

        MyElevatedButton(
                width: 100,
                text: 'Done',
                elevation: 0,
                onPressed: () {},
              ),
            ],
          ),
        ],
      ),
    );
    return content;
  }
aij0ehis

aij0ehis1#

你可以使用flutter中的GridView。https://docs.flutter.dev/cookbook/lists/grid-lists
或者如果你想要任何例子。请访问Medium.com并搜索你想要的。你可以找到更多由经验丰富的开发人员发布的信息。例如:https://medium.com/flutter-community/flutter-widgets-grid-view-the-whole-picture-34d2dd6dff9f

ui7jx7zq

ui7jx7zq2#

如果我理解你想要什么,它有点类似于我正在做的,除了不是把图像在GrindView我把他们在一个轮播.在这个例子中,我编辑一个广告的虚拟商店.图像的一部分被添加到一个临时列表中之前按下添加按钮.这还没有实现.但我认为这可能会帮助你.

import 'package:ecommerce/models/product.dart';
import 'package:ecommerce/screens/edit_product/components/images_form.dart';
import 'package:flutter/material.dart';

class EditProductScreen extends StatelessWidget {
  const EditProductScreen({Key? key, required this.product}) : super(key: key);

  final Product product;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Editar Anúncio'),
        centerTitle: true,
      ),
      body: ListView(
        children: [
          ImagesForm(product: product),
        ],
      ),
    );
  }
}
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart' show kIsWeb;

import 'package:ecommerce/models/product.dart';
import 'package:ecommerce/screens/edit_product/components/image_source_sheet.dart';
import 'package:ecommerce/screens/edit_product/components/image_source_web.dart';

import 'package:carousel_slider/carousel_slider.dart';
import 'package:universal_html/html.dart' as html;

class ImagesForm extends StatelessWidget {
  const ImagesForm({
    Key? key,
    this.product,
    this.imageSourceSheet,
  }) : super(key: key);

  final Product? product;
  final ImageSourceSheet? imageSourceSheet;

  @override
  Widget build(BuildContext context) {
    return FormField<List<dynamic>>(
      initialValue: List.from(product!.images!),
      builder: (state) {
        void onImageSelected(File file) {
          state.value!.add(file);
          state.didChange(state.value);
          Navigator.of(context).pop();
        }

        void onImageSelectedList(List<File> files) {
          state.value!.addAll(files);
          state.didChange(state.value);
          Navigator.of(context).pop();
        }

        void onImageSelectedWeb(List<html.File> files) async {
          for (html.File file in files) {
            html.FileReader reader = html.FileReader();
            reader.readAsDataUrl(file);
            reader.onLoadEnd.listen((event) {
              state.value!.add(reader.result.toString());
              state.didChange(state.value);
            });
          }
          Navigator.of(context).pop();
        }

        Widget buildImageSourceSheet() {
          if (kIsWeb) {
            return ImageSourceWeb(
              onImageSelectedWeb: onImageSelectedWeb,
            );
          } else if (imageSourceSheet?.local == 'gallery') {
            return ImageSourceSheet(
              onImageSelectedList: onImageSelectedList,
            );
          } else {
            return ImageSourceSheet(
                onImageSelected: onImageSelected,
                onImageSelectedList: onImageSelectedList);
          }
        }

        return CarouselSlider(
          options: CarouselOptions(
            initialPage: 0,
            enableInfiniteScroll: state.value!.isEmpty ? false : true,
            height: 400,
            enlargeCenterPage: true,
            disableCenter: true,
          ),
          items: state.value!.map<Widget>((image) {
            return Stack(
              fit: StackFit.expand,
              children: <Widget>[
                if (image is String)
                  Image.network(
                    image,
                    fit: BoxFit.cover,
                  )
                else if (image is File)
                  Image.file(
                    image,
                    fit: BoxFit.cover,
                  ),
                Align(
                  alignment: Alignment.topRight,
                  child: IconButton(
                    icon: const Icon(
                      Icons.delete,
                      size: 40,
                      color: Colors.red,
                    ),
                    onPressed: () {
                      state.value!.remove(image);
                      state.didChange(state.value);
                    },
                  ),
                )
              ],
            );
          }).toList()
            ..add(
              kIsWeb
                  ? Container(
                      color: Colors.grey[100],
                      child: IconButton(
                          icon: Icon(
                            Icons.add_a_photo,
                            size: 60,
                            color: Theme.of(context).primaryColor,
                          ),
                          onPressed: () {
                            showDialog(
                                context: context,
                                builder: (_) => buildImageSourceSheet());
                          }),
                    )
                  : Material(
                      color: Colors.grey[100],
                      child: IconButton(
                          icon: Icon(
                            Icons.add_a_photo,
                            size: 60,
                            color: Theme.of(context).primaryColor,
                          ),
                          onPressed: () {
                            if (Platform.isAndroid) {
                              showModalBottomSheet(
                                  context: context,
                                  builder: (_) => buildImageSourceSheet());
                            } else if (Platform.isIOS) {
                              showCupertinoModalPopup(
                                  context: context,
                                  builder: (_) => buildImageSourceSheet());
                            } else {
                              showDialog(
                                  context: context,
                                  builder: (_) => buildImageSourceSheet());
                            }
                          })),
            ),
        );
      },
    );
  }
}
import 'dart:async';
import 'package:universal_html/html.dart' as html;
import 'package:flutter/material.dart';

class ImageSourceWeb extends StatelessWidget {
  ImageSourceWeb({Key? key, this.onImageSelectedWeb}) : super(key: key);

  final Function(List<html.File>)? onImageSelectedWeb;

  List<html.File> _files = [];

  Future<void> pickFiles() async {
    final completer = Completer<List<html.File>>();
    final html.FileUploadInputElement input = html.FileUploadInputElement()
      ..accept = 'image/*'
      ..multiple = true;

    input.onChange.listen((e) {
      final files = input.files!;
      completer.complete(files);
    });
    input.click();
    _files = await completer.future;
  }

  Future<void> pickImages() async {
    bool mounted = true;
    try {
      await pickFiles();
      if (mounted && _files.isNotEmpty) {
        final List<html.File> files = List.from(_files);
        onImageSelectedWeb?.call(files);
      }
    } finally {
      mounted = false;
    }
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: const Text('Selecionar fotos:'),
      content: const Text('Escolha as fotos do seu dispositivo!'),
      actions: [
        TextButton(
          onPressed: () async {
            await pickImages();
            //Navigator.of(context).pop();
          },
          child: const Text('Carregar...'),
        ),
        TextButton(
          onPressed: () {
            Navigator.of(context).pop();
          },
          child: const Text('Cancelar'),
        )
      ],
    );
  }
}
import 'dart:io';
import 'dart:async';
import 'package:ecommerce/common/button/custom_text_button.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';

// ignore: must_be_immutable
class ImageSourceSheet extends StatelessWidget {
  ImageSourceSheet({
    Key? key,
    this.onImageSelected,
    required this.onImageSelectedList,
    this.local,
  }) : super(key: key);

  final ImagePicker picker = ImagePicker();

  final Function(File)? onImageSelected;
  final Function(List<File>) onImageSelectedList;

  String? local = '';

  @override
  Widget build(BuildContext context) {
    Future<void> editImage(String? path) async {
      if (path != null) {
        final croppedFile = await ImageCropper().cropImage(
          sourcePath: path,
          compressFormat: ImageCompressFormat.jpg,
          compressQuality: 100,
          uiSettings: [
            AndroidUiSettings(
                toolbarTitle: 'Editar Imagem',
                toolbarColor: Theme
                    .of(context)
                    .primaryColor,
                toolbarWidgetColor: Colors.white,
                initAspectRatio: CropAspectRatioPreset.original,
                lockAspectRatio: false),
            IOSUiSettings(
              title: 'Editar Imagem',
              cancelButtonTitle: 'Cancelar',
              doneButtonTitle: 'Concluir',
            ),
            WebUiSettings(
              context: context,
              presentStyle: CropperPresentStyle.dialog,
              boundary: const CroppieBoundary(
                width: 520,
                height: 520,
              ),
              viewPort: const CroppieViewPort(
                  width: 480, height: 480, type: 'circle'),
              enableExif: true,
              enableZoom: true,
              showZoomer: true,
            ),
          ],
        );
        if (croppedFile != null) {
          final originalFile = File(path);
          await originalFile.writeAsBytes(await croppedFile.readAsBytes());
          onImageSelected!(originalFile);
        }
      }
    }

    Future<void> imgGallery() async {
      local = 'gallery';
      final List<XFile> xfiles = await picker.pickMultiImage();
      final List<File> files = xfiles.map((xfile) => File(xfile.path)).toList();
      if (files.length == 1) {
        File file = files.first;
        editImage(file.path);
      } else {
        onImageSelectedList(List.from(files));
      }
    }

    Future<void> imgCamera() async {
      XFile? photo = await picker.pickImage(source: ImageSource.camera);
      editImage(photo!.path);
    }

    if (Platform.isAndroid) {
      return BottomSheet(
        builder: (_) => Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            CustomTextButton(
              onPressed: () {
                imgCamera();
              },
              text: 'Câmera',
              fontSize: 18,
            ),
            const Divider(
              height: 5,
            ),
            CustomTextButton(
              onPressed: () {
                imgGallery();
              },
              text: 'Galeria',
              fontSize: 18,
            ),
            //const SizedBox(height: 8,),
            const Divider(
              height: 2,
              thickness: 2,
            ),
            CustomTextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              text: 'Cancelar',
              color: Colors.red,
              fontSize: 18,
            ),
          ],
        ),
        onClosing: () {},
      );
    } else if (Platform.isIOS) {
      return CupertinoActionSheet(
        title: const Text('Selecionar a foto para o item:'),
        message: const Text('Escolha a origem da foto!'),
        cancelButton: CupertinoActionSheetAction(
          onPressed: Navigator.of(context).pop,
          child: const Text('Cancelar'),
        ),
        actions: [
          CupertinoActionSheetAction(
            isDefaultAction: true,
            child: const Text('Câmera'),
            onPressed: () {
              imgCamera();
            },
          ),
          CupertinoActionSheetAction(
            child: const Text('Galeria'),
            onPressed: () {
              imgGallery();
            },
          ),
        ],
      );
    } else {
      return AlertDialog(
        title: const Text('Selecionar foto para o item:'),
        content: const Text('Escolher Fotos!'),
        actions: [
          CustomTextButton(
            onPressed: () {
              imgCamera();
            },
            text: 'Câmera',
            fontSize: 18,
          ),
          const Divider(
            height: 5,
          ),
          CustomTextButton(
            onPressed: () {
              imgGallery();
            },
            text: 'Galeria',
            fontSize: 18,
          ),
          TextButton(
            onPressed: () {
              Navigator.of(context).pop();
            },
            child: const Text('Cancelar'),
          )
        ],
      );
    }
  }
}

我希望我能理解并帮助你。

相关问题