flutter聊天界面-加号【➕】更多展开相机、相册等操作Panel

这篇具有很好参考价值的文章主要介绍了flutter聊天界面-加号【➕】更多展开相机、相册等操作Panel。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

flutter聊天界面-加号【➕】更多展开相机、相册等操作Panel
在之前实现了flutter聊天界面的自定义表情的展示,这里记录一下更多操作展开的相机、相册等操作功能实现。

一、查看效果

更多操作展开的相机、相册等操作功能实现。

flutter聊天界面-加号【➕】更多展开相机、相册等操作Panel,flutter开发实战,flutter,flutter,flutter聊天界面,操作面板

二、代码实现

展开的操作按钮可能比较多,一页显示8个、多个可以左右滑动,这里就用到的flutter_swiper插件
这里使用的swpier插件是

  # 轮播图
  flutter_swiper_null_safety: ^1.0.2

Swiper左右滑动的元素为GridView。
GridView网格布局是一种常见的布局类型,GridView 组件正是实现了网格布局的组件,
SliverGridDelegate是一个抽象类,定义了GridView Layout相关接口,子类需要通过实现它们来实现具体的布局算法。Flutter中提供了两个SliverGridDelegate的子类SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent,
每个GridView包括多个相机、相册等操作按钮

按钮如下

// 每个option的大小
class ChatMoreOptionButton extends StatelessWidget {
  const ChatMoreOptionButton({
    Key? key,
    required this.commMoreOption,
    required this.onMoreOptionPressed,
  }) : super(key: key);

  final CommMoreOption commMoreOption;
  final Function(CommMoreOption commMoreOption) onMoreOptionPressed;

  
  Widget build(BuildContext context) {
    EdgeInsets viewPadding = MediaQuery.of(context).viewPadding;
    Size screenSize = MediaQuery.of(context).size;

    double aWidth = (screenSize.width - (kOptionSperate * 5)) / 4;
    double aHeight = (kMorePanelHeight -
            (kOptionSperate * 3) -
            viewPadding.bottom -
            kSwiperPaginationHeight) /
        2;

    double aMin = min(aWidth, aHeight);

    double marginSpace = kOptionSperate / 2;
    return ButtonWidget(
      margin: EdgeInsets.symmetric(
        vertical: marginSpace,
        horizontal: marginSpace,
      ),
      width: aMin,
      height: aMin,
      borderRadius: 6.0,
      bgColor: ColorUtil.hexColor(0xffffff),
      bgHighlightedColor: ColorUtil.hexColor(0xf0f0f0),
      onPressed: () {
        onMoreOptionPressed(commMoreOption);
      },
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          buildButtonIcon(context),
          SizedBox(
            height: 5.0,
          ),
          Text(
            "${commMoreOption.name}",
            textAlign: TextAlign.left,
            maxLines: 1,
            overflow: TextOverflow.ellipsis,
            style: TextStyle(
              fontSize: 12,
              fontWeight: FontWeight.w500,
              fontStyle: FontStyle.normal,
              color: ColorUtil.hexColor(0x333333),
              decoration: TextDecoration.none,
            ),
          ),
        ],
      ),
    );
  }

  Widget buildButtonIcon(BuildContext context) {
    if (CommMoreOptionIconType.commMoreOptionIconFile ==
        commMoreOption.iconType) {
      // 本地图片
      String imageUrl = "${commMoreOption.icon ?? ""}";
      String start = "file://";
      if (imageUrl.startsWith(start)) {
        String imageAssetFile = imageUrl.substring(start.length);

        return ImageHelper.wrapAssetAtImages(
          "icons/${imageAssetFile}",
          fit: BoxFit.cover,
          width: 26.0,
          height: 26.0,
        );
      }
    } else if (CommMoreOptionIconType.commMoreOptionIconUrl ==
        commMoreOption.iconType) {
      // 网络图片
      String imageUrl = "${commMoreOption.icon ?? ""}";
      return ImageHelper.imageNetwork(
        imageUrl: imageUrl,
        fit: BoxFit.cover,
        width: 40.0,
        height: 40.0,
      );
    }

    return Container();
  }
}

GridView实现排列展示

