flutter常用基础知识点

先记录这么点,还有很多技巧干活,只要学,会思考,每天都在进步
定义模型 其实现在有json转dart工具
class SearchModel {
  String keyword;
  final List<SearchItem> data;

  SearchModel({this.data});

  factory SearchModel.fromJson(Map<String, dynamic> json) {
    var dataJson = json['data'] as List;
    List<SearchItem> data =
    dataJson.map((item) => SearchItem.fromJson(item)).toList();
    return SearchModel(data: data);
  }
}

class SearchItem {
  final String word;
  final String type;
  final String price;
  final String star;
  final String zonename;
  final String districtname;
  final String url;

  SearchItem(
      {this.word,
        this.type,
        this.price,
        this.star,
        this.zonename,
        this.districtname,
        this.url});

  factory SearchItem.fromJson(Map<String, dynamic> json) {
    return SearchItem(
      word: json['word'],
      type: json['type'],
      price: json['price'],
      star: json['star'],
      zonename: json['zonename'],
      districtname: json['districtname'],
      url: json['url'],
    );
  }
}
接口请求
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:flutterapptrip/model/search_model.dart';

const SEARCH_URL = 'https://xxxxxx/search?keyword=';

///搜索接口
class SearchDao {
  static Future<SearchModel> fetch(String keyword) async {
    Response response = await Dio().get(SEARCH_URL + keyword);
    if (response.statusCode == 200) {
      //只有当输入的内容与服务端返回的内容一致时才渲染
      SearchModel model = SearchModel.fromJson(response.data);
      model.keyword = keyword;
      return model;
    } else {
      throw Exception('Failed to load search');
    }
  }
}
监听scroll,下拉刷新
  double appBarAlpha = 0;
  const APPBAR_SCROLL_OFFSET = 100;

  //滚动改变透明度
  _onScroll(offset) {
    double alpha = offset / APPBAR_SCROLL_OFFSET;
    if (alpha < 0) {
      alpha = 0;
    } else if (alpha > 1) {
      alpha = 1;
    }
    setState(() {
      appBarAlpha = alpha;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Color(0xfff2f2f2),
        body: LoadingContainer(//加入加载loading
            isLoading: _loading,
            child: Stack(
              children: <Widget>[
                MediaQuery.removePadding(
                    removeTop: true, //移除顶部的padding
                    context: context,
                    child: RefreshIndicator(
                        child: NotificationListener(
                          //监听滚动
                          onNotification: (scrollNotification) {
                            //当满足是ScrollUpdateNotification才触发
                            if (scrollNotification
                                    is ScrollUpdateNotification &&
                                scrollNotification.depth == 0) {
                              //scrollNotification.depth 找到 ListView滚动才触发
                              //滚动且是列表滚动的时候
                              _onScroll(scrollNotification.metrics.pixels);
                            }
                          },
                          child: _listView,
                        ),
                        onRefresh: _handleRefresh)),
                _appBar
              ],
            )));
  }
Swiper的调用
//抽离banner
  Widget get _banner {
    return Container(
        height: 240,
        child: Swiper(
          itemCount: bannerList.length,
          autoplay: true,
          itemBuilder: (BuildContext context, int index) {
            return GestureDetector(
              onTap: () {
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  CommonModel model = bannerList[index];
                  return WebView(
                      url: model.url,
                      title: model.title,
                      hideAppBar: model.hideAppBar);
                }));
              },
              child: Image.network(
                bannerList[index].icon,
                fit: BoxFit.fill, //图片的适配方式
              ),
            );
          },
          pagination: SwiperPagination(), //指示器
        ));
  }
列表渲染
@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          _appBar(),
          MediaQuery.removePadding(
              removeTop: true, //去除空白处
              context: context,
              child: Expanded(
                //Expanded 自适应宽高
                flex: 1,
                child: ListView.builder(//列表 常用需要数量 和 item 结构复杂的多拆分成小块
                    itemCount: searchModel?.data?.length ?? 0,
                    itemBuilder: (BuildContext context, int position) {
                      return _item(position);//position -> index
                    }),
              ))
        ],
      ),
    );
  }
