40个flutter入门实例详解(七)

35.监听滚动事件

class ScrollControllerTestRoute extends StatefulWidget {
  @override
  ScrollControllerTestRouteState createState() {
    return new ScrollControllerTestRouteState();
  }
}

class ScrollControllerTestRouteState extends State<ScrollControllerTestRoute> {
  ScrollController _controller = new ScrollController();
  bool showToTopBtn = false; //是否显示“返回到顶部”按钮

  @override
  void initState() {
    super.initState();
    //监听滚动事件,打印滚动位置
    _controller.addListener(() {
      print(_controller.offset); //打印滚动位置
      //当偏移量小于1000像素,不显示按钮
      //这里后面之所以&&showToTopBtn,是因为可以通过判断它是true或false省得不断地调用setState,影响性能
      if (_controller.offset < 1000 && showToTopBtn) {
        setState(() {
          showToTopBtn = false;
        });
        //当偏移量大于等于1000像素,显示按钮
        //&&showToTopBtn的理由同上
      } else if (_controller.offset >= 1000 && showToTopBtn == false) {
        setState(() {
          showToTopBtn = true;
        });
      }
    });
  }

  @override
  void dispose() {
    //为了避免内存泄露,需要调用_controller.dispose
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("滚动控制")),
      body: Scrollbar(//滚动条
        child: ListView.builder(
            itemCount: 100,//滚动的总条数
            itemExtent: 50.0, //列表项高度固定时,显式指定高度是一个好习惯(性能消耗小)
            controller: _controller,//添加已加入监听功能的控制器
            itemBuilder: (context, index) {
              return ListTile(title: Text("$index"),);//显示文本
            }
        ),
      ),
      //通过判断showToTopBtn的值来显示按钮
      floatingActionButton: !showToTopBtn ? null : FloatingActionButton(
          child: Icon(Icons.arrow_upward),
          onPressed: () {
            //执行动画返回到顶部
            _controller.animateTo(.0,
                duration: Duration(milliseconds: 200),
                curve: Curves.ease
            );
          }
      ),
    );
  }
}

效果:

36.根组件数据共享给子组件

class InheritedWidgetTestRoute extends StatefulWidget {
  @override
  _InheritedWidgetTestRouteState createState() => new _InheritedWidgetTestRouteState();
}

class _InheritedWidgetTestRouteState extends State<InheritedWidgetTestRoute> {
  //state的数据
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return  Center(
      //根组件,用于共享数据给它的子组件
      child: ShareDataWidget( //使用ShareDataWidget
        //构建根组件要用到的参数data
        data: count,
        //根组件的子组件
        child: Column(
          //垂直水平方向居中
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.only(bottom: 20.0),
              //根组件的子组件的子组件...
              child: _TestWidget(),//子widget中依赖ShareDataWidget
            ),
            RaisedButton(
              child: Text("Increment"),
              //每点击一次,将count自增,然后重新build,ShareDataWidget的data将被更新  
              onPressed: () => setState(() => ++count),
            )
          ],
        ),
      ),
    );
  }
}
class _TestWidget extends StatefulWidget {
  @override
  __TestWidgetState createState() => new __TestWidgetState();
}

class __TestWidgetState extends State<_TestWidget> {
  @override
  Widget build(BuildContext context) {
    //使用ShareDataWidget中的共享数据
    return Text(ShareDataWidget
        .of(context)
        .data
        .toString());
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    //父或祖先widget中的InheritedWidget改变(updateShouldNotify返回true)时会被调用。
    //如果build中没有依赖InheritedWidget,则此回调不会被调用。
    print("Dependencies change");
  }
}
class ShareDataWidget extends InheritedWidget {
  ShareDataWidget({
    //接收_InheritedWidgetTestRouteState组件build时传入的两个参数
    @required this.data,
    Widget child
  }) :super(child: child);

  final int data; //需要在子树中共享的数据,保存点击次数

  //定义一个便捷方法,方便子树中的widget获取共享数据  
  static ShareDataWidget of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<ShareDataWidget>();
  }

  //该回调决定当data发生变化时,是否通知子树中依赖data的Widget  
  @override
  bool updateShouldNotify(ShareDataWidget old) {
    //如果返回true,则子树中依赖(build函数中有调用)本widget
    //的子widget的`state.didChangeDependencies`会被调用
    return old.data != data;
  }
}

