flutter聊天界面-加号【➕】更多展开相机、相册等操作Panel
在之前实现了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 _ChatMoreOptionSwiperContainerStateextends 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 initStatesuper.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 disposesuper.dispose();}// 点击不同的操作Optionvoid 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来处理后续的逻辑实现。
学习记录,每天不停进步。