Flutter :几个常用的知识点

简介: 本文介绍几个在 Flutter 中常用的知识点。

1. BoxFit 各个值得含义

在使用 Image Widget 展示一张图片时,我们通过 fit 参数给它设置图片的拉伸规则,例如:

Image.asset('assets/top.jpeg',fit: BoxFit.cover),

BixFit 本身是一个枚举:

它是表示将一个 box 内置到另一个 box 中时,如何利用外层 box 的剩余空间。

enum BoxFit {
   
   
  fill,

  contain,

  cover,

  fitWidth,

  fitHeight,

  none,

  scaleDown,
}

1.1 BoxFit.fill

充满父容器。为了适应父容器,宽和高有可能被拉伸或者压缩而导致变形。

1.2 BoxFit.contain

尽可能大,但同时保证不超过父容器的边界。如果子元素的宽和高不能与父容器的宽高匹配,那么子元素的左右两侧或者上下有可能留有空白区域。

1.3 BoxFit.cover

充满容器,可能会被截断。

1.4 BoxFit.fitWidth

图片填满宽度,高度可能会被截断。

1.5 BoxFit.fitHeight

图片填满高度,宽度可能会被截断

1.6 BoxFit.none

默认居中展示在容器的中间,如果超出父容器的宽高,那么超出的部分会被截断;如果没有超出父容器的宽高,直接居中展示。

1.7 BoxFit.scaleDown

默认居中展示在容器的中间,如果超出父容器的宽高,将其进行缩小,以保证全部展示,这点和 BoxFit.contain 一样;如果没有超出父容器的宽高,直接居中展示,这点和 BoxFit.none 一样。

2. Stateful and stateless widgets

有状态的 Widget 和无状态的 Widget 唯一的区别就是看它与用户交互以后,Widget 是否会发生变化。

比如用户可以进行勾选的 Checkbox

一个 widget 的状态保存在一个 State 对象中,它和 widget 的显示分离。 Widget 的状态是一些可以更改的值,如一个复选框是否被选中。当 widget 状态改变时,State 对象调用 setState(),告诉框架去重绘 widget。

如何创建一个 StatefulWidget

需要创建两个类:一个 StatefulWidget 的子类和一个 State 的子类。

例子:点击收藏按钮,更新收藏数量

///创建 StatefulWidget 的子类
///
///FavoriteWidget 类管理自己的状态,因此它通过重写 createState() 来创建状态对象。框架会在构建 widget 时调用 createState()。
///在这个例子中,createState() 创建 _FavoriteWidgetState 的实例,将在下一步中实现该实例。
class FavoriteWidget extends StatefulWidget {
   
   
  
  _FavoriteWidgetState createState() => _FavoriteWidgetState();
}
class _FavoriteWidgetState extends State<FavoriteWidget> {
   
   
  //状态对象存储的信息在 _isFavorited 和 _favoriteCount 变量中。
  bool _isFavorited = true;//是否收藏
  int _favoriteCount = 41;//收藏数量

  
  Widget build(BuildContext context) {
   
   
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
          padding: EdgeInsets.all(0),
          child: IconButton(
            padding: EdgeInsets.all(0),
            alignment: Alignment.centerRight,
            icon: (_isFavorited ? Icon(Icons.star) : Icon(Icons.star_border)),
            color: Colors.red[500],
            onPressed: _toggleFavorite,
          ),
        ),
        SizedBox(
          width: 18,
          child: Container(
            child: Text('$_favoriteCount'),
          ),
        ),
      ],
    );
  }

  void _toggleFavorite() {
   
   
  setState(() {
   
   
    if (_isFavorited) {
   
   
      _favoriteCount -= 1;
      _isFavorited = false;
    } else {
   
   
      _favoriteCount += 1;
      _isFavorited = true;
    }
  });
}
}

运行效果

3. Flutter 中的页面指的是什么?

在 Flutter 中我们使用 screen 表示一个页面,它的本质就是一个 Widget

那什么是路由呢?

在 Android 开发中,Activity 相当于“路由”,在 iOS 开发中,ViewController 相当于“路由”。在 Flutter 中,“路由”也是一个 widget。

4. Flutter 页面之间如何传值?

在 Flutter 中从一个页面导航到另一个页面主要有两种方式:

  1. Navigator.push()