// 一个swiper的容器
class ChatMoreOptionSwiperContainer extends StatefulWidget {
  const ChatMoreOptionSwiperContainer({
    Key? key,
    required this.moreOptions,
    required this.onMoreOptionPressed,
  }) : super(key: key);

  final List<CommMoreOption> moreOptions;
  final Function(CommMoreOption commMoreOption) onMoreOptionPressed;

  
  State<ChatMoreOptionSwiperContainer> createState() =>
      _ChatMoreOptionSwiperContainerState();
}

class _ChatMoreOptionSwiperContainerState
    extends State<ChatMoreOptionSwiperContainer> {
  
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 10.0),
      child: GridView.builder(
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: kGridCrossAxisCount, //每行三列
          childAspectRatio: 1.0, //显示区域宽高相等
        ),
        itemCount: widget.moreOptions.length,
        itemBuilder: (context, index) {
          CommMoreOption commMoreOption = widget.moreOptions[index];
          return ChatMoreOptionButton(
            onMoreOptionPressed: widget.onMoreOptionPressed,
            commMoreOption: commMoreOption,
          );
        },
      ),
    );
  }
}

最后使用Swiper实现左右滑动的效果,代码如下

// 中间间隔
const double kOptionSperate = 15.0;
const double kSwiperPaginationHeight = 10.0;

const int kGridCrossAxisCount = 4;
const int kGridCrossAxisRow = 2;

// 更多操作
class ChatMoreOptionPanel extends StatefulWidget {
  const ChatMoreOptionPanel({
    Key? key,
    required this.morePanelHeight,
    required this.chatInputBarController,
    required this.moreOptionEntries,
  }) : super(key: key);

  final double morePanelHeight;
  final ChatInputBarController chatInputBarController;
  final List<CommMoreOption> moreOptionEntries;

  
  State<ChatMoreOptionPanel> createState() => _ChatMoreOptionPanelState();
}

class _ChatMoreOptionPanelState extends State<ChatMoreOptionPanel> {
  List<CommMoreOption> allOptionList = [];

  List<List<CommMoreOption>> optionSwiperList = [];

  
  void initState() {
    // TODO: implement initState
    super.initState();

    CommMoreOption commMoreOption = CommMoreOption();
    commMoreOption.icon = "file://ic_toolbar_camera.png";
    commMoreOption.name = "相机";
    commMoreOption.iconType = CommMoreOptionIconType.commMoreOptionIconFile;
    commMoreOption.type = 0;
    commMoreOption.linkUrl = kOptionCamera;
    allOptionList.add(commMoreOption);

    CommMoreOption commMoreOption1 = CommMoreOption();
    commMoreOption1.icon = "file://ic_toolbar_ablum.png";
    commMoreOption1.name = "相册";
    commMoreOption1.iconType = CommMoreOptionIconType.commMoreOptionIconFile;
    commMoreOption1.type = 0;
    commMoreOption1.linkUrl = kOptionAlbum;
    allOptionList.add(commMoreOption1);

    CommMoreOption commMoreOption2 = CommMoreOption();
    commMoreOption2.icon = "file://ic_toolbar_coupon.png";
    commMoreOption2.name = "卡券";
    commMoreOption2.iconType = CommMoreOptionIconType.commMoreOptionIconFile;
    commMoreOption2.type = 0;
    commMoreOption2.linkUrl = kOptionCoupon;
    allOptionList.add(commMoreOption2);

    if (widget.moreOptionEntries.isNotEmpty) {
      allOptionList.addAll(widget.moreOptionEntries);
    }

    handlerSwiperList();
  }

  void handlerSwiperList() {
    List<List<CommMoreOption>> tmpOptionSwiperList = [];
    int aPageNum = kGridCrossAxisCount * kGridCrossAxisRow;
    int swiperCount = (allOptionList.length % aPageNum == 0
            ? allOptionList.length / aPageNum
            : (allOptionList.length / aPageNum + 1))
        .toInt();
    for (int i = 0; i < swiperCount; i++) {
      int location = 0;
      int length = 0;

      location = i * aPageNum;
      if (i == 0) {
        length =
            aPageNum > allOptionList.length ? allOptionList.length : aPageNum;
      } else {
        length = (1 + i) * aPageNum > allOptionList.length
            ? (allOptionList.length - i * aPageNum)
            : aPageNum;
      }

      List<CommMoreOption> swiperItems =
          allOptionList.sublist(location, (location + length));
      tmpOptionSwiperList.add(swiperItems);
    }
    optionSwiperList = tmpOptionSwiperList;
    setState(() {});
  }

  
  void dispose() {
    // TODO: implement dispose
    super.dispose();
  }

