Flutter 用户拍照+用户选择图片,并且裁剪后传给后台

前言
虽然现在Flutter关于裁剪图片的插件挺多,在经过一下午的踩坑后,发现了其中很多问题,在Pub上排名靠前的两个插件均有问题

在这里插入图片描述

image_crop问题是在于如果不嵌套在MaterilaApp当中,选择图片后,无法正常裁剪,而且会将原图片损坏,导致原图片也无法使用,真的恶心
simple_image_crop是因为由于近期刚更新了版本,我在下载了示例代码后,运行时直接报错,希望作者在之后能够修改一个这个Bug问题。

正文

接下来就进入正题了,给大家介绍亲测好用的插件image_cropper,首先给大家展示一下我使用的效果
在这里插入图片描述

Pub地址https://pub.dev/packages/image_cropper
注意:

该插件是配合着image_picker插件来使用的,image_picker是用来呼唤起用户的相机以及选择图片用的,具体可以去参考官方文档https://pub.dev/packages/image_picker

这个是我自己封装好的插件,只是把调用摄像头和裁剪的方法封装进去了,方便别的页面调用

import 'package:project/plugins/Plugins.dart';

在这里插入图片描述
这个是我封装的屏幕适配类,具体可参考我的另外一篇文章:https://blog.csdn.net/qq_38774121/article/details/102883746

import 'package:project/plugins/ScreenAdapter.dart';

这个是我封装的统一请求接口类,用来发送上传图片请求的,具体可参考我的另外一篇文章:https://blog.csdn.net/qq_38774121/article/details/102883746

import 'package:project/config/api.dart';
完整代码(具体的意思我全部写在代码当中了,如果有什么问题,请留言给我,24小时内答复您)
import 'dart:convert';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:project/plugins/Plugins.dart';				
import 'package:project/plugins/ScreenAdapter.dart';
import 'package:project/config/api.dart';


class ModifyUserInfo extends StatefulWidget {
 
  @override
  _ModifyUserInfoState createState() => _ModifyUserInfoState();
}

class _ModifyUserInfoState extends State<ModifyUserInfo> {
  
  File _file;
  var _croppFile;

  var api = Api();

