flutter聊天界面-自定义表情键盘实现
flutter 是 Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。开发者可以通过 Dart语言开发 App,一套代码同时运行在 iOS 和 Android平台。

flutter开发基础腾讯IM的聊天应用,使用的是tencent_im_sdk_plugin插件。使用的是自定义表情。

一、使用的表情

1.1、自定义表情

这里使用自定义表情,表情列表如下

const emojiUrl = 'https://web.sdk.qcloud.com/im/assets/emoji/';const emojiMap = {'[NO]': 'emoji_0@2x.png','[OK]': 'emoji_1@2x.png','[下雨]': 'emoji_2@2x.png','[么么哒]': 'emoji_3@2x.png','[乒乓]': 'emoji_4@2x.png','[便便]': 'emoji_5@2x.png','[信封]': 'emoji_6@2x.png','[偷笑]': 'emoji_7@2x.png','[傲慢]': 'emoji_8@2x.png','[再见]': 'emoji_9@2x.png','[冷汗]': 'emoji_10@2x.png','[凋谢]': 'emoji_11@2x.png','[刀]': 'emoji_12@2x.png','[删除]': 'emoji_13@2x.png','[勾引]': 'emoji_14@2x.png','[发呆]': 'emoji_15@2x.png','[发抖]': 'emoji_16@2x.png','[可怜]': 'emoji_17@2x.png','[可爱]': 'emoji_18@2x.png','[右哼哼]': 'emoji_19@2x.png','[右太极]': 'emoji_20@2x.png','[右车头]': 'emoji_21@2x.png','[吐]': 'emoji_22@2x.png','[吓]': 'emoji_23@2x.png','[咒骂]': 'emoji_24@2x.png','[咖啡]': 'emoji_25@2x.png','[啤酒]': 'emoji_26@2x.png','[嘘]': 'emoji_27@2x.png','[回头]': 'emoji_28@2x.png','[困]': 'emoji_29@2x.png','[坏笑]': 'emoji_30@2x.png','[多云]': 'emoji_31@2x.png','[大兵]': 'emoji_32@2x.png','[大哭]': 'emoji_33@2x.png','[太阳]': 'emoji_34@2x.png','[奋斗]': 'emoji_35@2x.png','[奶瓶]': 'emoji_36@2x.png','[委屈]': 'emoji_37@2x.png','[害羞]': 'emoji_38@2x.png','[尴尬]': 'emoji_39@2x.png','[左哼哼]': 'emoji_40@2x.png','[左太极]': 'emoji_41@2x.png','[左车头]': 'emoji_42@2x.png','[差劲]': 'emoji_43@2x.png','[弱]': 'emoji_44@2x.png','[强]': 'emoji_45@2x.png','[彩带]': 'emoji_46@2x.png','[彩球]': 'emoji_47@2x.png','[得意]': 'emoji_48@2x.png','[微笑]': 'emoji_49@2x.png','[心碎了]': 'emoji_50@2x.png','[快哭了]': 'emoji_51@2x.png','[怄火]': 'emoji_52@2x.png','[怒]': 'emoji_53@2x.png','[惊恐]': 'emoji_54@2x.png','[惊讶]': 'emoji_55@2x.png','[憨笑]': 'emoji_56@2x.png','[手枪]': 'emoji_57@2x.png','[打哈欠]': 'emoji_58@2x.png','[抓狂]': 'emoji_59@2x.png','[折磨]': 'emoji_60@2x.png','[抠鼻]': 'emoji_61@2x.png','[抱抱]': 'emoji_62@2x.png','[抱拳]': 'emoji_63@2x.png','[拳头]': 'emoji_64@2x.png','[挥手]': 'emoji_65@2x.png','[握手]': 'emoji_66@2x.png','[撇嘴]': 'emoji_67@2x.png','[擦汗]': 'emoji_68@2x.png','[敲打]': 'emoji_69@2x.png','[晕]': 'emoji_70@2x.png','[月亮]': 'emoji_71@2x.png','[棒棒糖]': 'emoji_72@2x.png','[汽车]': 'emoji_73@2x.png','[沙发]': 'emoji_74@2x.png','[流汗]': 'emoji_75@2x.png','[流泪]': 'emoji_76@2x.png','[激动]': 'emoji_77@2x.png','[灯泡]': 'emoji_78@2x.png','[炸弹]': 'emoji_79@2x.png','[熊猫]': 'emoji_80@2x.png','[爆筋]': 'emoji_81@2x.png','[爱你]': 'emoji_82@2x.png','[爱心]': 'emoji_83@2x.png','[爱情]': 'emoji_84@2x.png','[猪头]': 'emoji_85@2x.png','[猫咪]': 'emoji_86@2x.png','[献吻]': 'emoji_87@2x.png','[玫瑰]': 'emoji_88@2x.png','[瓢虫]': 'emoji_89@2x.png','[疑问]': 'emoji_90@2x.png','[白眼]': 'emoji_91@2x.png','[皮球]': 'emoji_92@2x.png','[睡觉]': 'emoji_93@2x.png','[磕头]': 'emoji_94@2x.png','[示爱]': 'emoji_95@2x.png','[礼品袋]': 'emoji_96@2x.png','[礼物]': 'emoji_97@2x.png','[篮球]': 'emoji_98@2x.png','[米饭]': 'emoji_99@2x.png','[糗大了]': 'emoji_100@2x.png','[红双喜]': 'emoji_101@2x.png','[红灯笼]': 'emoji_102@2x.png','[纸巾]': 'emoji_103@2x.png','[胜利]': 'emoji_104@2x.png','[色]': 'emoji_105@2x.png','[药]': 'emoji_106@2x.png','[菜刀]': 'emoji_107@2x.png','[蛋糕]': 'emoji_108@2x.png','[蜡烛]': 'emoji_109@2x.png','[街舞]': 'emoji_110@2x.png','[衰]': 'emoji_111@2x.png','[西瓜]': 'emoji_112@2x.png','[调皮]': 'emoji_113@2x.png','[象棋]': 'emoji_114@2x.png','[跳绳]': 'emoji_115@2x.png','[跳跳]': 'emoji_116@2x.png','[车厢]': 'emoji_117@2x.png','[转圈]': 'emoji_118@2x.png','[鄙视]': 'emoji_119@2x.png','[酷]': 'emoji_120@2x.png','[钞票]': 'emoji_121@2x.png','[钻戒]': 'emoji_122@2x.png','[闪电]': 'emoji_123@2x.png','[闭嘴]': 'emoji_124@2x.png','[闹钟]': 'emoji_125@2x.png','[阴险]': 'emoji_126@2x.png','[难过]': 'emoji_127@2x.png','[雨伞]': 'emoji_128@2x.png','[青蛙]': 'emoji_129@2x.png','[面条]': 'emoji_130@2x.png','[鞭炮]': 'emoji_131@2x.png','[风车]': 'emoji_132@2x.png','[飞吻]': 'emoji_133@2x.png','[飞机]': 'emoji_134@2x.png','[饥饿]': 'emoji_135@2x.png','[香蕉]': 'emoji_136@2x.png','[骷髅]': 'emoji_137@2x.png','[麦克风]': 'emoji_138@2x.png','[麻将]': 'emoji_139@2x.png','[鼓掌]': 'emoji_140@2x.png','[龇牙]': 'emoji_141@2x.png',
};const emojiName = ['[龇牙]','[调皮]','[流汗]','[偷笑]','[再见]','[敲打]','[擦汗]','[猪头]','[玫瑰]','[流泪]','[大哭]','[嘘]','[酷]','[抓狂]','[委屈]','[便便]','[炸弹]','[菜刀]','[可爱]','[色]','[害羞]','[得意]','[吐]','[微笑]','[怒]','[尴尬]','[惊恐]','[冷汗]','[爱心]','[示爱]','[白眼]','[傲慢]','[难过]','[惊讶]','[疑问]','[困]','[么么哒]','[憨笑]','[爱情]','[衰]','[撇嘴]','[阴险]','[奋斗]','[发呆]','[右哼哼]','[抱抱]','[坏笑]','[飞吻]','[鄙视]','[晕]','[大兵]','[可怜]','[强]','[弱]','[握手]','[胜利]','[抱拳]','[凋谢]','[米饭]','[蛋糕]','[西瓜]','[啤酒]','[瓢虫]','[勾引]','[OK]','[爱你]','[咖啡]','[月亮]','[刀]','[发抖]','[差劲]','[拳头]','[心碎了]','[太阳]','[礼物]','[皮球]','[骷髅]','[挥手]','[闪电]','[饥饿]','[困]','[咒骂]','[折磨]','[抠鼻]','[鼓掌]','[糗大了]','[左哼哼]','[打哈欠]','[快哭了]','[吓]','[篮球]','[乒乓]','[NO]','[跳跳]','[怄火]','[转圈]','[磕头]','[回头]','[跳绳]','[激动]','[街舞]','[献吻]','[左太极]','[右太极]','[闭嘴]','[猫咪]','[红双喜]','[鞭炮]','[红灯笼]','[麻将]','[麦克风]','[礼品袋]','[信封]','[象棋]','[彩带]','[蜡烛]','[爆筋]','[棒棒糖]','[奶瓶]','[面条]','[香蕉]','[飞机]','[左车头]','[车厢]','[右车头]','[多云]','[下雨]','[钞票]','[熊猫]','[灯泡]','[风车]','[闹钟]','[雨伞]','[彩球]','[钻戒]','[沙发]','[纸巾]','[手枪]','[青蛙]',
];

