flutter项目爬坑记录

目录

一、flutter内的布局

二、flutter内的倒计时 periodic

三、flutter的生命周期

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

五、底部TabBar的组件

六、路由的跳转和返回

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

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

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

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

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

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

十三、flutter中的弹框

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


一、flutter内的布局

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

二、flutter内的倒计时 periodic

//开启一个定时器
var _timer;    
_timer = Timer.periodic(
      Duration(seconds: 1),
      (timer) {
        print('表示1秒执行一次')
      },
    );

//关闭一个定时器
_timer.cancel();

三、flutter的生命周期

  // flutter的生命周期
  // 1、初始化状态,可以获取数据等等操作
  @override
  void initState() {
    super.initState();
  }

  // 2、构建dom的状态
  // @override
  // Widget build(){}


  // 3、页面销毁的状态(离开页面将要销毁的时候,相当于vue的beforedetroy)
  @override
  void dispose() {
    super.dispose();
  }

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

//引入dio第三方库
import 'package:dio/dio.dart';
import 'package:newtoutiao/moudle/config.dart';
import 'package:shared_preferences/shared_preferences.dart';

Dio dio = new Dio();  //创建实例

class PubMOdule {
  static httpRequestApi(method, url, [data]) async {
    // SharedPreferences第三方的存取和获取token的插件,prefs里有get获取token和set存储token
    SharedPreferences prefs = await SharedPreferences.getInstance();
    try {
      // 设置请求头
      dio.options.headers['Autoken'] =
          prefs.getString('token') ?? ''; //获取token,如果没有token就默认为空
      Response response;
      switch (method) {
        case "get":
          response = await dio.get(Config.baseUrl + url);
          break;
        case "post":
          response = await dio.post(Config.baseUrl + url, data: data);
          break;
      }
      return response;
    } catch (e) {
      print(e);
    }
  }

  static checkToken() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString('token',
        'qwedd123412erwedwe2'); //存储token,这是正常的请求接口的操作,我们没有请求接口,造假数据进行测试
    return prefs.getString('token'); //由于没有请求数据,我们造假数据
  }
}

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

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

五、底部TabBar的组件

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

import 'package:flutter/material.dart';
import 'package:newtoutiao/news/news.dart';
import 'package:newtoutiao/question/question.dart';
import 'package:newtoutiao/user/user.dart';
import 'package:newtoutiao/video/video.dart';

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  // 创建一个数组
  int _index = 0;
  List _bodys = [News(), Question(), Video(), User()];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _bodys[_index],
      // 底部导航bottomNavigationBar
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: '首页',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.question_answer),
            label: '问答',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.video_label),
            label: '视频',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.account_circle),
            label: '我的',
          ),
        ],
        type: BottomNavigationBarType.fixed, //使底部tab自适应
        currentIndex: _index, //确认当期点击的是哪个tab
        // 底部tab的点击事件
        onTap: (value) => {
          print(value),
          setState(
            () => {_index = value},
          ),
        },
      ),
    );
  }
}

六、路由的跳转和返回

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

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

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

Navigator.pop(context),

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

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

返回和上面一样

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

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

class Artical {
  String artId;
  String title;
  int autId;
  String autName;
  int commCount;
  int isTop;
  int imgType;
  String pubdate;
  List images;

  Artical.fromJson(json) {
    artId = json['art_id'];
    title = json['title'];
    autId = json['aru_id'];
    autName = json['aru_name'];
    commCount = json['comm_count'];
    isTop = json['is_top'];
    imgType = json['img_type'];
    pubdate = json['pubdate'];
    images = json['images'];
  }
}

2、在页面中引用 

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

List<Artical> _list = [];

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

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

