繁体   English   中英

如何将库 image_picker 和 image_cropper 实现到扩展无状态小部件的类?

[英]How to implement library image_picker and image_cropper to a class that extends Stateless widget?

我正在尝试将库image_pickerimage_cropper 实现到遗留代码,但它扩展了无状态小部件。

import 'package:elxr_mobile/components/export.dart';
import 'package:elxr_mobile/models/export.dart';
import 'package:elxr_mobile/pages/04_profile/export.dart';
import 'package:elxr_mobile/styles/export.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';

class ProfileHeader extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StoreConnector<AppState, ElxrViewModel>(
        converter: ElxrViewModel.fromStore,
        builder: (BuildContext context, vm) {
          return Container(
            child: Column(
              children: <Widget>[
                InkWell(
                  child: CircleAvatar(
                    radius: 30.0,
                    backgroundImage:
                        AssetImage('assets/images/profile.icon.round.png'),
                    backgroundColor: Colors.white,
                  ),
                  onTap: () {
                    Navigator.of(context).push(
                      MaterialPageRoute(
                          builder: (BuildContext context) => AboutMePage()),
                    );
                  },
                ),
                Container(height: 5.0),
                Text(
                  vm.user?.displayName ?? "",
                  textAlign: TextAlign.center,
                  style: ProfileTextTheme.header(),
                ),
                Container(height: 5.0),
                Container(
                  width: 150.0,
                  padding: EdgeInsets.fromLTRB(20.0, 5.0, 20.0, 5.0),
                  decoration: BoxDecoration(
                      border: Border.all(
                    color: Colors.grey,
                  )),
                  child: Text(
                    'KIT: ${(vm.customer?.userKitNo ?? "").padLeft(8, '0')}',
                    textAlign: TextAlign.center,
                    style: ProfileTextTheme.subtext(context),
                  ),
                ),
                Container(height: 5.0),
              ],
            ),
          );
        });
  }
}

当我单击用户头像时,它应该显示从图库中选择图片或从相机拍摄图片的选项,然后用户可以裁剪该图片。

当前用户界面如下图所示。当前用户界面 请帮忙!

这就是您可以在没有选择器的情况下执行此操作的方法,您可以在其中选择要从中导入图像的源。 某处必须有一个插件,或者您可以自己创建对话框。

                InkWell(
              child: CircleAvatar(
                radius: 30.0,
                backgroundImage:
                    AssetImage('assets/images/profile.icon.round.png'),
                backgroundColor: Colors.white,
              ),
              onTap: () async {
              File file = await ImagePicker.pickImage(source: ImageSource.gallery);

              if (file == null) {return;}

              File croppedFile = await ImageCropper.cropImage(
                  sourcePath: file.path,
                  ratioX: 1.0,
                  ratioY: 1.0,
                  maxWidth: 512,
                  maxHeight: 512,
                  circleShape: true);


              if (croppedFile == null) {return;}

              Directory directory = await getApplicationDocumentsDirectory();


              String finalPath = directory.path + '/profile_picture' + pathPlugin.extension(croppedFile.path);
              File finalImage = await croppedFile.copy(finalPath);

              imageCache.clear();
              },
            ),

我通过更改类以扩展 StatefulWidget 并制作处理程序和对话框来解决该问题。

profile_header.dart:

import 'dart:io';

import 'package:elxr_mobile/components/export.dart';
import 'package:elxr_mobile/models/export.dart';
import 'package:elxr_mobile/helpers/image_picker_handler.dart';
import 'package:elxr_mobile/styles/export.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';

class ProfileHeader extends StatefulWidget {
  ProfileHeader({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _ProfileHeaderState createState() => new _ProfileHeaderState();
}

class _ProfileHeaderState extends State<ProfileHeader>
    with TickerProviderStateMixin, ImagePickerListener {
  File _image;
  AnimationController _controller;
  ImagePickerHandler imagePicker;

  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 500),
    );
    imagePicker = new ImagePickerHandler(this, _controller);
    imagePicker.init();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return StoreConnector<AppState, ElxrViewModel>(
        converter: ElxrViewModel.fromStore,
        builder: (BuildContext context, vm) {
          return Container(
            child: Column(
              children: <Widget>[
                InkWell(
                  child: _image == null
                      ? CircleAvatar(
                          radius: 30.0,
                          backgroundColor: Colors.white,
                          backgroundImage: AssetImage(
                              "assets/images/profile.icon.round.png"))
                      : CircleAvatar(
                          radius: 30.0,
                          backgroundColor: Colors.white,
                          backgroundImage: ExactAssetImage(_image.path)),
                  onTap: () => imagePicker.showDialog(context),
                ),
                Container(height: 5.0),
                Text(
                  vm.user?.displayName ?? "",
                  textAlign: TextAlign.center,
                  style: ProfileTextTheme.header(),
                ),
                Container(height: 5.0),
                Container(
                  width: 150.0,
                  padding: EdgeInsets.fromLTRB(20.0, 5.0, 20.0, 5.0),
                  decoration: BoxDecoration(
                      border: Border.all(
                    color: Colors.grey,
                  )),
                  child: Text(
                    'KIT: ${(vm.customer?.userKitNo ?? "").padLeft(8, '0')}',
                    textAlign: TextAlign.center,
                    style: ProfileTextTheme.subtext(context),
                  ),
                ),
                Container(height: 5.0),
              ],
            ),
          );
        });
  }

  @override
  userImage(File _image) {
    setState(() {
      this._image = _image;
    });
  }
}