搜索关键字高亮技巧
_keywordTextSpans(String word, String keyword) {
    List<TextSpan> spans = [];
    if (word == null || word.length == 0) return spans;
    List<String> arr = word.split(keyword);//切割后字符如:'oqadsao'->[,qadsa,]

    TextStyle normalStyle = TextStyle(fontSize: 16, color: Colors.black87);
    TextStyle keywordStyle = TextStyle(fontSize: 16, color: Colors.orange);

    for (int i = 0; i < arr.length; i++) {
      if ((i + 1) % 2 == 0) {//匹配到关键字设置高亮
        spans.add(TextSpan(text: keyword, style: keywordStyle));
      }
      String val = arr[i];
      if (val != null && val.length > 0) {
        spans.add(TextSpan(text: val, style: normalStyle));
      }
    }
    return spans;
  }
动画
Animation<double> animation;
AnimationController controller;

  @override
  void initState() {
  	//定义动画controller
    controller = AnimationController(
        vsync: this, duration: Duration(milliseconds: 1000));
        //动画效果 及状态
    animation = CurvedAnimation(parent: controller, curve: Curves.easeIn)
      ..addStatusListener((status) {//加入监听状态
        if (status == AnimationStatus.completed) {
          controller.reverse();
        } else if (status == AnimationStatus.dismissed) {
          controller.forward();
        }
      });
    super.initState();
  }
 @override
  void dispose() {//加入的同时 也记得销毁
    controller.dispose();
    super.dispose();
  }


//调用动画
Center(
  child: AnimatedMic(animation: animation),
)

//定义动画的类

const double MIC_SIZE = 80;
class AnimatedMic extends AnimatedWidget {
	//定义动画元素的 改变效果 如:透明度 大小
  static final _opacityTween = Tween<double>(begin: 1, end: 0.5);
  static final _sizeTween = Tween<double>(begin: MIC_SIZE, end: MIC_SIZE - 20);

  AnimatedMic({Key key, Animation<double> animation})
      : super(key: key, listenable: animation);

  @override
  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    return Opacity(
      opacity: _opacityTween.evaluate(animation),
      child: Container(
        height: _sizeTween.evaluate(animation),
        width: _sizeTween.evaluate(animation),
        decoration: BoxDecoration(//装饰器 如:border
            color: Colors.blue,
            borderRadius: BorderRadius.circular(MIC_SIZE / 2)),
        child: Icon(
          Icons.mic,
          color: Colors.white,
          size: 30,
        ),
      ),
    );
  }
}
布局,定位,元素绑定事件
_bottomItem() {
    return FractionallySizedBox(
      widthFactor: 1,//撑满整个
      child: Stack(
        children: <Widget>[
          GestureDetector(//相关事件绑定
            onTapDown: (e) {
              // controller.forward();
              _speakStart();
            },
            onTapUp: (e) {
              // controller.reset();
              // controller.stop();
               _speakStop();
            },
            onTapCancel: () {
              // controller.reset();
               _speakStop();

            },
            child: Center(//子元素整体 居中
              child: Column(//分为上下布局
                children: <Widget>[
                  Padding(
                    padding: EdgeInsets.all(10),
                    child: Text(//文字一般都是 Text('xxx',style:xxxxx)
                      speakTips,
                      style: TextStyle(color: Colors.blue, fontSize: 12),
                    ),
                  ),
                  Stack(//Stack 可覆盖
                    children: <Widget>[
                      Container(
                          //站位元素 ,避免动画执行过程中导致父布局大小变动
                          height: MIC_SIZE,
                          width: MIC_SIZE),
                      Center(
                        child: AnimatedMic(animation: animation),
                      )
                    ],
                  )
                ],
              ),
            ),
          ),
          Positioned(//定位
            right: 0,
            bottom: 20,
            child: GestureDetector(
              onTap: () {//加入点击事件
                Navigator.pop(context);
              },
              child: Icon(
                Icons.close,
                size: 30,
                color: Colors.grey,
              ),
            ),
          )
        ],
      ),
    );
  }
}
跳转页面传参及返回页面
//flutter 调取配置好的语音识别SDK
    AsrManger.start().then((text) {
      if (text != null && text.length > 0) {
      //setState -> 动态修改值
        setState(() {
          speakResult = text;
        });
        //先关闭 后跳转
        // Navigator.pop(context) -> 默认返回上一页
        Navigator.pop(context);
        
		//返回指定的跳转页面 注:SearchPage是另外的页面,需要引入后才可调用
        Navigator.push(
            context,
            MaterialPageRoute(
                builder: (context) => SearchPage(keyword: speakResult)));
      }
    }).catchError((onError) => print(onError));
  }
延时操作
// 延时执行返回 `1s
Future.delayed(Duration(seconds: 1), (){
    Navigator.of(context).pop();
    print('延时1s执行');
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值