当前位置:   article > 正文

flutter项目爬坑记录_flutter实现ajax请求

flutter实现ajax请求

目录

一、flutter内的布局

二、flutter内的倒计时 periodic

三、flutter的生命周期

四、网络请求AJAX,在这里我们不使用flutter自带的,我们使用第三方插件进行网络请求(dio插件进行请求)

五、底部TabBar的组件

六、路由的跳转和返回

七、数据序列化(数据很多,不方便根据数据类型一一处理的时候,使用数据序列化,事半功倍)

八、下拉刷新组件(RefreshIndicator)和上拉加载

九、时间格式化,比如:一小时之前,刚刚等等,这里我们借助第三方插件timeago

十、边栏组件的使用(Drawer)

十一、子组件调用父组件的方法

十二、sliver的使用,页面上滑,将作者和相关信息固定在顶部不消失,实现代码如下,讲解一下

十三、flutter中的弹框

十四、flutter中的输入框,TextField,页面中的Expanded是自适应宽度


一、flutter内的布局

布局分Column(竖向)和Row(横向)

二、flutter内的倒计时 periodic

  1. //开启一个定时器
  2. var _timer;
  3. _timer = Timer.periodic(
  4. Duration(seconds: 1),
  5. (timer) {
  6. print('表示1秒执行一次')
  7. },
  8. );
  9. //关闭一个定时器
  10. _timer.cancel();

三、flutter的生命周期

  1. // flutter的生命周期
  2. // 1、初始化状态,可以获取数据等等操作
  3. @override
  4. void initState() {
  5. super.initState();
  6. }
  7. // 2、构建dom的状态
  8. // @override
  9. // Widget build(){}
  10. // 3、页面销毁的状态(离开页面将要销毁的时候,相当于vue的beforedetroy)
  11. @override
  12. void dispose() {
  13. super.dispose();
  14. }

四、网络请求AJAX,在这里我们不使用flutter自带的,我们使用第三方插件进行网络请求(dio插件进行请求)

  1. //引入dio第三方库
  2. import 'package:dio/dio.dart';
  3. import 'package:newtoutiao/moudle/config.dart';
  4. import 'package:shared_preferences/shared_preferences.dart';
  5. Dio dio = new Dio(); //创建实例
  6. class PubMOdule {
  7. static httpRequestApi(method, url, [data]) async {
  8. // SharedPreferences第三方的存取和获取token的插件,prefs里有get获取token和set存储token
  9. SharedPreferences prefs = await SharedPreferences.getInstance();
  10. try {
  11. // 设置请求头
  12. dio.options.headers['Autoken'] =
  13. prefs.getString('token') ?? ''; //获取token,如果没有token就默认为空
  14. Response response;
  15. switch (method) {
  16. case "get":
  17. response = await dio.get(Config.baseUrl + url);
  18. break;
  19. case "post":
  20. response = await dio.post(Config.baseUrl + url, data: data);
  21. break;
  22. }
  23. return response;
  24. } catch (e) {
  25. print(e);
  26. }
  27. }
  28. static checkToken() async {
  29. SharedPreferences prefs = await SharedPreferences.getInstance();
  30. await prefs.setString('token',
  31. 'qwedd123412erwedwe2'); //存储token,这是正常的请求接口的操作,我们没有请求接口,造假数据进行测试
  32. return prefs.getString('token'); //由于没有请求数据,我们造假数据
  33. }
  34. }

补充一下flutter自带的网络请求

  1. // 获取请求的状态码
  2. // response.statusCode 比如200(成功)404(找不到)403(禁止访问)502(服务器错误)等等
  3. // 官方提供的http请求方式(官方提供的方法太笨重,我们使用第三方的插件进行http请求,不推荐使用)
  4. // 1.引入io
  5. // 2.建立client
  6. // var httpClient = new HttpClient();
  7. // // 3.构造URI
  8. // var uri = new Uri.http('example.com', '/app', {'name': '名字'});
  9. // // 4.发起请求
  10. // var req = await httpClient.getUrl(uri);
  11. // // 5.关闭请求等待
  12. // var res = await req.close();

五、底部TabBar的组件