  var imageUrl = 'https://huyaimg.msstatic.com/avatar/1084/37/7c96090110880e88916b11e4a18cf9_180_135.jpg?437764';						// 初始化默认图片



  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Container(
            child: Text('测试页面'),
          ),
        ),
        body: ConstrainedBox(
          constraints: BoxConstraints.expand(),
          child: Container(
            color: Color.fromRGBO(233, 233, 233, 0.7),
            child: ListView(
              children: <Widget>[
                InkWell(
                  child: Container(
                    padding: EdgeInsets.symmetric(
                        horizontal: ScreenAdapter.setWidth(20)),
                    color: Colors.white,
                    height: ScreenAdapter.setHeight(150),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Text(
                          '头像',
                          style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: ScreenAdapter.size(28)),
                        ),
                        Row(
                          children: <Widget>[
                            CircleAvatar(
                              backgroundImage: NetworkImage(imageUrl),
                              radius: 40.0,
                            ),
                            Icon(Icons.chevron_right)
                          ],
                        ),
                      ],
                    ),
                  ),
                  onTap: showSelectPicker,
                ),
                UserInfoList('昵称', '磐石Boy'),
                // Text('')
                _croppFile != null ? Image.file(_croppFile) : Text('')
              ],
            ),
          ),
        ));
  }

  // 选择图片
  showSelectPicker() {
    showModalBottomSheet(
      context: context,
      builder: (context){
        return Container(
          height: ScreenAdapter.setHeight(200),
          child: Column(
            children: <Widget>[
              InkWell(
                onTap: () async {
                  var file = await Plugins.takePhoto();
                  if(file!=null){
                    // 获取图片路径
                    setState(() {
                      _file = file;
                    });
                    // 关闭弹窗
                    Navigator.pop(context);
                    // 获取裁剪后地址
                    
                    var croppFile = await Plugins.cropImage(context, file.path);
                    // 请求接口上传图片
                    if(croppFile!=null){
                      api.postData('uploadFile', formData: await FormData1(croppFile.path)).then((val){
                        var imgurl = json.decode(val.toString());
                        setState(() {
                          imageUrl = 'https://flutter.ikuer.cn/'+imgurl['file_path'];
                        });
                      });
                      setState(() {
                        _croppFile = croppFile;
                      });
                    }
                  }
                  
                },
                child: Container(
                  alignment: Alignment.center,
                  height: ScreenAdapter.setHeight(100),
                  child: Text('拍照'),
                  decoration: BoxDecoration(
                    border: Border(
                      bottom: BorderSide(
                        width: 0.5,
                        color: Colors.black26
                      )
                    )
                  ),
                ),
              ),
              InkWell(
                onTap: ()  async {
                  var file = await Plugins.openGallery();
                  if(file!=null){
                    setState(() {
                      _file = file;
                    });
                    Navigator.pop(context);
                    var croppFile = await Plugins.cropImage(context, file.path);
                    if(croppFile!=null){
                      api.postData('uploadFile', formData: await FormData1(croppFile.path)).then((val){
                        var imgurl = json.decode(val.toString());
                        setState(() {
                          imageUrl = 'https://flutter.ikuer.cn/'+imgurl['file_path'];
                        });
                      });
                      setState(() {
                        _croppFile = croppFile;
                      });
                    }
                  }
                },
                child: Container(
                  alignment: Alignment.center,
                  height: ScreenAdapter.setHeight(100),
                  child: Text('相册选择'),
                ),
              )
            ],
          )
        );
      }
    );
  }

 // dio上传文件FormData格式
  Future<FormData> FormData1(fileUrl) async {
    return FormData.fromMap({
      "file": await MultipartFile.fromFile(fileUrl)
    });
  }

  // 用户信息列表
  Widget UserInfoList(String title, String subtitle) {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: ScreenAdapter.setWidth(20)),
      color: Colors.white,
      height: ScreenAdapter.setHeight(150),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Text(
            '${title}',
            style: TextStyle(
                fontWeight: FontWeight.bold, fontSize: ScreenAdapter.size(28)),
          ),
          Row(
            children: <Widget>[Text('${subtitle}'), Icon(Icons.chevron_right)],
          )
        ],
      ),
    );
  }
}

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
Flutter 是一种跨平台的移动应用开发框架,它提供了丰富的组件和功能,可以帮助开发者快速构建漂亮、流畅的用户界面。对于可滑动自动滚动折线图,在 Flutter 中可以使用 `ListView` 和 `AnimatedContainer` 组件来实现。 首先,我们可以使用 `ListView` 组件来创建一个可以滑动的容器。使用 `ListView.builder` 构建一个动态列表,将折线图中的数据作为列表项进行展示。在 `ListView` 内部添加一个 `ScrollController`,用来控制列表的滚动。 当需要自动滚动时,我们可以通过动画来实现。使用 `AnimatedContainer` 组件来包裹折线图,通过修改它的宽度来实现滚动效果。可以在需要的时候,通过调用 `setState` 方法,来更新 `AnimatedContainer` 的属性值,从而触发动画效果。 在滚动时,可以监听滚动的位置,根据当前滚动的位置来判断是否需要自动滚动。通过 `ScrollController` 的 `addListener` 方法监听滚动事件,计算滚动的位置,并进行相应的判断,如果需要自动滚动,就通过修改 `AnimatedContainer` 的属性值来触发动画。 同时,可以为 `AnimatedContainer` 设置合适的动画时长和曲线,来使滚动效果更加顺滑。 总结来说,要实现可滑动自动滚动折线图,可以使用 `ListView` 和 `AnimatedContainer` 组件。通过监听滚动事件,根据滚动的位置进行判断,并通过修改 `AnimatedContainer` 的属性值来触发动画效果,从而实现自动滚动的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值