  // 点击不同的操作Option
  void onMoreOptionPressed(CommMoreOption commMoreOption) {
    // 点击不同的操作Option
    // 发送eventBus事件
    CommEventBusModel eventBusModel = CommEventBusModel(
      commEventBusType: CommEventBusType.commEventBusTypeMoreOption,
      data: commMoreOption,
    );
    kCommEventBus.fire(eventBusModel);
  }

  
  Widget build(BuildContext context) {
    Size screenSize = MediaQuery.of(context).size;
    return Container(
      width: screenSize.width,
      height: widget.morePanelHeight,
      decoration: BoxDecoration(
        color: ColorUtil.hexColor(0xf7f7f7),
      ),
      padding: EdgeInsets.only(
        left: 0.0,
        right: 0.0,
        bottom: 0.0,
        top: 0.0,
      ),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Expanded(
            child: Swiper(
              // 横向
              scrollDirection: Axis.horizontal,
              // 布局构建
              itemBuilder: (BuildContext context, int index) {
                List<CommMoreOption> optionList = optionSwiperList[index];
                return ChatMoreOptionSwiperContainer(
                  moreOptions: optionList,
                  onMoreOptionPressed: (CommMoreOption commMoreOption) {
                    onMoreOptionPressed(commMoreOption);
                  },
                );
              },
              //条目个数
              itemCount: optionSwiperList.length,
              // 自动翻页
              autoplay: false,
              // 分页指示
              pagination: SwiperPagination(
                //指示器显示的位置 Alignment.bottomCenter 底部中间
                alignment: Alignment.bottomCenter,
                // 距离调整
                margin: const EdgeInsets.only(bottom: 0.0),
                // 指示器构建
                builder: DotSwiperPaginationBuilder(
                  // 点之间的间隔
                  space: 3,
                  // 没选中时的大小
                  size: 6,
                  // 选中时的大小
                  activeSize: 6,
                  // 没选中时的颜色
                  color: ColorUtil.hexColor(0xDCDCDC),
                  //选中时的颜色
                  activeColor: ColorUtil.hexColor(0xff462e),
                ),
              ),
              // pagination: _buildSwiperPagination(),
              // pagination: _buildNumSwiperPagination(),
              //点击事件
              onTap: (index) {
                print(" 点击 " + index.toString());
              },
              // 相邻子条目视窗比例
              viewportFraction: 1,
              // 用户进行操作时停止自动翻页
              autoplayDisableOnInteraction: true,
              // 无限轮播
              loop: false,
              //当前条目的缩放比例
              scale: 1,
            ),
          ),
          buildAreaBottom(context),
        ],
      ),
    );
  }

  Widget buildAreaBottom(BuildContext context) {
    EdgeInsets viewPadding = MediaQuery.of(context).viewPadding;
    Size screenSize = MediaQuery.of(context).size;
    return Container(
      decoration: BoxDecoration(
        color: ColorUtil.hexColor(0xf7f7f7),
      ),
      height: viewPadding.bottom,
      width: screenSize.width,
    );
  }
}

三、小结

flutter聊天界面-加号【➕】更多展开相机、相册等操作Panel菜单,主要Swiper和GridView排列相机、相册等按钮,点击按钮时候发送事件,使用EventBus来处理后续的逻辑实现。

学习记录,每天不停进步。文章来源地址https://www.toymoban.com/news/detail-537631.html