onPressed: () {
   
   
  Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => SecondRoute()),
  );
}
  1. 命名路由 Navigator.pushNamed()
onPressed: () {
   
   
  Navigator.pushNamed(context, '/second');
}

使用不同的导航方式,传值的方式也不同,下面分别来说一下:

4.1 使用 Navigator.push() 传值的方式有两种

第一种:通过构造函数传值

先在目标页面定义好构造函数

class SecondScreen extends StatelessWidget {
   
   
  //SecondScreen 页面需要一个 title 参数
  SecondScreen({
   
   Key key,  this.title}) : super(key: key);

...
}

传值:

onPressed: () {
   
   
  Navigator.push(
    context,
    MaterialPageRoute(
      builder: (context) => SecondScreen(title: '参数',)
    )
  )
}

第二种:使用 RouteSettings 传递参数

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => RouteManager(),
    settings: RouteSettings(arguments: '参数')
  )
)

接收参数:ModalRoute.of(context).settings.arguments

class SecondScreen extends StatelessWidget {
   
   
  
  Widget build(BuildContext context) {
   
   
    //接收参数
    final String title = ModalRoute.of(context).settings.arguments;

    // Use the title to create the UI.
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Text(title),
      ),
    );
  }
}

4.2 使用 Navigator.pushNamed() 时的传值方式

Navigator.pushNamed(
  context,
  '路由名称',
  arguments:'参数'
)

接收参数同样可以用:ModalRoute.of(context).settings.arguments

4.3 适配

那么这里有一个问题,假如一个页面,它的构造函数必须接收一个参数,同时呢,我也想用命令路由的方式跳转到该页面,应该怎么做呢?

假设这个页面是:

class SecondScreen extends StatelessWidget {
   
   
  //SecondScreen 页面需要一个 title 参数
  SecondScreen({
   
   Key key,  this.title}) : super(key: key);

  final String title;

...
}

路由注册方式:

class MyApp extends StatelessWidget {
   
   
  
  Widget build(BuildContext context) {
   
   
    return MaterialApp(

      //省略无语代码
      ...

      //注册路由表
      routes: {
   
   
        'second': (context) => SecondScreen(
              title: ModalRoute.of(context).settings.arguments,
            ),
      },
    );
  }
}

4.4 从一个页面回传数据

上面介绍了跳转一个新路由时如何传值,那么如果我返回上一个页面的话,如果回传数据呢?

Navigator.pop(context, '回传的值');

接收上个页面返回的值,并通过一个 SnackBar 来显示:

void _navigateAndDisplay(BuildContext context) async {
   
   
  //导航并接收结果
  final result =
      await Navigator.pushNamed(context, 'second', arguments: '参数');

  Scaffold.of(context)
    ..removeCurrentSnackBar()
    ..showSnackBar(SnackBar(content: Text("$result")));
}

5. 跨页面切换的动效 Widget (Hero animations)

如何在页面切换时为某个组件加上转场动画,从而在两个页面间建立视觉上的锚定关联。如下如所示:

Flutter 为我们提供了 Hero animations 来实现:

代码示例:

///第一个页面
class HeroDemoScreen extends StatelessWidget {
   
   
  static const routeName = '/HeroDemoScreen';

  
  Widget build(BuildContext context) {
   
   
    return Scaffold(
      appBar: AppBar(
        title: Text('Hero animations'),
      ),
      body: GestureDetector(
        child: Hero(
            tag: 'imageHero',
            child: Image.network('https://picsum.photos/250?image=9')),
        onTap: () => {
   
   Navigator.pushNamed(context, ImageScanScreen.routeName)},
      ),
    );
  }
}
///第二个页面
class ImageScanScreen extends StatelessWidget {
   
   
  static const routeName = '/ImageScanScreen';

  
  Widget build(BuildContext context) {
   
   
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('查看图片'),
      ),
      body: GestureDetector(
        child: Center(
          child: Hero(
              tag: 'imageHero',
              child: Image.network('https://picsum.photos/250?image=9')),
        ),
        onTap: ()=>{
   
   
          Navigator.pop(context)
        },
      ),
    );
  }
}

为了通过动画在两个页面间建立联系,需要把每个页面的 Image 组件都包裹进 Hero 组件里面。 Hero 组件有两个参数:

  1. tag
    作为 Hero 组件的标识,在这两个页面中必须相同。

  2. child
    在两个屏幕直接跨越的那个 widget,在本例中就是 Image。

