简体   繁体   English

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

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

I'm trying to implement library image_picker and image_cropper to the legacy code but it 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),
              ],
            ),
          );
        });
  }
}

When I clicked the user avatar it should show options to pick the picture from gallery or take a picture from the camera and then the user can crop that picture.当我单击用户头像时,它应该显示从图库中选择图片或从相机拍摄图片的选项,然后用户可以裁剪该图片。

Current UI is showing in the picture below.当前用户界面如下图所示。当前用户界面 Please help!请帮忙!

This is how you can do it without the picker where you can choose the source you want the image to be imported from.这就是您可以在没有选择器的情况下执行此操作的方法,您可以在其中选择要从中导入图像的源。 There must be a plugin somwhere, or you can create the dialog yourself.某处必须有一个插件,或者您可以自己创建对话框。

                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();
              },
            ),

I fixed the problem by changing the class to extend StatefulWidget and making a handler and a dialog.我通过更改类以扩展 StatefulWidget 并制作处理程序和对话框来解决该问题。

profile_header.dart: 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: 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: 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