Flutter构建聊天页面+接入图灵机器人
程序员文章站
2022-06-04 09:54:04
...
作为一个专注flutter开发十年的老人,我想说talk is cheap, show me the gif:
这里特别感谢一下screenToGif软件,只有3MB大小,却是录屏转gif的神器,墙裂推荐给大家!
如何用flutter构建一个聊天页面?
1.引入bubble: ^1.1.9这个插件,这是一个可以带口子的聊天框,各种样式设定都有,一下对它封装制造一个自定义组件ChatRow,源码如下:
class ChatRow extends StatelessWidget{
String avatarLocalSavedPath;
String content;
bool isMyself;
ChatRow({@required this.avatarLocalSavedPath,
@required this.content,
@required this.isMyself});
@override
Widget build(BuildContext context) {
if(isMyself) {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Bubble(
margin: BubbleEdges.only(top: 10),
alignment: Alignment.topRight,
nip: BubbleNip.rightTop,
child: Container(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width/2
),
child: Text(content)
),
),
SizedBox(
height: 50,
child: Image.asset(this.avatarLocalSavedPath)),
],
);
}else{
return Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 50,
child: Image.asset("assets/TuringRobot.jpg")
),
Bubble(
margin: BubbleEdges.only(top: 10),
alignment: Alignment.topLeft,
nip: BubbleNip.leftTop,
child: Container(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width/2
),
child: Text(this.content)
),
),
],
);
}
}
}
这里三个参数分别代表用户头像储存路径、说话的内容和是不是用户自己(主要用于区分左右行构建),大家伙可以根据自己的需求改良。比如添加用户ID变量,尺寸引入screenUtil作全款型适配。
2.底层输入框自定义组件
这里完全模仿了微信,觉得微信的前端码农还是挺厉害的,输入文字切发送按钮,文字消除切表情按钮,很好很方便。这里巧用TextField的onChanged回调方法和发送按钮的onPressed方法解决切换问题。
3.底层输入框和聊天行的配合
第一个就是输入框弹起时和聊天行一起上拉
这里在Column控件外层套用一个SingleChildScrollView
@override
Widget build(BuildContext context) {
lcr=_getList(Provider.of<ChatContentProvider>(context).lcim);
// TODO: implement build
return SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height*8/10,
child: GestureDetector(
onTap: (){
FocusScope.of(context).requestFocus(FocusNode());
},
child: ListView(
//padding: EdgeInsets.only(top: max(MediaQuery.of(context).size.height/2-lcr.length*30, 0)),
reverse: true,
children: lcr,
),
)
),
BottomInput(),
],
),
);
}
第二个是保持输入框和ListView里最后一条信息贴合
列表添加收到信息的顺序要注意
void addChatItem(ChatItemModel cim){
if(lcim.isEmpty)lcim.add(cim);
else
lcim.insert(0, cim);
notifyListeners();
}
再就是ListView的reverse属性设置为true
ListView(
reverse: true,
children: lcr,
),
第三个就是聊天框最大宽度的限制
Container(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width/2
),
child: Text(content)
),
),
页面的数据传入是在widget树上层绑定这个ChatContentProvider,这个信息主要就是维护一个聊天行的List。
如何用flutter接入图灵机器人?
注册->拿到API_KEY和USER_ID->用dio库直接发送请求就好了
这里记住李文周老师的一句话:一个请求对应一个响应
import 'package:dio/dio.dart';
import 'dart:convert' as Convert;
class SelfHttpUtil{
static const API_KEY="填你自己的秘钥";
static const USER_ID="填你自己的用户号";
Dio dio=new Dio();
Future<String> getHttp(String sentMsg) async{
try{
Response response = await dio.post(
"http://openapi.tuling123.com/openapi/api/v2",
data: {
"reqType":0,
"perception": {
"inputText": {
"text": sentMsg
},
},
"userInfo": {
"apiKey": API_KEY,
"userId": USER_ID,
}
}
);
print("get response from turing robot server");
print(response);
Map<String, dynamic> data=Convert.jsonDecode(response.data);
print("data is $data");
List list=data["results"];
print("list is $list");
String replyContent=list[0]["values"]["text"];
print(replyContent);
return replyContent;
}catch(e){
print(e);
}
}
}
最后我想说,我只从事了flutter开发2周,有兴趣的话联系我吧,一起做点有意义的事。