image_picker_handler.dart:

import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:elxr_mobile/helpers/image_picker_dialog.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';

class ImagePickerHandler {
  ImagePickerDialog imagePicker;
  AnimationController _controller;
  ImagePickerListener _listener;

  ImagePickerHandler(this._listener, this._controller);

  openCamera() async {
    imagePicker.dismissDialog();
    var image = await ImagePicker.pickImage(source: ImageSource.camera);
    cropImage(image);
  }

  openGallery() async {
    imagePicker.dismissDialog();
    var image = await ImagePicker.pickImage(source: ImageSource.gallery);
    cropImage(image);
  }

  void init() {
    imagePicker = new ImagePickerDialog(this, _controller);
    imagePicker.initState();
  }

  Future cropImage(File image) async {
    File croppedFile = await ImageCropper.cropImage(
      sourcePath: image.path,
      ratioX: 1.0,
      ratioY: 1.0,
      maxWidth: 512,
      maxHeight: 512,
    );
    _listener.userImage(croppedFile);
  }

  showDialog(BuildContext context) {
    imagePicker.getImage(context);
  }

  Future<void> retrieveLostData() async {
    final LostDataResponse response = await ImagePicker.retrieveLostData();
    if (response == null) {
      return;
    }
    if (response.file != null) {
      if (response.type == RetrieveType.video) {
        return;
      } else {
        _listener.userImage(response.file);
      }
    } else {
      return;
    }
  }
}

abstract class ImagePickerListener {
  userImage(File _image);
}

image_picker_dialog.dart:

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:elxr_mobile/helpers/image_picker_handler.dart';

// ignore: must_be_immutable
class ImagePickerDialog extends StatelessWidget {
  ImagePickerHandler _listener;
  AnimationController _controller;
  BuildContext context;
  ImagePickerDialog(this._listener, this._controller);
  Animation<double> _drawerContentsOpacity;
  Animation<Offset> _drawerDetailsPosition;

  void initState() {
    _drawerContentsOpacity = new CurvedAnimation(
      parent: new ReverseAnimation(_controller),
      curve: Curves.fastOutSlowIn,
    );
    _drawerDetailsPosition = new Tween<Offset>(
      begin: const Offset(0.0, 1.0),
      end: Offset.zero,
    ).animate(new CurvedAnimation(
      parent: _controller,
      curve: Curves.fastOutSlowIn,
    ));
  }

  getImage(BuildContext context) {
    if (_controller == null ||
        _drawerDetailsPosition == null ||
        _drawerContentsOpacity == null) {
      return;
    }
    _controller.forward();
    showDialog(
      context: context,
      builder: (BuildContext context) => new SlideTransition(
        position: _drawerDetailsPosition,
        child: new FadeTransition(
          opacity: new ReverseAnimation(_drawerContentsOpacity),
          child: this,
        ),
      ),
    );
  }

  void dispose() {
    _controller.dispose();
  }

  startTime() async {
    var _duration = new Duration(milliseconds: 200);
    return new Timer(_duration, navigationPage);
  }

  void navigationPage() {
    Navigator.pop(context);
  }

  dismissDialog() {
    _controller.reverse();
    startTime();
  }

  @override
  Widget build(BuildContext context) {
    this.context = context;
    return new Material(
        type: MaterialType.transparency,
        child: new Opacity(
          opacity: 1.0,
          child: new Container(
            padding: EdgeInsets.fromLTRB(30.0, 0.0, 30.0, 20.0),
            child: Column(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                new GestureDetector(
                  onTap: () => _listener.openCamera(),
                  child: roundedButton(
                      "Camera",
                      EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0),
                      const Color(0xFF167F67),
                      const Color(0xFFFFFFFF)),
                ),
                new GestureDetector(
                  onTap: () => _listener.openGallery(),
                  child: roundedButton(
                      "Gallery",
                      EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0),
                      const Color(0xFF167F67),
                      const Color(0xFFFFFFFF)),
                ),
                const SizedBox(height: 15.0),
                new GestureDetector(
                  onTap: () => dismissDialog(),
                  child: new Padding(
                    padding: EdgeInsets.fromLTRB(30.0, 0.0, 30.0, 0.0),
                    child: roundedButton(
                        "Cancel",
                        EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0),
                        Colors.redAccent,
                        const Color(0xFFFFFFFF)),
                  ),
                ),
              ],
            ),
          ),
        ));
  }

  Widget roundedButton(
      String buttonLabel, EdgeInsets margin, Color bgColor, Color textColor) {
    return new Container(
      margin: margin,
      padding: EdgeInsets.all(10.0),
      alignment: FractionalOffset.center,
      decoration: new BoxDecoration(
        color: bgColor,
        borderRadius: new BorderRadius.all(const Radius.circular(10.0)),
      ),
      child: Text(
        buttonLabel,
        style: new TextStyle(
            color: textColor,
            fontSize: 20.0,
            fontWeight: FontWeight.bold,
            fontFamily: "Cairo"),
      ),
    );
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM