flutter仿微信朋友圈发布页面图片上传及九宫格展示

该文章展示了如何在Flutter应用中使用nine_grid_view和wechat_assets_picker库来实现图片选择功能。ImageBean类用于存储图片信息,PictureUtils包含辅助方法如显示SnackBar和获取Widget。此外,还介绍了屏幕适配方法以及如何监听拖动事件以实现在九宫格中移动和删除图片的功能。
摘要由CSDN通过智能技术生成
使用到的包

nine_grid_view
wechat_assets_picker
wechat_assets_picker使用前需要给相应权限,参考这篇文章

代码

ImageBean类

import 'package:nine_grid_view/nine_grid_view.dart';

class ImageBean extends DragBean {
  ImageBean({
    this.originPath,
    this.middlePath,
    this.thumbPath,
    this.originalWidth,
    this.originalHeight,
  });

  /// origin picture file path.
  String? originPath;

  /// middle picture file path.
  String? middlePath;

  /// thumb picture file path.
  /// It is recommended to use a thumbnail picture,because the original picture is too large,
  /// it may cause repeated loading and cause flashing.
  String? thumbPath;

  /// original image width.
  int? originalWidth;

  /// original image height.
  int? originalHeight;
}

PictureUtils

import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:meowfront/models/picture.dart';

class PictureUtils {

  static Future<T?> pushPage<T extends Object>(
      BuildContext context, Widget page) {
    return Navigator.push(
      context,
      CupertinoPageRoute(builder: (ctx) => page),
    );
  }

  static void showSnackBar(BuildContext context, String msg) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(msg),
        duration: Duration(seconds: 2),
      ),
    );
  }

  static Widget getWidget(String url) {
    // 加载网络图片
    if (url.startsWith('http')) {
      //return CachedNetworkImage(imageUrl: url, fit: BoxFit.cover);
      return Image.network(url, fit: BoxFit.cover);
    }
    // 加载资源文件
    if (url.startsWith('assets/images')) {
      return Image.asset(url, fit: BoxFit.cover);
    }
    if (url.startsWith('/storage/emulated')) {
      return Image.file(File(url), fit: BoxFit.cover);
    }
    // 加载失败图片
    return Image.asset('assets/images/image_load_error.png', fit: BoxFit.cover);
  }

  static List<ImageBean> getImageBean(List<File> files) {
    List<ImageBean> list = [];
    for (int i = 0; i < files.length; i++) {
      String url = files[i].path;
      list.add(ImageBean(
        originPath: url,
        middlePath: url,
        thumbPath: url,
        originalWidth: i == 0 ? 264 : null,
        originalHeight: i == 0 ? 258 : null,
      ));
    }
    return list;
  }

}

屏幕适配(需要先下载flutter_screenutil包)

import 'package:flutter_screenutil/flutter_screenutil.dart';

class ScreenAdapter {
  static heigth(num value) {
    return ScreenUtil().setHeight(value);
  }

  static width(num value) {
    return ScreenUtil().setWidth(value);
  }

  static size(num value) {
    return ScreenUtil().setSp(value);
  }

  static getScreenWidth() {
    return ScreenUtil().screenWidth; //获取设备的物理宽度
  }

  static getScreenHigth() {
    return ScreenUtil().screenHeight; //获取设备的物理高度
  }
}

页面

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:meowfront/models/picture.dart';
import 'package:meowfront/util/PictureUtil.dart';
import 'package:meowfront/util/ScreenAdapter.dart';
import 'package:nine_grid_view/nine_grid_view.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';

class PublishPage extends StatefulWidget {
  
  _PublishPageState createState() => _PublishPageState();
}

class _PublishPageState extends State<PublishPage> {
  List<ImageBean> _imageList = [];

  List<File> _imageFiles = [];
  int moveAction = MotionEvent.actionUp;
  bool _canDelete = false;

  
  void initState() {
    super.initState();
  }

  selectPictures() async {
    final List<AssetEntity>? entitys = await AssetPicker.pickAssets(context,
        maxAssets: 9 - _imageFiles.length);
    if (entitys == null) return;
    //遍历
    for (var entity in entitys) {
      File? imgFile = await entity.file;

      if (imgFile != null) {
        setState(() {
          _imageFiles.add(imgFile);
          _imageList = PictureUtils.getImageBean(_imageFiles);
          print('22222' + imgFile.path);
        });
      }
    }
  }