Hero(
  tag: 'imageHero',
  child: Image.network(
    'https://picsum.photos/250?image=9',
  ),
);
相关文章
|
Dart Java
flutter开发之必须掌握的dart知识点:list,set,map
要说,List在我的开发使用中,确实是最为频繁的了,那么如何使用list,也就成了一个问题,list提供的方法又有哪些 这些都是需要掌握理解的。 首先第一个, 对于固定长度的list,如何删除添加元素呢
527 0
|
3天前
|
缓存 监控 前端开发
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
【4月更文挑战第30天】本文探讨了Flutter应用启动优化策略,包括理解启动过程、资源加载优化、减少初始化工作、界面布局简化、异步初始化、预加载关键数据、性能监控分析以及案例和未来优化方向。通过这些方法,可以缩短启动时间,提升用户体验。使用Flutter DevTools等工具可助于识别和解决性能瓶颈,实现持续优化。
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
|
3天前
|
开发框架 Dart 前端开发
【Flutter前端技术开发专栏】Flutter与React Native的对比与选择
【4月更文挑战第30天】对比 Flutter(Dart,强类型,Google支持,快速热重载,高性能渲染)与 React Native(JavaScript,庞大生态,热重载,依赖原生渲染),文章讨论了开发语言、生态系统、性能、开发体验、学习曲线、社区支持及项目选择因素。两者各有优势,选择取决于项目需求、团队技能和长期维护考虑。参考文献包括官方文档和性能比较文章。
【Flutter前端技术开发专栏】Flutter与React Native的对比与选择
|
1天前
|
前端开发 C++ 容器
Flutter-完整开发实战详解(一、Dart-语言和-Flutter-基础)(1)
Flutter-完整开发实战详解(一、Dart-语言和-Flutter-基础)(1)
|
2天前
|
Android开发
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
|
2天前
|
XML Dart Java
Flutter插件开发之APK自动安装,字节跳动Android岗面试题
Flutter插件开发之APK自动安装,字节跳动Android岗面试题
|
2天前
|
Java Android开发 设计模式
flutter音视频开发,Android开发需要学什么
flutter音视频开发,Android开发需要学什么
|
3天前
|
Dart 前端开发 测试技术
【Flutter前端技术开发专栏】Flutter开发中的代码质量与重构实践
【4月更文挑战第30天】随着Flutter在跨平台开发的普及,保证代码质量成为开发者关注的重点。优质代码能确保应用性能与稳定性,提高开发效率。关键策略包括遵循最佳实践,编写可读性强的代码,实施代码审查和自动化测试。重构实践在项目扩展时尤为重要,适时重构能优化结构,降低维护成本。开发者应重视代码质量和重构,以促进项目成功。
【Flutter前端技术开发专栏】Flutter开发中的代码质量与重构实践
|
3天前
|
存储 缓存 监控
【Flutter前端技术开发专栏】Flutter中的列表滚动性能优化
【4月更文挑战第30天】本文探讨了Flutter中优化列表滚动性能的策略。建议使用`ListView.builder`以节省内存,避免一次性渲染所有列表项。为防止列表项重建,可使用`UniqueKey`或`ObjectKey`。缓存已渲染项、减少不必要的重绘和异步加载大数据集也是关键。此外,选择轻量级组件,如`StatelessWidget`,并利用Flutter DevTools监控性能以识别和解决瓶颈。持续测试和调整以提升用户体验。
【Flutter前端技术开发专栏】Flutter中的列表滚动性能优化
|
3天前
|
Dart 前端开发 安全
【Flutter前端技术开发专栏】Flutter中的线程与并发编程实践
【4月更文挑战第30天】本文探讨了Flutter中线程管理和并发编程的关键性,强调其对应用性能和用户体验的影响。Dart语言提供了`async`、`await`、`Stream`和`Future`等原生异步支持。Flutter采用事件驱动的单线程模型,通过`Isolate`实现线程隔离。实践中,可利用`async/await`、`StreamBuilder`和`Isolate`处理异步任务,同时注意线程安全和性能调优。参考文献包括Dart异步编程、Flutter线程模型和DevTools文档。
【Flutter前端技术开发专栏】Flutter中的线程与并发编程实践