简体   繁体   中英

Image cropper not working in GetxController

The following is the code i was trying to implement in. The future method pickImage i guess it is the one having the problem. I am extending the class with GetxController. The method is expected to pick and crop the selected image using the image cropper, and then set the cropped image to the imageFile variable if the cropping was successful.

import 'dart:io';

import 'package:pamoja/app/data/const.dart';
import 'package:pamoja/app/data/firebase/firebase_functions.dart';
import 'package:pamoja/app/data/global_widgets/indicator.dart';
import 'package:pamoja/app/models/advert_model.dart';
import 'package:pamoja/app/modules/my_adverts/controllers/my_adverts_controller.dart';
import 'package:pamoja/app/routes/app_pages.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
import 'package:image_cropper/image_cropper.dart';

class UploadBlogController extends GetxController {
  TextEditingController title = TextEditingController();
  TextEditingController description = TextEditingController();
  TextEditingController location = TextEditingController();
  TextEditingController category = TextEditingController();
  TextEditingController price = TextEditingController();
  TextEditingController phone = TextEditingController();
  final FirebaseFunctions _functions = FirebaseFunctions();
  File? imageFile;

  Future<void> pickImage() async {
    try {
      ImagePicker _picker = ImagePicker();

      await _picker.pickImage(source: ImageSource.gallery).then((value) async {
        if (value != null) {
          File? croppedFile = await ImageCropper().cropImage(
            sourcePath: value.path,
            aspectRatio: CropAspectRatio(ratioX: 1, ratioY: 1),
            compressQuality: 100,
            maxWidth: 700,
            maxHeight: 700,
            // saveCircleCroppedImage: true,
          );

          if (croppedFile != null) {
            imageFile = croppedFile;
            update();
          }
        }
      });
    } catch (e) {
      showAlert("$e");
    }
  }

  void createBlog() async {
    if (title.text.isNotEmpty && description.text.isNotEmpty) {
      if (imageFile != null && imageFile != "") {
        Indicator.showLoading();

        await _functions
            .uploadBlog(
          title.text,
          description.text,
          imageFile!,
          price.text,
          category.text,
          location.text,
          phone.text,
        )
            .then((value) {
          Indicator.closeLoading();
          showAlert("Your advert created sucessfully");
          // Get.back();
          Get.toNamed(Routes.HOME);
        });
      } else {
        showAlert("Image is required");
      }
    } else {
      showAlert("All fields are required");
    }
  }

  void editBlog(BlogsModel model) async {
    Indicator.showLoading();

    if (title.text.isNotEmpty && description.text.isNotEmpty) {
      if (imageFile == null) {
        Map<String, dynamic> map = {
          'title': title.text,
          'description': description.text,
        };

        await _functions.editBlog(model.id, map).then((value) {
          Get.toNamed(Routes.HOME);
          showAlert("Your ads Updated Sucessfully");
        });
      } else {
        String imageUrl = await _functions.uploadImage(imageFile!);

        Map<String, dynamic> map = {
          'title': title.text,
          'description': description.text,
          'img': imageUrl,
        };

        await _functions.editBlog(model.id, map).then((value) {
          Get.toNamed(Routes.HOME);
          showAlert("Your Advert Updated Sucessfully");
        });
      }
    } else {
      showAlert("All fields are required");
    }

    Indicator.closeLoading();
    updateData();
  }

  void updateData() {
    Get.back();
    Get.toNamed(Routes.HOME);
    if (Get.isRegistered<MyBlogsController>()) {
      final controller = Get.find<MyBlogsController>();

      controller.myBlogs = [];
      Indicator.showLoading();
      controller.getMyBlogData();
    }
  }
}

this i created reusable single-tone code for my entire app to pick media image or video . you can try or modify according your requirement.

// Dart imports:
import 'dart:io';

// Package imports:
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';

// Project imports:
import 'package:app/utils/export_utils.dart';

class MediaPicker {
  MediaPicker._();

  static const supportedImageFormates = [".jpeg", ".png"];
  static const supportedVedioFormates = [".mp4"];
  static final picker = ImagePicker();

  // Single image / video selection
  static Future<File?> pickMedia({
    required ImageSource source,
    bool isVideo = false,
    bool isEditing = false,
  }) async {
    try {
      final pickMedia = !isVideo
          ? await picker.pickImage(source: source)
          : await picker.pickVideo(source: source);

      if (pickMedia != null) {
        return isEditing
            ? await editImage(file: File(pickMedia.path))
            : File(pickMedia.path);
      } else {
        return null;
      }
    } catch (ex) {
      "Pick Media error: $ex".printLog();
      return null;
    }
  }

  static Future<File> editImage({required File file}) async {
    final CroppedFile? croppedFile = await ImageCropper().cropImage(
      sourcePath: file.path,
      uiSettings: [
        AndroidUiSettings(
          toolbarTitle: 'Cropper',
          toolbarColor: ColorConst.themePrimaryColor,
          toolbarWidgetColor: ColorConst.white,
          initAspectRatio: CropAspectRatioPreset.original,
          lockAspectRatio: false,
        ),
        IOSUiSettings(
          title: 'Cropper',
        ),
      ],
    );

    if (croppedFile != null) {
      return File(croppedFile.path);
    } else {
      return file;
    }
  }
}

Usage add call method on button tap with Future & async method

Future<void> btnPickImageTap() async {
    final File? selectImageFile = await MediaPicker.pickMedia(
      source: ImageSource.gallery, 
      isEditing: true, // Default false
    );
}

source: ImageSource.camera - to pick image from camera. 
isEditing: false - avoid image cropping functionality.
isVideo: to pick video from gallery / camera.

Make sure following permission added for both platforms

Andriod - AndroidManifest.xml

    <uses-permission android:name="android.permission.CAMERA"/> //Camera
   <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> // Read Storage 

iOS Runner/info.plist

<key>NSCameraUsageDescription</key>
    <string>App require camera permission to update profile pic</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>App require gallery permission to update profile pic</string>

As package mentioned in image_cropper add bellow code in AndroidManifest.xml under <applcaiton> TAG

<activity
  android:name="com.yalantis.ucrop.UCropActivity"
  android:screenOrientation="portrait"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>

I modified it following your instruction it worked. The following is a sample modification

Future<void> pickImage() async {
try {
  ImagePicker _picker = ImagePicker();

  await _picker.pickImage(source: ImageSource.gallery).then((value) async {
    if (value != null) {
      imageFile = File(value.path);
      showAlert(imageFile.toString());
      editImage(imageFile: imageFile);

      // cropImage(imageFile);
    } else {
      showAlert("No image selected");
    }
  });
} catch (e) {
  showAlert("$e");
}}
Future<void> editImage({required File? imageFile}) async {
final File? croppedFile = await ImageCropper().cropImage(
  sourcePath: imageFile!.path,
  androidUiSettings: AndroidUiSettings(
    toolbarTitle: 'Advert Image',
    toolbarColor: Colors.green.shade400,
    toolbarWidgetColor: Colors.white,
    initAspectRatio: CropAspectRatioPreset.original,
    lockAspectRatio: false,
  ),
  iosUiSettings: IOSUiSettings(
    title: 'Cropper',
  ),
);

if (croppedFile != null) {
  imageFile = File(croppedFile.path);
  update();
} else {
  // update();
}}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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