效果:

37.改变主题

class ThemeTestRoute extends StatefulWidget {
  @override
  _ThemeTestRouteState createState() => new _ThemeTestRouteState();
}

class _ThemeTestRouteState extends State<ThemeTestRoute> {
  Color _themeColor = Colors.teal; //当前路由主题色

  @override
  Widget build(BuildContext context) {
    ThemeData themeData = Theme.of(context);
    return Theme(
      data: ThemeData(
          primarySwatch: _themeColor, //用于导航栏、FloatingActionButton的背景色等
          iconTheme: IconThemeData(color: _themeColor) //用于Icon颜色
      ),
      child: Scaffold(
        appBar: AppBar(title: Text("主题测试")),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            //第一行Icon使用主题中的iconTheme
            Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Icon(Icons.favorite),
                  Icon(Icons.airport_shuttle),
                  Text("  颜色跟随主题")
                ]
            ),
            //为第二行Icon自定义颜色(固定为黑色)
            Theme(
              //局部主题覆盖全局主题
              data: themeData.copyWith(
                iconTheme: themeData.iconTheme.copyWith(
                    color: Colors.black
                ),
              ),
              child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Icon(Icons.favorite),
                    Icon(Icons.airport_shuttle),
                    Text("  颜色固定黑色")
                  ]
              ),
            ),
          ],
        ),
        floatingActionButton: FloatingActionButton(
            onPressed: () =>  //切换主题
                setState(() =>
                _themeColor =
                _themeColor == Colors.teal ? Colors.blue : Colors.teal
                ),
            child: Icon(Icons.palette)
        ),
      ),
    );
  }
}

效果:

      

38.异步UI更新

class MyHomePage extends StatelessWidget {
 @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('标题'),
      ),
      body: StreamBuilder<int>(
        stream: counter(), //调用异步耗时任务
        builder: (BuildContext context, AsyncSnapshot<int> snapshot) {//snapshot会包含当前异步任务的状态信息及结果信息
          //通过snapshot.hasError判断异步任务是否有错误
          if (snapshot.hasError)
            //打印错误
            return Text('Error: ${snapshot.error}');
            //onnectionState是一个枚举类,根据当前异步任务状态ConnectionState来返回不同的widget
          switch (snapshot.connectionState) {
            case ConnectionState.none:
              return Text('没有Stream');
            case ConnectionState.waiting:
              return Text('等待数据...');
            case ConnectionState.active:
              return Text('active: ${snapshot.data}');
            case ConnectionState.done:
              return Text('Stream已关闭');
          }
          return null; // unreachable
        },
      ),
    );
}
}
//使用Stream来实现异步每隔一秒生成一个数字,每次返回一个int类型
Stream<int> counter() {
  return Stream.periodic(Duration(seconds: 1), (i) {
    return i;
  });
}

效果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flutter开发实战详解PDF》是一本介绍如何使用Flutter进行实际开发的书籍。Flutter是由谷歌开发的一款跨平台框架,可以用来开发iOS、Android、Web和桌面应用程序。这本书涵盖了从Flutter基础知识到高级开发技巧的各个方面。 《Flutter开发实战详解PDF》首先介绍了Flutter的基本概念和工具,帮助读者快速入门。接着,书中详细讲解了Flutter的布局和UI组件,包括文本、按钮、图片等常用控件的使用方法。读者可以通过学习这些内容,了解如何构建一个漂亮、流畅的用户界面。 在基础知识介绍之后,书中通过实例介绍了如何进行网络请求、与后台进行数据交互。读者可以学习到如何使用Flutter的Http库来进行网络请求,并将获取到的数据展示在应用程序中。此外,书中还介绍了如何使用Flutter与数据库进行交互,以及如何处理用户输入和使用设备传感器。 《Flutter开发实战详解PDF》还提供了一些高级开发技巧和实践经验,例如如何进行状态管理、如何优化性能等。这些内容对于有一定Flutter开发经验的开发者来说尤为重要。 总的来说,这本书通过实例和案例的方式,详细讲解了Flutter的开发实践。无论是初学者还是有一定经验的开发者,都可以从中学到很多实用的技巧和知识。如果你想深入学习Flutter的开发,这本书是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值