实现过程:使用Scaffold脚手架构建body和底部导航bottomNavigationBar,通过currentIndex确认点击的序号,通过onTap进行动态切换

  1. import 'package:flutter/material.dart';
  2. import 'package:newtoutiao/news/news.dart';
  3. import 'package:newtoutiao/question/question.dart';
  4. import 'package:newtoutiao/user/user.dart';
  5. import 'package:newtoutiao/video/video.dart';
  6. class Home extends StatefulWidget {
  7. @override
  8. _HomeState createState() => _HomeState();
  9. }
  10. class _HomeState extends State<Home> {
  11. // 创建一个数组
  12. int _index = 0;
  13. List _bodys = [News(), Question(), Video(), User()];
  14. @override
  15. Widget build(BuildContext context) {
  16. return Scaffold(
  17. body: _bodys[_index],
  18. // 底部导航bottomNavigationBar
  19. bottomNavigationBar: BottomNavigationBar(
  20. items: [
  21. BottomNavigationBarItem(
  22. icon: Icon(Icons.home),
  23. label: '首页',
  24. ),
  25. BottomNavigationBarItem(
  26. icon: Icon(Icons.question_answer),
  27. label: '问答',
  28. ),
  29. BottomNavigationBarItem(
  30. icon: Icon(Icons.video_label),
  31. label: '视频',
  32. ),
  33. BottomNavigationBarItem(
  34. icon: Icon(Icons.account_circle),
  35. label: '我的',
  36. ),
  37. ],
  38. type: BottomNavigationBarType.fixed, //使底部tab自适应
  39. currentIndex: _index, //确认当期点击的是哪个tab
  40. // 底部tab的点击事件
  41. onTap: (value) => {
  42. print(value),
  43. setState(
  44. () => {_index = value},
  45. ),
  46. },
  47. ),
  48. );
  49. }
  50. }

六、路由的跳转和返回

1、未在main.dart中定义的路由的跳转方式,说白了就是覆盖将需要跳转的路由放到最上面

Navigator.push(context,MaterialPageRoute(builder: (context) => NewsDetails(widget.id),),),

路由的返回,就是将最上面的路由删除拿掉

Navigator.pop(context),

2、在main.dart中定义的路由的跳转

Navigator.pushNamed(context, '/search')},

返回和上面一样

七、数据序列化(数据很多,不方便根据数据类型一一处理的时候,使用数据序列化,事半功倍)

1、定义一个class类,将返回的数据都在这个类里面进行声明,以下数据都是接口返回的字段

  1. class Artical {
  2. String artId;
  3. String title;
  4. int autId;
  5. String autName;
  6. int commCount;
  7. int isTop;
  8. int imgType;
  9. String pubdate;
  10. List images;
  11. Artical.fromJson(json) {
  12. artId = json['art_id'];
  13. title = json['title'];
  14. autId = json['aru_id'];
  15. autName = json['aru_name'];
  16. commCount = json['comm_count'];
  17. isTop = json['is_top'];
  18. imgType = json['img_type'];
  19. pubdate = json['pubdate'];
  20. images = json['images'];
  21. }
  22. }

2、在页面中引用 

3、定义变量,并格式化数据,然后在dom里就可以直接使用了

  1. List<Artical> _list = [];
  2. _getData([type]) async {
  3. var data = await PubMOdule.httpRequestApi(
  4. 'post', '/getArticals', {'id': widget.id, 'page': page});
  5. List jsonlist = data.data['data']['results']; //接口返回的数据
  6. List<Artical> listData =
  7. jsonlist.map((value) => Artical.fromJson(value)).toList(); //将数据遍历格式化
  8. if (type == 1) {
  9. setState(() {
  10. _list.addAll(listData); //如果向实例里添加,需要在声明的变量前加上实例名称
  11. });
  12. } else {
  13. setState(() {
  14. _list = listData;
  15. });
  16. }
  17. }
  1. @override
  2. Widget build(BuildContext context) {
  3. // RefreshIndicator下拉刷新
  4. return RefreshIndicator(
  5. onRefresh: _refresh,
  6. child: Padding(
  7. padding: EdgeInsets.all(15.0),
  8. child: ListView.builder(
  9. itemCount: _list.length,
  10. itemBuilder: (context, index) {
  11. return GestureDetector(
  12. onTap: () {
  13. Navigator.push(
  14. context,
  15. MaterialPageRoute(
  16. builder: (context) => NewsDetails(_list[index].artId)));
  17. },
  18. child: NewsItem(_list[index]), //通过组件传值传入无状态组件内
  19. );
  20. },
  21. // controller上拉加载
  22. controller: _controller,
  23. ),
  24. ),
  25. );
  26. }
  27. }