  _loadAssets(BuildContext context) {
    // pick Images.
    PictureUtils.showSnackBar(context, "pick Images.");
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.white,
        title: const Text(''),
        elevation: 0,
        centerTitle: true,
        actions: <Widget>[
          UnconstrainedBox(
            child: Container(
              padding: EdgeInsets.only(right: ScreenAdapter.width(20)),
              height: ScreenAdapter.heigth(55),
              child: ElevatedButton(
                  child: Text('发布'),
                  style: ButtonStyle(
                    backgroundColor: MaterialStateProperty.all(Colors.blue),
                    foregroundColor: MaterialStateProperty.all(Colors.white),
                    // elevation: MaterialStateProperty.all(10),
                    shape: MaterialStateProperty.all(RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(10))),
                  ),
                  onPressed: () {
                    print("圆形按钮2");
                  }),
            ),
          ),
        ],
      ),
      body: Container(
        color: Colors.white,
        child: ListView(
          children: <Widget>[
            Container(
              padding: EdgeInsets.fromLTRB(25, 20, 30, 25),
              height: ScreenAdapter.heigth(300),
              child: TextField(
                maxLength: 100,
                maxLines: 8,
                decoration: InputDecoration(
                    border: InputBorder.none,
                    contentPadding: EdgeInsets.zero,
                    hintText: "分享新鲜事",
                    hintStyle: TextStyle(color: Colors.black12)
                    ),
              ),
            ),
            DragSortView(
              _imageList,
              space: 5,
              margin: EdgeInsets.all(20),
              padding: EdgeInsets.all(0),
              itemBuilder: (BuildContext context, int index) {
                ImageBean bean = _imageList[index];
                // It is recommended to use a thumbnail picture
                return PictureUtils.getWidget(bean.thumbPath!);
              },
              initBuilder: (BuildContext context) {
                return InkWell(
                  onTap: () {
                    selectPictures();
                  },
                  child: Container(
                    color: Color(0xFFF0F0F0),
                    child: Center(
                      child: Icon(
                        Icons.add,
                      ),
                    ),
                  ),
                );
              },
              onDragListener: (MotionEvent event, double itemWidth) {
                switch (event.action) {
                  case MotionEvent.actionDown:
                    moveAction = event.action!;
                    setState(() {});
                    break;
                  case MotionEvent.actionMove:
                    double x = event.globalX! + itemWidth;
                    double y = event.globalY! + itemWidth;
                    double maxX = MediaQuery.of(context).size.width - 1 * 100;
                    double maxY = MediaQuery.of(context).size.height - 1 * 100;
                    print('Sky24n maxX: $maxX, maxY: $maxY, x: $x, y: $y');
                    if (_canDelete && (x < maxX || y < maxY)) {
                      setState(() {
                        _canDelete = false;
                      });
                    } else if (!_canDelete && x > maxX && y > maxY) {
                      setState(() {
                        _canDelete = true;
                      });
                    }
                    break;
                  case MotionEvent.actionUp:
                    moveAction = event.action!;
                    if (_canDelete) {
                      setState(() {
                        _canDelete = false;
                      });
                      return true;
                    } else {
                      setState(() {});
                    }
                    break;
                }
                return false;
              },
            ),
          ],
        ),
      ),
      floatingActionButton: moveAction == MotionEvent.actionUp
          ? null
          : FloatingActionButton(
              onPressed: () {},
              child: Icon(_canDelete ? Icons.delete : Icons.delete_outline),
            ),
    );
  }
}![请添加图片描述](https://img-blog.csdnimg.cn/56d1b5d385ab4cda8532462f70a48e4c.jpeg)


效果图

请添加图片描述
请添加图片描述

长按图片可以移动或删除
请添加图片描述

Flutter 中,模拟微信群聊 @ 好友的功能通常涉及以下几个步骤: 1. **创建用户列表**:首先,你需要存储用户的名称和头像数据,可以用 `List<Widget>` 或者 `List<UserModel>` 类型的数据结构来表示。 ```dart class UserModel { String name; String avatarUrl; UserModel({required this.name, required this.avatarUrl}); } ``` 2. **构建好友列表**:使用 `ListView.builder` 和 `AvatarImage` 创建一个滚动的用户列表,当点击某个用户时触发 `onTap` 事件。 ```dart ListView.builder( itemCount: users.length, itemBuilder: (context, index) { return ListTile( leading: CircleAvatar( child: Image.network(users[index].avatarUrl), ), title: Text(users[index].name), onTap: () { // 当前选中的好友,这里只是一个示例,需要连接到具体的处理逻辑 _selectedUser = users[index]; }, ); }, ); ``` 3. **显示@消息**:当选择一个用户后,在聊天区域显示 "@[用户名]" 的提示,并且可能是高亮显示。 ```dart Text('@${_selectedUser.name} 发送的消息'), ``` 4. **模拟发送消息**:你可以设置一个按钮或者文本框,当用户输入文字并点击发送时,将文字加上@的标识发送出去。 ```dart RaisedButton( onPressed: () { setState(() { sendMessage('@' + _selectedUser.name + ' 这是一条消息'); _selectedUser = null; // 清空选择状态 }); }, ) ``` 这只是一个基本的框架,实际应用中可能还需要考虑更多的细节,例如网络请求、实时更新、长按复制等等。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值