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,如何删除添加元素呢
589 0
|
1月前
|
Android开发 iOS开发 容器
鸿蒙harmonyos next flutter混合开发之开发FFI plugin
鸿蒙harmonyos next flutter混合开发之开发FFI plugin
|
5月前
|
开发框架 前端开发 测试技术
Flutter开发常见问题解答
Flutter开发常见问题解答
|
1月前
|
开发者
鸿蒙Flutter实战:07-混合开发
鸿蒙Flutter混合开发支持两种模式:1) 基于har包,便于主项目开发者无需关心Flutter细节,但不支持热重载;2) 基于源码依赖,利于代码维护与热重载,需配置Flutter环境。项目结构包括AppScope、flutter_module等目录,适用于不同开发需求。
74 3
|
17天前
|
传感器 开发框架 物联网
鸿蒙next选择 Flutter 开发跨平台应用的原因
鸿蒙(HarmonyOS)是华为推出的一款旨在实现多设备无缝连接的操作系统。为了实现这一目标,鸿蒙选择了 Flutter 作为主要的跨平台应用开发框架。Flutter 的跨平台能力、高性能、丰富的生态支持和与鸿蒙系统的良好兼容性,使其成为理想的选择。通过 Flutter,开发者可以高效地构建和部署多平台应用,推动鸿蒙生态的快速发展。
130 0
|
19天前
|
Dart 安全 UED
Flutter&鸿蒙next中的表单封装:提升开发效率与用户体验
在移动应用开发中,表单是用户与应用交互的重要界面。本文介绍了如何在Flutter中封装表单,以提升开发效率和用户体验。通过代码复用、集中管理和一致性的优势,封装表单组件可以简化开发流程。文章详细讲解了Flutter表单的基础、封装方法和表单验证技巧,帮助开发者构建健壮且用户友好的应用。
60 0
|
1月前
|
开发框架 移动开发 Android开发
安卓与iOS开发中的跨平台解决方案:Flutter入门
【9月更文挑战第30天】在移动应用开发的广阔舞台上,安卓和iOS两大操作系统各自占据半壁江山。开发者们常常面临着选择:是专注于单一平台深耕细作,还是寻找一种能够横跨两大系统的开发方案?Flutter,作为一种新兴的跨平台UI工具包,正以其现代、响应式的特点赢得开发者的青睐。本文将带你一探究竟,从Flutter的基础概念到实战应用,深入浅出地介绍这一技术的魅力所在。
77 7
|
1月前
|
编解码 Dart API
鸿蒙Flutter实战:06-使用ArkTs开发Flutter鸿蒙插件
本文介绍了如何开发一个 Flutter 鸿蒙插件,实现 Flutter 与鸿蒙的混合开发及双端消息通信。通过定义 `MethodChannel` 实现 Flutter 侧的 token 存取方法,并在鸿蒙侧编写 `EntryAbility` 和 `ForestPlugin`,使用鸿蒙的首选项 API 完成数据的读写操作。文章还提供了注意事项和参考资料,帮助开发者更好地理解和实现这一过程。
57 0
|
1月前
|
Dart Android开发
鸿蒙Flutter实战:03-鸿蒙Flutter开发中集成Webview
本文介绍了在OpenHarmony平台上集成WebView的两种方法:一是使用第三方库`flutter_inappwebview`,通过配置pubspec.lock文件实现;二是编写原生ArkTS代码,自定义PlatformView,涉及创建入口能力、注册视图工厂、处理方法调用及页面构建等步骤。
52 0
|
2月前
|
JSON Dart Java
flutter开发多端平台应用的探索
flutter开发多端平台应用的探索
50 6