1.2、定义自定义表情数据类

这里定义自定义表情的数据类 CommonChatEmoji

class CommonChatEmojiItem {String? emojiName;String? url;CommonChatEmojiItem({required this.emojiName, required this.url});
}class CommonChatEmoji {static List<CommonChatEmojiItem> emojiUrlList() {return emojiName.map((item) => CommonChatEmojiItem(emojiName: item, url: emojiUrl + emojiMap[item]!)).toList();}static bool emojiIsContain(String emojiName) {bool isContain = false;CommonChatEmojiItem? emojiItem = CommonChatEmoji.findEmojiItem(emojiName);if (emojiName.contains(emojiName) && emojiItem != null) {isContain = true;}return isContain;}static CommonChatEmojiItem? findEmojiItem(String emojiName) {List<CommonChatEmojiItem> emojiItemList = CommonChatEmoji.emojiUrlList();CommonChatEmojiItem? emojiItem;for(CommonChatEmojiItem item in emojiItemList) {if (emojiName == item.emojiName) {emojiItem = item;break;}}return emojiItem;}
}

二、聊天表情键盘

2.1、实现表情排列Panel键盘

排列表情,使用的是GridView.builder,GridView网格布局是一种常见的布局类型,GridView 组件正是实现了网格布局的组件,
SliverGridDelegate是一个抽象类,定义了GridView Layout相关接口,子类需要通过实现它们来实现具体的布局算法。Flutter中提供了两个SliverGridDelegate的子类SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent,

            GridView.builder(gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 7, //每行三列childAspectRatio: 1.0, //显示区域宽高相等),itemCount: CommonChatEmoji.emojiUrlList().length,itemBuilder: (context, index) {CommonChatEmojiItem emojiItem =CommonChatEmoji.emojiUrlList()[index];return ChatInputEmojiButton(emojiItem: emojiItem,size: itemSize,onEmojiLongPressed: widget.onEmojiLongPressed,onEmojiTapPressed: widget.onEmojiTapPressed,);},padding: EdgeInsets.only(bottom: deleteBarHeight,),),

排列效果如图所示

聊天界面的表情Panel的布局完整代码

// 表情输入
class ChatInputEmojiPanel extends StatefulWidget {const ChatInputEmojiPanel({Key? key,required this.emojiPanelHeight,required this.chatInputBarController,required this.onTextFieldDelete,required this.onEmojiTapPressed,required this.onEmojiLongPressed,required this.onTextFieldSend,}) : super(key: key);final double emojiPanelHeight;final ChatInputBarController chatInputBarController;final Function onTextFieldDelete;final Function onTextFieldSend;final Function(CommonChatEmojiItem emojiItem) onEmojiTapPressed;final Function(CommonChatEmojiItem emojiItem, Offset globalPosition) onEmojiLongPressed;@overrideState<ChatInputEmojiPanel> createState() => _ChatInputEmojiPanelState();
}class _ChatInputEmojiPanelState extends State<ChatInputEmojiPanel> {@overridevoid initState() {// TODO: implement initStatesuper.initState();}@overridevoid dispose() {// TODO: implement disposesuper.dispose();}@overrideWidget build(BuildContext context) {Size screenSize = MediaQuery.of(context).size;int crossAxisCount = 7;double itemSize = screenSize.width / crossAxisCount;EdgeInsets viewPadding = MediaQuery.of(context).viewPadding;double emojiCateBarHeight = 50.0 + viewPadding.bottom;double deleteBarHeight = 50.0;return Container(width: screenSize.width,height: widget.emojiPanelHeight,decoration: BoxDecoration(color: ColorUtil.hexColor(0xf7f7f7),),child: Column(mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: [Expanded(child: Stack(children: [GridView.builder(gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 7, //每行三列childAspectRatio: 1.0, //显示区域宽高相等),itemCount: CommonChatEmoji.emojiUrlList().length,itemBuilder: (context, index) {CommonChatEmojiItem emojiItem =CommonChatEmoji.emojiUrlList()[index];return ChatInputEmojiButton(emojiItem: emojiItem,size: itemSize,onEmojiLongPressed: widget.onEmojiLongPressed,onEmojiTapPressed: widget.onEmojiTapPressed,);},padding: EdgeInsets.only(bottom: deleteBarHeight,),),Positioned(bottom: 0.0,right: 0.0,child: ChatInputEmojiDeleteBar(height: deleteBarHeight,onTextFieldDelete: widget.onTextFieldDelete,),),],),),ChatInputEmojiCateBar(height: emojiCateBarHeight,onTextFieldSend: widget.onTextFieldSend,),],),);}
}// 显示表情Emoji图片
class ChatInputEmojiButton extends StatelessWidget {const ChatInputEmojiButton({Key? key,required this.emojiItem,required this.size,required this.onEmojiTapPressed,required this.onEmojiLongPressed,}) : super(key: key);final CommonChatEmojiItem emojiItem;final double size;final Function(CommonChatEmojiItem emojiItem) onEmojiTapPressed;final Function(CommonChatEmojiItem emojiItem, Offset globalPosition) onEmojiLongPressed;@overrideWidget build(BuildContext context) {double iconSize = size;if (iconSize > 36.0) {iconSize = 36.0;}return ButtonWidget(width: size,height: size,onLongPressStart: (LongPressStartDetails details) {onEmojiLongPressed(emojiItem, details.globalPosition);},onPressed: () {onEmojiTapPressed(emojiItem);},child: ImageHelper.imageNetwork(imageUrl: "${emojiItem.url}",fit: BoxFit.cover,width: iconSize,height: iconSize,),);}
}

2.2、表情Panel的布局代码。

// 底部表情切换bar与发送按钮
class ChatInputEmojiCateBar extends StatefulWidget {const ChatInputEmojiCateBar({Key? key,required this.height,required this.onTextFieldSend,}) : super(key: key);final double height;final Function onTextFieldSend;@overrideState<ChatInputEmojiCateBar> createState() => _ChatInputEmojiCateBarState();
}class _ChatInputEmojiCateBarState extends State<ChatInputEmojiCateBar> {@overrideWidget build(BuildContext context) {EdgeInsets viewPadding = MediaQuery.of(context).viewPadding;Size screenSize = MediaQuery.of(context).size;print("ChatInputEmojiCateBar viewPadding bottom:${viewPadding.bottom}");return Container(width: screenSize.width,height: widget.height,decoration: BoxDecoration(color: ColorUtil.hexColor(0xf7f7f7),border: Border(bottom: BorderSide(width: 0.0, color: ColorUtil.hexColor(0xffffff)),left: BorderSide(width: 0.0, color: ColorUtil.hexColor(0xffffff)),right: BorderSide(width: 0.0, color: ColorUtil.hexColor(0xffffff)),top: BorderSide(width: 1.0, color: ColorUtil.hexColor(0xf0f0f0)),),),child: Column(mainAxisAlignment: MainAxisAlignment.start,crossAxisAlignment: CrossAxisAlignment.center,children: [Expanded(child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,crossAxisAlignment: CrossAxisAlignment.start,children: [ButtonWidget(margin: EdgeInsets.only(left: 10.0),width: 36.0,onPressed: () {},child: ImageHelper.wrapAssetAtImages("icons/ic_custom_emoji_cate.png",fit: BoxFit.cover,width: 32.0,height: 32.0,),),Expanded(child: Container(),),ButtonWidget(margin: const EdgeInsets.only(left: 10.0),width: 70.0,bgColor: ColorUtil.hexColor(0xf7f7f7),bgHighlightedColor: ColorUtil.hexColor(0x3b93ff, alpha: 0.35),onPressed: () {widget.onTextFieldSend();},child: Text("发送",textAlign: TextAlign.center,maxLines: 1000,overflow: TextOverflow.ellipsis,softWrap: true,style: TextStyle(fontSize: 16,fontWeight: FontWeight.w500,fontStyle: FontStyle.normal,color: ColorUtil.hexColor(0x3b93ff),decoration: TextDecoration.none,),),),],),),SizedBox(height: viewPadding.bottom,),],),);}
}

删除输入的表情的删除按钮

// 表情键盘底部发送及删除按钮
class ChatInputEmojiDeleteBar extends StatefulWidget {const ChatInputEmojiDeleteBar({Key? key,required this.height,required this.onTextFieldDelete,}) : super(key: key);final double height;final Function onTextFieldDelete;@overrideState<ChatInputEmojiDeleteBar> createState() =>_ChatInputEmojiDeleteBarState();
}class _ChatInputEmojiDeleteBarState extends State<ChatInputEmojiDeleteBar> {@overrideWidget build(BuildContext context) {return Container(padding: EdgeInsets.only(right: 10.0),color: Colors.transparent,height: widget.height,child: Row(mainAxisAlignment: MainAxisAlignment.end,crossAxisAlignment: CrossAxisAlignment.center,children: [ButtonWidget(onPressed: () {widget.onTextFieldDelete();},child: ImageHelper.wrapAssetAtImages("icons/ic_backspace.png",fit: BoxFit.cover,width: 42.0,height: 42.0,),),],),);}
}

2.3、长按预览表情

当我们使用常见的聊天工具的时候,表情基本上都有预览功能,这里实现长按预览表情功能。
预览表情效果如下

具体代码

/// 表情长按预览功能
class ChatInputEmojiPreview extends StatefulWidget {const ChatInputEmojiPreview({Key? key,required this.emojiItem,required this.width,required this.height,}) : super(key: key);final CommonChatEmojiItem emojiItem;final double width;final double height;@overrideState<ChatInputEmojiPreview> createState() => _ChatInputEmojiPreviewState();
}class _ChatInputEmojiPreviewState extends State<ChatInputEmojiPreview> {@overrideWidget build(BuildContext context) {return Container(child: ChatInputEmojiShowEmoji(emojiItem: widget.emojiItem,width: widget.width,height: widget.height,),);}
}// 显示预览的内容
class ChatInputEmojiShowEmoji extends StatelessWidget {const ChatInputEmojiShowEmoji({Key? key,required this.emojiItem,required this.width,required this.height,}) : super(key: key);final CommonChatEmojiItem emojiItem;final double width;final double height;@overrideWidget build(BuildContext context) {return Container(width: width,height: height,child: Stack(children: [ImageHelper.wrapAssetAtImages("icons/bg_emoji-preview.png",width: width,height: height,),Column(mainAxisAlignment: MainAxisAlignment.start,crossAxisAlignment: CrossAxisAlignment.center,children: [SizedBox(height: 25.0,),ImageHelper.imageNetwork(imageUrl: "${emojiItem.url}",fit: BoxFit.cover,width: 60,height: 60,),SizedBox(height: 3.0,),Text("${emojiItem.emojiName}",textAlign: TextAlign.center,maxLines: 1,overflow: TextOverflow.ellipsis,style: TextStyle(fontSize: 16,fontWeight: FontWeight.w500,fontStyle: FontStyle.normal,color: ColorUtil.hexColor(0x555555),decoration: TextDecoration.none,),),Expanded(child: Container(),),],),],),);}
}

三、小结

flutter聊天界面-自定义表情键盘实现,主要实现GridView布局表情,自定义预览功能,使用GestureDetector长按功能得到LongPressStartDetails details获得长按的位置,展示表情预览、表情的图片和文本富文本展示-Text.rich(TextSpan(children: textSapns));。

学习记录,每天不停进步。

flutter聊天界面-自定义表情键盘实现相关推荐

  1. 一款相对比较简单 聊天界面的 表情输入库:

    一,前言: 说实话,搞了这么久的Android,个人感觉,Android开发 其实只是一个无限重复的工作.         当然说这句话是有前提的,前提就是你还未从一个代码学习者转变为一个代码创造者. ...

  2. flutter图片聊天泡泡_flutter即时聊天IM仿微信|flutter聊天界面

    鉴于Flutter最近比较火,今天给大家分享的是基于flutter+dart全家桶技术开发的仿微信界面聊天FlutterChat项目实例.实现了消息+表情.图片预览.红包.长按菜单.视频/仿朋友圈等功 ...

  3. Android键盘自定义表情包,关于自定义表情键盘...

    在做输入的时候,除了可以输入系统的表情符号,项目中通常还要求输入表情图片 表情图片 1.正则表达式 一个正则表达式,就是一串有特定意义的字符,首先要编译成为一个Pattern对象,然后使用matche ...

  4. Android自定义表情键盘与输入法键盘冲突

    下面输入框在界面的中间位置,点击输入框弹出输入法键盘,如果此时表情键盘打开要收回表情键盘:点击笑脸图标弹出表情键盘,如果此时输入法键盘打开则要收回输入法键盘: 由于点击输入框输入法键盘是自动弹出的,因 ...

  5. Swift自定义表情键盘+录音

    老规矩,一图胜千言.Demo 传送门 点我就行 . 运行环境 Xcode10 swift 4.0 前言 这里没有干货,也没有教程,请各位大神手下留情.这个 demo 是平时自己在工作之余学习 swif ...

  6. flutter 聊天界面+表情图片

    网上找了找 零零碎碎有一些文章 没找到一个整体的 自己做完记录一下 防止忘了 大体就是这样 聊天气泡用的是 https://blog.csdn.net/oterminator12/article/de ...

  7. Qt仿QQ界面,主界面、聊天界面、表情界面

    利用Qt仿的QQ的界面如下:

  8. Android 仿qq聊天界面之一

    一.登录界面 本来是只想仿一个qq的聊天界面的,顺便做了一个登录界面,熟悉下SharedPreferences(解释一下:SharedPreferences由于非常适合记录一些零散的简单的数据,因此登 ...

  9. iOS_仿QQ表情键盘

    当UITextFiled和UITextView这种文本输入类控件成为第一响应者时,弹出的键盘由他们的一个UIView类的inputView属性来控制,当inputView为nil时会弹出系统的键盘,想 ...

最新文章

  1. mysql err 1349_MySQL 视图 第1349号错误解决方法
  2. Android中Canvas绘图之Shader使用图文详解
  3. ocp 043 第十三章:管理资源
  4. jsp项目开发案例_Laravel中使用swoole项目实战开发案例一 (建立swoole和前端通信)
  5. python程序文件的扩展名称是什么_python程序文件的扩展名称是什么_Python教程,python,扩展名...
  6. Windows服务创建及安装
  7. python 获取当前日期和时间_如何在Python中获取当前日期和时间?
  8. 视频教程-ASP.NET就业实例视频教程(1)基础入门——搭建网站开发环境教学视频-.NET
  9. 微信公众平台素材编辑与自动回复图文教程
  10. 网易游戏互娱 笔试题2021.8.7 Java版
  11. 【分布式 论文】之 1. MapReduce——Simplified Data Processing on Large Clusters
  12. Oracle 添加主键、索引、删除主键、索引
  13. ICPC训练联盟2021寒假冬令营(5)_2021.01.22_笔记
  14. Flask开发微电影网站(一)
  15. 云栖大会,一场边缘云计算的「超前瞻」之约
  16. 英特尔将调整上网本策略:推199美元MeeGo机型
  17. 以悠悠之生,立一技之长,而贞静自守
  18. 企业在知乎上做问答推广的技巧分析,企业知乎推广营销方法步骤
  19. python 与and运算符
  20. C++/数据结构——课程设计——回合制对战小游戏

热门文章

  1. 苦逼了就辞职弃学去旅行?
  2. git 迭代开发分支流程规范
  3. python扩展包安装_Python扩展库的安装方法
  4. java中对象数组如何构造_对象数组如何构造
  5. 共享打印机无法完成(错误Ox00000709)
  6. 图像语义分割在皮肤检测,缺陷检测上的应用。
  7. one方法报错 select_mybatis中selectOne方法分析
  8. 红黑树原理浅谈(附Linux内核源码注释)
  9. 你梦中的嫁衣为谁而穿红装
  10. python seo 相关的库_【张亚楠】Python你必须知道的十个库【翻】