4、在无状态组件内接收,然后使用

  1. class NewsItem extends StatelessWidget {
  2. final Artical artical; //在这里接收
  3. NewsItem(this.artical);
  4. @override
  5. Widget build(BuildContext context) {
  6. return Column(
  7. crossAxisAlignment: CrossAxisAlignment.start,
  8. children: <Widget>[
  9. artical.imgType == 1
  10. ? Row(
  11. crossAxisAlignment: CrossAxisAlignment.start,
  12. children: <Widget>[
  13. Expanded(
  14. child: Text(
  15. artical.title, //正常使用即可
  16. style: TextStyle(color: Colors.black, fontSize: 18.0),
  17. ),
  18. ),

八、下拉刷新组件(RefreshIndicator)和上拉加载

  1. @override
  2. Widget build(BuildContext context) {
  3. // RefreshIndicator下拉刷新
  4. return RefreshIndicator(
  5. onRefresh: _refresh, //下拉刷新函数
  6. child: Padding(
  7. padding: EdgeInsets.all(15.0),
  8. child: ListView.builder(
  9. itemCount: _list.length, //页面上tabBar的数量
  10. itemBuilder: (context, index) {
  11. return GestureDetector(
  12. onTap: () {
  13. Navigator.push(
  14. context,
  15. MaterialPageRoute(
  16. builder: (context) => NewsDetails(_list[index].artId)));
  17. },
  18. child: NewsItem(_list[index]),
  19. );
  20. },
  21. // controller上拉加载
  22. controller: _controller,
  23. ),
  24. ),
  25. );
  26. }
  27. //上拉加载
  28. ScrollController _controller = ScrollController(); // 上拉加载更多
  29. //在初始化的生命周期内创建监听
  30. @override
  31. void initState() {
  32. super.initState();
  33. _getData();
  34. // 上拉加载更多的监听
  35. _controller.addListener(() {
  36. var maxScroll = _controller.position.maxScrollExtent;//上拉的距离
  37. var pixels = _controller.position.pixels; //触发刷新的距离
  38. if (maxScroll == pixels) {
  39. //s刷新了
  40. _getData(1);
  41. }
  42. });
  43. }
  44. //下拉刷新 定义一个函数,重新获取数据即可
  45. // 下拉刷新
  46. Future _refresh() async {
  47. //走接口
  48. _getData();
  49. // setState(() {
  50. // });
  51. }

九、时间格式化,比如:一小时之前,刚刚等等,这里我们借助第三方插件timeago

1、引入timeago插件

2、直接使用

  1. import 'package:timeago/timeago.dart' as timeago; //处理时间,多久之前
  2. TextSpan(
  3. text: timeago.format(DateTime.parse(artical.pubdate)), //直接使用即可
  4. style: TextStyle(
  5. olor: Colors.grey,
  6. ),
  7. )

3、默认是英文的,如果想调为中文,需要手动改插件的文件,按住Ctrl,鼠标点击format,跳转进一个文件,找到EnMessages(),再次Ctrl+鼠标左键,又进入一个文件,如下,然后你将英文改为中文即可

  1. import 'package:timeago/src/messages/lookupmessages.dart';
  2. /// English Messages
  3. class EnMessages implements LookupMessages {
  4. @override
  5. String prefixAgo() => '';
  6. @override
  7. String prefixFromNow() => '';
  8. @override
  9. String suffixAgo() => 'ago';
  10. @override
  11. String suffixFromNow() => 'from now';
  12. @override
  13. String lessThanOneMinute(int seconds) => 'a moment';
  14. @override
  15. String aboutAMinute(int minutes) => 'a minute';
  16. @override
  17. String minutes(int minutes) => '$minutes minutes';
  18. @override
  19. String aboutAnHour(int minutes) => 'about an hour';
  20. @override
  21. String hours(int hours) => '$hours hours';
  22. @override
  23. String aDay(int hours) => 'a day';
  24. @override
  25. String days(int days) => '$days days';
  26. @override
  27. String aboutAMonth(int days) => 'about a month';
  28. @override
  29. String months(int months) => '$months months';
  30. @override
  31. String aboutAYear(int year) => 'about a year';
  32. @override
  33. String years(int years) => '$years years';
  34. @override
  35. String wordSeparator() => ' ';
  36. }
  37. /// English short Messages
  38. class EnShortMessages implements LookupMessages {
  39. @override
  40. String prefixAgo() => '';
  41. @override
  42. String prefixFromNow() => '';
  43. @override
  44. String suffixAgo() => '';
  45. @override
  46. String suffixFromNow() => '';
  47. @override
  48. String lessThanOneMinute(int seconds) => 'now';
  49. @override
  50. String aboutAMinute(int minutes) => '1 min';
  51. @override
  52. String minutes(int minutes) => '$minutes min';
  53. @override
  54. String aboutAnHour(int minutes) => '~1 h';
  55. @override
  56. String hours(int hours) => '$hours h';
  57. @override
  58. String aDay(int hours) => '~1 d';
  59. @override
  60. String days(int days) => '$days d';
  61. @override
  62. String aboutAMonth(int days) => '~1 mo';
  63. @override
  64. String months(int months) => '$months mo';
  65. @override
  66. String aboutAYear(int year) => '~1 yr';
  67. @override
  68. String years(int years) => '$years yr';
  69. @override
  70. String wordSeparator() => ' ';
  71. }

十、边栏组件的使用(Drawer)

1、使用 ListView列表排列

2、DrawerHeader 边栏的标题或者名字之类的

3、ListTile 边栏子类的标题

4、Wrap 横向排列,Wrap同样可以横向排列,一行放不下可以自动换行,这是和row的区别

5、Chip 小徽标

  1. import 'package:flutter/material.dart';
  2. class DrawerList extends StatelessWidget {
  3. @override
  4. Widget build(BuildContext context) {
  5. return Drawer(
  6. elevation: 0.0,
  7. child: ListView(
  8. children: [
  9. DrawerHeader(
  10. decoration: BoxDecoration(color: Colors.blue),
  11. child: Center(
  12. child: SizedBox(
  13. width: 60.0,
  14. height: 60.0,
  15. child: CircleAvatar(
  16. child: Text('张三'),
  17. ),
  18. ),
  19. ),
  20. ),
  21. ListTile(
  22. title: Text(
  23. '我的频道',
  24. style: TextStyle(
  25. fontSize: 16.0,
  26. fontWeight: FontWeight.normal,
  27. ),
  28. ),
  29. trailing: Container(
  30. padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 1.0),
  31. width: 50.0,
  32. height: 25.0,
  33. decoration: BoxDecoration(
  34. border: Border.all(
  35. color: Colors.red,
  36. ),
  37. borderRadius: BorderRadius.circular(20.0),
  38. ),
  39. child: Text(
  40. '编辑',
  41. style: TextStyle(color: Colors.red),
  42. ),
  43. ),
  44. ),
  45. Padding(
  46. padding: EdgeInsets.symmetric(horizontal: 15.0),
  47. // Wrap同样可以横向排列,一行放不下可以自动换行,这是和row的区别
  48. child: Wrap(
  49. spacing: 15.0, //每一个小Chip的间隔
  50. children: [
  51. Chip(
  52. label: Text('html'),
  53. onDeleted: () => {print('删除')},
  54. ),
  55. Chip(
  56. label: Text('css'),
  57. onDeleted: null,
  58. ),
  59. Chip(
  60. label: Text('app'),
  61. onDeleted: () => {print('删除')},
  62. ),
  63. Chip(
  64. label: Text('js'),
  65. onDeleted: null,
  66. ),
  67. Chip(
  68. label: Text('vue'),
  69. onDeleted: null,
  70. ),
  71. ],
  72. ),
  73. ),
  74. ListTile(
  75. title: Text(
  76. '频道推荐',
  77. style: TextStyle(
  78. fontSize: 16.0,
  79. fontWeight: FontWeight.normal,
  80. ),
  81. ),
  82. ),
  83. Padding(
  84. padding: EdgeInsets.symmetric(horizontal: 15.0),
  85. // Wrap同样可以横向排列,一行放不下可以自动换行,这是和row的区别
  86. child: Wrap(
  87. spacing: 15.0, //每一个小Chip的间隔
  88. children: [
  89. FilterChip(
  90. avatar: CircleAvatar(
  91. backgroundColor: Colors.grey,
  92. child: Text(
  93. '+',
  94. style: TextStyle(color: Colors.white, fontSize: 16.0),
  95. ),
  96. ),
  97. label: Text('java'),
  98. onSelected: (value) => {print('添加')},
  99. ),
  100. ],
  101. ),
  102. ),
  103. ],
  104. ),
  105. );
  106. }
  107. }

十一、子组件调用父组件的方法

1、首先先将父组件的方法传递给子组件

  1. @override
  2. Widget build(BuildContext context) {
  3. // 如果tabBarList是空不加载tab页面,优化设计
  4. return tabBarList.length == 0
  5. ? SizedBox()
  6. : DefaultTabController(
  7. length: tabBarList.length,
  8. child: Scaffold(
  9. appBar: AppBar(
  10. title: SearchBtn(),
  11. elevation: 0.0,
  12. // PreferredSize一般用在顶部tabBar或者底部tabBar,进行包裹,preferredSize是距离顶部的距离或者距离底部的距离
  13. bottom: PreferredSize(
  14. preferredSize: Size.fromHeight(50.0),
  15. child: TabBarBtn(tabBarList),
  16. )),
  17. body: TabBarBody(tabBarList),
  18. drawer: DrawerList1(_getChannels), //子组件调用父组件的方法
  19. ),
  20. );
  21. }

2、子组件接收VoidCallback

  1. class DrawerList1 extends StatefulWidget {
  2. final VoidCallback refresh; //接收父组件传递过来的方法
  3. DrawerList1(this.refresh);//接收父组件传递过来的方法
  4. @override
  5. _DrawerList1State createState() => _DrawerList1State();
  6. }

3、执行时间,在页面销毁的时候

  1. // 页面关闭的时候的回调
  2. @override
  3. void dispose() {
  4. super.dispose();
  5. widget.refresh();
  6. }

十二、sliver的使用,页面上滑,将作者和相关信息固定在顶部不消失,实现代码如下,讲解一下

1、主要是创建_SliverAppBarDelegate,依赖SliverPersistentHeaderDelegate

2、将页面内传递过来的child接收并且返回

3、minExtent和maxExtent固定的高

  1. import 'package:flutter/material.dart';
  2. import 'package:newtoutiao/news/comment.dart';
  3. import 'package:newtoutiao/news/share_sheet.dart';
  4. class NewsDetails extends StatefulWidget {
  5. final String id;
  6. NewsDetails(this.id);
  7. @override
  8. _NewsDetailsState createState() => _NewsDetailsState();
  9. }
  10. class _NewsDetailsState extends State<NewsDetails> {
  11. @override
  12. Widget build(BuildContext context) {
  13. // CircularProgressIndicator()//正在加载,转圈圈
  14. // 使用slivers组件,实现的功能是当内容向上滚动的时候,可以将题头放入TabBar上
  15. return Scaffold(
  16. body: CustomScrollView(
  17. slivers: [
  18. SliverAppBar(
  19. pinned: false,
  20. elevation: 0.0,
  21. expandedHeight: 80.0,
  22. title: Text('海上生明月,天涯共此时,劝君更尽一杯酒'),
  23. actions: [
  24. IconButton(
  25. icon: Icon(Icons.more_horiz),
  26. onPressed: () => {
  27. print('点击了举报'),
  28. // 点击打开一个底部弹窗
  29. showModalBottomSheet(
  30. context: context,
  31. builder: (BuildContext context) {
  32. print(context);
  33. return ShareSheet();
  34. })
  35. },
  36. ),
  37. ],
  38. ),
  39. SliverList(
  40. delegate: SliverChildListDelegate(
  41. [
  42. Padding(
  43. padding: EdgeInsets.all(15.0),
  44. child: Text(
  45. '海上生明月,天涯共此时,劝君更尽一杯酒',
  46. style: TextStyle(
  47. color: Colors.blue,
  48. fontSize: 16.0,
  49. fontWeight: FontWeight.w600),
  50. ),
  51. ),
  52. ],
  53. ),
  54. ),
  55. //作者
  56. SliverPersistentHeader(
  57. pinned: true, //讲设置的栏固定
  58. delegate: _SliverAppBarDelegate(
  59. child: Container(
  60. color: Colors.blue,
  61. ),
  62. ),
  63. ),
  64. // 内容 dart内可以使用三个引号去除文字的自有格式
  65. SliverList(
  66. delegate: SliverChildListDelegate(
  67. [
  68. Padding(
  69. padding: EdgeInsets.all(15.0),
  70. child: Text(
  71. '''新京报快讯 据滴滴出行官博消息,我们关注到网上关于“长沙22岁女生乘网约车后失联”事件后立即进行核实。乘客于1月22日凌晨1点51分通过滴滴叫车,起点是伏苓冲路某园区东门,凌晨2点乘客上车,司机开始行程,于凌晨2点19分到达目的地猴子石大桥某公交站。''',
  72. style: TextStyle(
  73. color: Colors.black,
  74. fontSize: 14.0,
  75. fontWeight: FontWeight.normal),
  76. ),
  77. ),
  78. Padding(
  79. padding: EdgeInsets.all(15.0),
  80. child: Column(
  81. crossAxisAlignment: CrossAxisAlignment.start,
  82. children: [
  83. Text(
  84. '猜你喜欢',
  85. style: TextStyle(
  86. color: Colors.black,
  87. fontSize: 16.0,
  88. fontWeight: FontWeight.w600,
  89. ),
  90. ),
  91. SizedBox(
  92. height: 10.0,
  93. ),
  94. Wrap(
  95. children: [
  96. Container(
  97. // MediaQuery.of(context).size.width / 2 - 20 计算整个屏幕一般的宽度
  98. // color: Colors.red,
  99. margin: EdgeInsets.only(bottom: 10.0),
  100. width: MediaQuery.of(context).size.width / 2 - 20,
  101. child: Text(
  102. '月薪过万的职业,永远不用加班的职业永远不用加班的职业',
  103. maxLines: 1, //最多只有一行
  104. overflow: TextOverflow.ellipsis, //超过使用省略号显示
  105. ),
  106. ),
  107. Container(
  108. // color: Colors.pink,
  109. margin: EdgeInsets.only(bottom: 10.0),
  110. width: MediaQuery.of(context).size.width / 2 - 20,
  111. child: Text(
  112. '永远不用加班的职业,躺着就能挣钱的职业,躺着就能挣钱的职业',
  113. maxLines: 1, //最多只有一行
  114. overflow: TextOverflow.ellipsis, //超过使用省略号显示
  115. ),
  116. ),
  117. Container(
  118. margin: EdgeInsets.only(bottom: 10.0),
  119. width: MediaQuery.of(context).size.width / 2 - 20,
  120. child: Text(
  121. '躺着就能挣钱的职业',
  122. maxLines: 1, //最多只有一行
  123. overflow: TextOverflow.ellipsis, //超过使用省略号显示
  124. ),
  125. ),
  126. Container(
  127. margin: EdgeInsets.only(bottom: 10.0),
  128. width: MediaQuery.of(context).size.width / 2 - 20,
  129. child: Text(
  130. '如何教育下一代',
  131. maxLines: 1, //最多只有一行
  132. overflow: TextOverflow.ellipsis, //超过使用省略号显示
  133. ),
  134. ),
  135. Container(
  136. margin: EdgeInsets.only(bottom: 10.0),
  137. width: MediaQuery.of(context).size.width / 2 - 20,
  138. child: Text(
  139. '二胎之后我们何去何从',
  140. maxLines: 1, //最多只有一行
  141. overflow: TextOverflow.ellipsis, //超过使用省略号显示
  142. ),
  143. ),
  144. Container(
  145. margin: EdgeInsets.only(bottom: 10.0),
  146. width: MediaQuery.of(context).size.width / 2 - 20,
  147. child: Text(
  148. '两个孩子刚刚好',
  149. maxLines: 1, //最多只有一行
  150. overflow: TextOverflow.ellipsis, //超过使用省略号显示
  151. ),
  152. ),
  153. ],
  154. )
  155. ],
  156. ),
  157. ),
  158. Comment(),
  159. SizedBox(
  160. height: 35.0,
  161. ),
  162. Row(
  163. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  164. children: [
  165. GestureDetector(
  166. onTap: () => {
  167. print('喜欢'),
  168. },
  169. child: Container(
  170. padding: EdgeInsets.symmetric(
  171. horizontal: 20.0, vertical: 5.0),
  172. decoration: BoxDecoration(
  173. border: Border.all(
  174. width: 1.0,
  175. color: Colors.red,
  176. ),
  177. borderRadius: BorderRadius.circular(25.0),
  178. ),
  179. child: Row(
  180. children: [
  181. Icon(
  182. Icons.thumb_up,
  183. color: Colors.red,
  184. ),
  185. SizedBox(
  186. width: 5.0,
  187. ),
  188. Text(
  189. '喜欢',
  190. style: TextStyle(color: Colors.red),
  191. ),
  192. ],
  193. ),
  194. ),
  195. ),
  196. GestureDetector(
  197. onTap: () => {
  198. print('不喜欢'),
  199. },
  200. child: Container(
  201. padding: EdgeInsets.symmetric(
  202. horizontal: 15.0, vertical: 5.0),
  203. decoration: BoxDecoration(
  204. border: Border.all(width: 1.0),
  205. borderRadius: BorderRadius.circular(25.0)),
  206. child: Row(
  207. children: [
  208. Icon(Icons.delete),
  209. Text('不喜欢'),
  210. ],
  211. ),
  212. ),
  213. ),
  214. ],
  215. ),
  216. ],
  217. ),
  218. ),
  219. ],
  220. ),
  221. );
  222. }
  223. }
  224. //实现功能,当文字向上滚动,把标题和作者映射到tabBar上
  225. class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  226. _SliverAppBarDelegate({this.child}); //带{}传值是带有参数的
  227. final Widget child;
  228. @override
  229. double get minExtent => 80.0; //此组件覆盖的的最小高度,当上去的时候是80
  230. @override
  231. double get maxExtent => 80.0; //此组件覆盖的的最大高度 当在自己的位置的时候是80
  232. @override
  233. Widget build(
  234. BuildContext context, double shrinkOffset, bool overlapsContent) {
  235. return SizedBox(
  236. child: this.child,
  237. );
  238. }
  239. @override
  240. bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
  241. return true;
  242. }
  243. }

十三、flutter中的弹框

  1. // 点击打开一个底部弹窗
  2. showModalBottomSheet(
  3. context: context,
  4. builder: (BuildContext context) {
  5. return ShareSheet();
  6. },
  7. ),
  8. //关闭弹窗 是一个路由
  9. Navigator.pop(context),

十四、flutter中的输入框,TextField,页面中的Expanded是自适应宽度

  1. Expanded(
  2. child: Container(
  3. height: 30.0,
  4. decoration: BoxDecoration(
  5. border: Border.all(
  6. color: Colors.black12,
  7. ),
  8. borderRadius: BorderRadius.circular(30.0),
  9. ),
  10. child: TextField(
  11. decoration: InputDecoration(
  12. hintText: '写评论',
  13. hintStyle: TextStyle(
  14. fontSize: 14.0,
  15. color: Colors.black54,
  16. ),
  17. contentPadding:
  18. EdgeInsets.symmetric(horizontal: 15.0, vertical: 8.5),
  19. enabledBorder: InputBorder.none,
  20. focusedBorder: InputBorder.none,
  21. ),
  22. onSubmitted: (value) => {
  23. print(value),
  24. },
  25. onChanged: (value) => {
  26. print(value),
  27. },
  28. ),
  29. ),
  30. ),

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/231847
推荐阅读
相关标签
  

闽ICP备14008679号