到了这里,关于flutter聊天界面-加号【➕】更多展开相机、相册等操作Panel的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • flutter聊天界面-TextField输入框buildTextSpan实现@功能展示高亮功能

    flutter聊天界面-TextField输入框buildTextSpan实现@功能展示高亮功能 最近有位朋友讨论的时候,提到了输入框的高亮展示。在flutter TextField中需要插入特殊样式的标签,比如:“请 @张三 回答一下”,这一串字符在TextField中输入,当输入@时 弹出好友列表选择,然后将 “@张三”高

    2024年02月07日
    浏览(42)
  • flutter聊天界面-Text富文本表情emoji、url、号码展示

    flutter聊天界面-Text富文本表情emoji、url、号码展示 Text富文本表情emoji展示,主要通过实现Text.rich展示文本、emoji、自定义表情、URL等 Text用于显示简单样式文本 TextSpan它代表文本的一个“片段”,不同“片段”可按照不同的样式显示。 示例片段 Text富文本表情emoji展示主要通过

    2024年02月12日
    浏览(28)
  • 微软将推出更多Edge特有功能,与Chrome展开竞争

    微软在 2018 年宣布将推出基于 Chromium 构建的 Edge 浏览器,并于 2020 年 1 月推出了新版 Edge。如今时隔三年,根据统计 Edge 全平台的市场占有率仅为 4.23%,如果只考虑桌面端的话,Edge 的市场占有率则是 10.98%,这两个数据均远远落后于 Chrome 的 64.68% 和 66.14%。 再加上 Edge 如今已

    2024年02月17日
    浏览(36)
  • CSS处理文字段落尾行行末缩进,点击查看更多展开效果

    需求:  如图:第三行文末需要展示省略号,并且有查看更多按钮,切换显示隐藏。 常规css处理方法: 控制文字行数: // 多行显示 .text_morerow {     overflow: hidden;     display: -webkit-box;     -webkit-line-clamp: 2; // 控制显示行数     -webkit-box-orient: vertical;     word-break: break-all; 

    2024年02月06日
    浏览(36)
  • vue 实现内容超出两行显示展开更多功能,可依据需求自定义任意行数!

    平时开发中我们经常会遇到这样的需求,在一个不限高度的盒子中会有很多内容,如果全部显示用户体验会非常不好,所以可以先折叠起来,当内容达到一定高度时,显示 展开更多 按钮, 点击即可显示全部内容 ,先来看看效果图:  这样做用户体验瞬间得到提升,接下来看

    2023年04月24日
    浏览(27)
  • uniapp 水印/相机/授权位置、相机、相册权限

    自定义相机水印 授权     // 手动授权【摄像头】     function getAuth() {         // 获取摄像头权限         uni.getSetting({             success(res) {                 console.log(\\\"auth res\\\", res);                 const authSetting = res.authSetting;                 if (auth

    2024年02月02日
    浏览(28)
  • iOS——调用系统相册和相机

    调用相册需要用到UIImagePickerController,这是iOS系统提供的和系统的相册和相机交互的一个类,可以用来获取相册的照片,也可以调用系统的相机拍摄照片或者视频。该类的继承结构是: UIImagePickerController–UINavigationController–UIViewController–UIResponder–NSObject 首先需要导入对应的库和

    2024年02月04日
    浏览(26)
  • flutter开发实战-图片保存到相册

    flutter开发实战-图片保存到相册。保存相册使用的是image_gallery_saver插件 在pubspec.yaml中引入插件 使用image_gallery_saver将图片保存到相册 flutter开发实战-图片保存到相册。保存相册使用的是image_gallery_saver插件。 学习记录,每天不停进步。

    2024年02月15日
    浏览(47)
  • flutter base64图片保存到相册

    首先base64转成uint8List,然后再用插件保存到相册(没有内置的方法处理) 保存图片的插件 完整代码如下 为啥要用下面 因为’data:image/png;base64,’ is part of the data URL,不是base-64字符串的一部分。您需要首先从URL中提取base-64数据。 否则就会报错如下: 网站用图片转base64如下

    2024年02月01日
    浏览(30)
  • 【iOS-UIImagePickerController访问相机和相册】

    UIImagePickerController是iOS平台上的一个类,用于在应用程序中访问设备的照片库、相机和视频录制功能。它提供了一个用户界面,使用户可以从设备的媒体库中选择照片或视频,或者使用设备的摄像头拍摄照片或录制视频。在这里我们先只介绍一下访问相机和相册这两个功能。

    2024年02月04日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包