class NewsItem extends StatelessWidget {
  final Artical artical;  //在这里接收
  NewsItem(this.artical);

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        artical.imgType == 1
            ? Row(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Expanded(
                    child: Text(
                      artical.title,  //正常使用即可
                      style: TextStyle(color: Colors.black, fontSize: 18.0),
                    ),
                  ),

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

  @override
  Widget build(BuildContext context) {
    // RefreshIndicator下拉刷新
    return RefreshIndicator(
      onRefresh: _refresh,  //下拉刷新函数
      child: Padding(
        padding: EdgeInsets.all(15.0),
        child: ListView.builder(
          itemCount: _list.length,  //页面上tabBar的数量
          itemBuilder: (context, index) {
            return GestureDetector(
              onTap: () {
                Navigator.push(
                    context,
                    MaterialPageRoute(
                        builder: (context) => NewsDetails(_list[index].artId)));
              },
              child: NewsItem(_list[index]),
            );
          },
          // controller上拉加载
          controller: _controller,
        ),
      ),
    );
  }

//上拉加载
ScrollController _controller = ScrollController(); // 上拉加载更多

//在初始化的生命周期内创建监听
  @override
  void initState() {
    super.initState();
    _getData();

// 上拉加载更多的监听
    _controller.addListener(() {
      var maxScroll = _controller.position.maxScrollExtent;//上拉的距离
      var pixels = _controller.position.pixels;  //触发刷新的距离
      if (maxScroll == pixels) {
        //s刷新了
        _getData(1);
      }
    });
  }

//下拉刷新  定义一个函数,重新获取数据即可
// 下拉刷新
  Future _refresh() async {
    //走接口
    _getData();
    // setState(() {

    // });
  } 

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

1、引入timeago插件

2、直接使用

import 'package:timeago/timeago.dart' as timeago; //处理时间,多久之前

TextSpan(
          text: timeago.format(DateTime.parse(artical.pubdate)), //直接使用即可
          style: TextStyle(
           olor: Colors.grey,
           ),
          )

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

import 'package:timeago/src/messages/lookupmessages.dart';

/// English Messages
class EnMessages implements LookupMessages {
  @override
  String prefixAgo() => '';
  @override
  String prefixFromNow() => '';
  @override
  String suffixAgo() => 'ago';
  @override
  String suffixFromNow() => 'from now';
  @override
  String lessThanOneMinute(int seconds) => 'a moment';
  @override
  String aboutAMinute(int minutes) => 'a minute';
  @override
  String minutes(int minutes) => '$minutes minutes';
  @override
  String aboutAnHour(int minutes) => 'about an hour';
  @override
  String hours(int hours) => '$hours hours';
  @override
  String aDay(int hours) => 'a day';
  @override
  String days(int days) => '$days days';
  @override
  String aboutAMonth(int days) => 'about a month';
  @override
  String months(int months) => '$months months';
  @override
  String aboutAYear(int year) => 'about a year';
  @override
  String years(int years) => '$years years';
  @override
  String wordSeparator() => ' ';
}

/// English short Messages
class EnShortMessages implements LookupMessages {
  @override
  String prefixAgo() => '';
  @override
  String prefixFromNow() => '';
  @override
  String suffixAgo() => '';
  @override
  String suffixFromNow() => '';
  @override
  String lessThanOneMinute(int seconds) => 'now';
  @override
  String aboutAMinute(int minutes) => '1 min';
  @override
  String minutes(int minutes) => '$minutes min';
  @override
  String aboutAnHour(int minutes) => '~1 h';
  @override
  String hours(int hours) => '$hours h';
  @override
  String aDay(int hours) => '~1 d';
  @override
  String days(int days) => '$days d';
  @override
  String aboutAMonth(int days) => '~1 mo';
  @override
  String months(int months) => '$months mo';
  @override
  String aboutAYear(int year) => '~1 yr';
  @override
  String years(int years) => '$years yr';
  @override
  String wordSeparator() => ' ';
}

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

1、使用 ListView列表排列

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

3、ListTile 边栏子类的标题

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

5、Chip 小徽标

import 'package:flutter/material.dart';

class DrawerList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Drawer(
      elevation: 0.0,
      child: ListView(
        children: [
          DrawerHeader(
            decoration: BoxDecoration(color: Colors.blue),
            child: Center(
              child: SizedBox(
                width: 60.0,
                height: 60.0,
                child: CircleAvatar(
                  child: Text('张三'),
                ),
              ),
            ),
          ),
          ListTile(
            title: Text(
              '我的频道',
              style: TextStyle(
                fontSize: 16.0,
                fontWeight: FontWeight.normal,
              ),
            ),
            trailing: Container(
              padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 1.0),
              width: 50.0,
              height: 25.0,
              decoration: BoxDecoration(
                border: Border.all(
                  color: Colors.red,
                ),
                borderRadius: BorderRadius.circular(20.0),
              ),
              child: Text(
                '编辑',
                style: TextStyle(color: Colors.red),
              ),
            ),
          ),
          Padding(
            padding: EdgeInsets.symmetric(horizontal: 15.0),
            // Wrap同样可以横向排列,一行放不下可以自动换行,这是和row的区别
            child: Wrap(
              spacing: 15.0, //每一个小Chip的间隔
              children: [
                Chip(
                  label: Text('html'),
                  onDeleted: () => {print('删除')},
                ),
                Chip(
                  label: Text('css'),
                  onDeleted: null,
                ),
                Chip(
                  label: Text('app'),
                  onDeleted: () => {print('删除')},
                ),
                Chip(
                  label: Text('js'),
                  onDeleted: null,
                ),
                Chip(
                  label: Text('vue'),
                  onDeleted: null,
                ),
              ],
            ),
          ),
          ListTile(
            title: Text(
              '频道推荐',
              style: TextStyle(
                fontSize: 16.0,
                fontWeight: FontWeight.normal,
              ),
            ),
          ),
          Padding(
            padding: EdgeInsets.symmetric(horizontal: 15.0),
            // Wrap同样可以横向排列,一行放不下可以自动换行,这是和row的区别
            child: Wrap(
              spacing: 15.0, //每一个小Chip的间隔
              children: [
                FilterChip(
                  avatar: CircleAvatar(
                    backgroundColor: Colors.grey,
                    child: Text(
                      '+',
                      style: TextStyle(color: Colors.white, fontSize: 16.0),
                    ),
                  ),
                  label: Text('java'),
                  onSelected: (value) => {print('添加')},
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

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

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

  @override
  Widget build(BuildContext context) {
    // 如果tabBarList是空不加载tab页面,优化设计
    return tabBarList.length == 0
        ? SizedBox()
        : DefaultTabController(
            length: tabBarList.length,
            child: Scaffold(
              appBar: AppBar(
                  title: SearchBtn(),
                  elevation: 0.0,
                  // PreferredSize一般用在顶部tabBar或者底部tabBar,进行包裹,preferredSize是距离顶部的距离或者距离底部的距离
                  bottom: PreferredSize(
                    preferredSize: Size.fromHeight(50.0),
                    child: TabBarBtn(tabBarList),
                  )),
              body: TabBarBody(tabBarList),
              drawer: DrawerList1(_getChannels), //子组件调用父组件的方法
            ),
          );
  }

2、子组件接收VoidCallback

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

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


// 页面关闭的时候的回调
  @override
  void dispose() {
    super.dispose();
    widget.refresh();
  }

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

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

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

3、minExtent和maxExtent固定的高

import 'package:flutter/material.dart';
import 'package:newtoutiao/news/comment.dart';
import 'package:newtoutiao/news/share_sheet.dart';

class NewsDetails extends StatefulWidget {
  final String id;
  NewsDetails(this.id);
  @override
  _NewsDetailsState createState() => _NewsDetailsState();
}

class _NewsDetailsState extends State<NewsDetails> {
  @override
  Widget build(BuildContext context) {
    // CircularProgressIndicator()//正在加载,转圈圈
    // 使用slivers组件,实现的功能是当内容向上滚动的时候,可以将题头放入TabBar上
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverAppBar(
            pinned: false,
            elevation: 0.0,
            expandedHeight: 80.0,
            title: Text('海上生明月,天涯共此时,劝君更尽一杯酒'),
            actions: [
              IconButton(
                icon: Icon(Icons.more_horiz),
                onPressed: () => {
                  print('点击了举报'),
                  // 点击打开一个底部弹窗
                  showModalBottomSheet(
                      context: context,
                      builder: (BuildContext context) {
                        print(context);
                        return ShareSheet();
                      })
                },
              ),
            ],
          ),
          SliverList(
            delegate: SliverChildListDelegate(
              [
                Padding(
                  padding: EdgeInsets.all(15.0),
                  child: Text(
                    '海上生明月,天涯共此时,劝君更尽一杯酒',
                    style: TextStyle(
                        color: Colors.blue,
                        fontSize: 16.0,
                        fontWeight: FontWeight.w600),
                  ),
                ),
              ],
            ),
          ),
          //作者
          SliverPersistentHeader(
            pinned: true, //讲设置的栏固定
            delegate: _SliverAppBarDelegate(
              child: Container(
                color: Colors.blue,
              ),
            ),
          ),
          // 内容  dart内可以使用三个引号去除文字的自有格式
          SliverList(
            delegate: SliverChildListDelegate(
              [
                Padding(
                  padding: EdgeInsets.all(15.0),
                  child: Text(
                    '''新京报快讯 据滴滴出行官博消息,我们关注到网上关于“长沙22岁女生乘网约车后失联”事件后立即进行核实。乘客于1月22日凌晨1点51分通过滴滴叫车,起点是伏苓冲路某园区东门,凌晨2点乘客上车,司机开始行程,于凌晨2点19分到达目的地猴子石大桥某公交站。''',
                    style: TextStyle(
                        color: Colors.black,
                        fontSize: 14.0,
                        fontWeight: FontWeight.normal),
                  ),
                ),
                Padding(
                  padding: EdgeInsets.all(15.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        '猜你喜欢',
                        style: TextStyle(
                          color: Colors.black,
                          fontSize: 16.0,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                      SizedBox(
                        height: 10.0,
                      ),
                      Wrap(
                        children: [
                          Container(
                            // MediaQuery.of(context).size.width / 2 - 20  计算整个屏幕一般的宽度
                            // color: Colors.red,
                            margin: EdgeInsets.only(bottom: 10.0),
                            width: MediaQuery.of(context).size.width / 2 - 20,
                            child: Text(
                              '月薪过万的职业,永远不用加班的职业永远不用加班的职业',
                              maxLines: 1, //最多只有一行
                              overflow: TextOverflow.ellipsis, //超过使用省略号显示
                            ),
                          ),
                          Container(
                            // color: Colors.pink,
                            margin: EdgeInsets.only(bottom: 10.0),
                            width: MediaQuery.of(context).size.width / 2 - 20,
                            child: Text(
                              '永远不用加班的职业,躺着就能挣钱的职业,躺着就能挣钱的职业',
                              maxLines: 1, //最多只有一行
                              overflow: TextOverflow.ellipsis, //超过使用省略号显示
                            ),
                          ),
                          Container(
                            margin: EdgeInsets.only(bottom: 10.0),
                            width: MediaQuery.of(context).size.width / 2 - 20,
                            child: Text(
                              '躺着就能挣钱的职业',
                              maxLines: 1, //最多只有一行
                              overflow: TextOverflow.ellipsis, //超过使用省略号显示
                            ),
                          ),
                          Container(
                            margin: EdgeInsets.only(bottom: 10.0),
                            width: MediaQuery.of(context).size.width / 2 - 20,
                            child: Text(
                              '如何教育下一代',
                              maxLines: 1, //最多只有一行
                              overflow: TextOverflow.ellipsis, //超过使用省略号显示
                            ),
                          ),
                          Container(
                            margin: EdgeInsets.only(bottom: 10.0),
                            width: MediaQuery.of(context).size.width / 2 - 20,
                            child: Text(
                              '二胎之后我们何去何从',
                              maxLines: 1, //最多只有一行
                              overflow: TextOverflow.ellipsis, //超过使用省略号显示
                            ),
                          ),
                          Container(
                            margin: EdgeInsets.only(bottom: 10.0),
                            width: MediaQuery.of(context).size.width / 2 - 20,
                            child: Text(
                              '两个孩子刚刚好',
                              maxLines: 1, //最多只有一行
                              overflow: TextOverflow.ellipsis, //超过使用省略号显示
                            ),
                          ),
                        ],
                      )
                    ],
                  ),
                ),
                Comment(),
                SizedBox(
                  height: 35.0,
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    GestureDetector(
                      onTap: () => {
                        print('喜欢'),
                      },
                      child: Container(
                        padding: EdgeInsets.symmetric(
                            horizontal: 20.0, vertical: 5.0),
                        decoration: BoxDecoration(
                          border: Border.all(
                            width: 1.0,
                            color: Colors.red,
                          ),
                          borderRadius: BorderRadius.circular(25.0),
                        ),
                        child: Row(
                          children: [
                            Icon(
                              Icons.thumb_up,
                              color: Colors.red,
                            ),
                            SizedBox(
                              width: 5.0,
                            ),
                            Text(
                              '喜欢',
                              style: TextStyle(color: Colors.red),
                            ),
                          ],
                        ),
                      ),
                    ),
                    GestureDetector(
                      onTap: () => {
                        print('不喜欢'),
                      },
                      child: Container(
                        padding: EdgeInsets.symmetric(
                            horizontal: 15.0, vertical: 5.0),
                        decoration: BoxDecoration(
                            border: Border.all(width: 1.0),
                            borderRadius: BorderRadius.circular(25.0)),
                        child: Row(
                          children: [
                            Icon(Icons.delete),
                            Text('不喜欢'),
                          ],
                        ),
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

//实现功能,当文字向上滚动,把标题和作者映射到tabBar上
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverAppBarDelegate({this.child}); //带{}传值是带有参数的
  final Widget child;

  @override
  double get minExtent => 80.0; //此组件覆盖的的最小高度,当上去的时候是80

  @override
  double get maxExtent => 80.0; //此组件覆盖的的最大高度 当在自己的位置的时候是80

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return SizedBox(
      child: this.child,
    );
  }

  @override
  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
    return true;
  }
}

十三、flutter中的弹框

// 点击打开一个底部弹窗
showModalBottomSheet(
    context: context,
    builder: (BuildContext context) {
        return ShareSheet();
    },
),

//关闭弹窗 是一个路由
Navigator.pop(context),

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

            Expanded(
                child: Container(
                  height: 30.0,
                  decoration: BoxDecoration(
                    border: Border.all(
                      color: Colors.black12,
                    ),
                    borderRadius: BorderRadius.circular(30.0),
                  ),
                  child: TextField(
                    decoration: InputDecoration(
                      hintText: '写评论',
                      hintStyle: TextStyle(
                        fontSize: 14.0,
                        color: Colors.black54,
                      ),
                      contentPadding:
                          EdgeInsets.symmetric(horizontal: 15.0, vertical: 8.5),
                      enabledBorder: InputBorder.none,
                      focusedBorder: InputBorder.none,
                    ),
                    onSubmitted: (value) => {
                      print(value),
                    },
                    onChanged: (value) => {
                      print(value),
                    },
                  ),
                ),
              ),

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码上登堂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值