flutter 知识点

前沿

熟悉了下flutter ,然后把一些知识点梳理下,便于记忆:

其实很多布局样式和CSS差异并不大,我的理解 flutter的写法就是HTML 写在 标签上的style,也就是内敛样式,这样好理解,你也可以有不同的看法,

 

完成了之前没有完成的flutter demo

哈哈哈,OK

 

常用的布局和用到的组件:

其他可以去官网上去查阅

Material 风格

下面我们使用 Material 风格来优化Hello World。在上面的代码中,我们已经 import 引入了 Material 库,Material是Google提供的一个设计语言和UI组件库

import 'package:flutter/material.dart';

void main() {
  runApp(
      MaterialApp(
          home: Scaffold(
              appBar: AppBar(
                  title: Text("第一个Flutter程序")
              ),
              body: Text("Hello World")
          )
      )
  );
}

MaterialApp 是Flutter中的一个顶级组件,它包装了整个应用程序,并提供了一些应用程序级别的功能,所以它是应用程序的根组件。在创建 MaterialApp 的时候,传递了一个 Scaffold 作为显示的主页,Scaffold 是一个布局组件,相当于一个页面。

Scaffold 的body属性表示是页面显示的body部分,Scaffold还可以包含appBar、tabBar等部分。

所以上面的操作就是使应用更加层次化,创建了一个应用的 Widget,在应用的 Widget 中又创建了一个页面的 Widget,在页面中添加了一个文本的 Widget

StatelessWidget

上面的 Hello World 感觉看上去代码很乱,各个 Widget 嵌套,都写在 main 函数里面结构很不清晰,现在还只是个 Hello World,如果是真正的项目,页面组件一多,那还了得。

所以我们需要对代码进行封装,创建我们自己的 Widget,将各种组件封装到我们的 Widget中,实现结构的清晰划分。

在 Flutter 中,我们可以创建两种 Widget,StatelessWidget 和 StatefulWidget ,什么区别呢?

  • StatelessWidget: 没有状态的Widget,也就是没有数据变化的 Widget,通常这种Widget仅仅是做一些展示工作而已;
  • StatefulWidget: 需要保存状态,也就是会有数据变化的Widget,例如 demo 程序中有计数的变化

 

Container

 是 Flutter 中的一个基础布局组件,用于包裹和布局其他组件,并且可以添加装饰、边框、阴影等样式效果。它是一个非常灵活的组件,常用于创建各种样式丰富的 UI 元素。

下面我们通过 Container 实现下面的效果,下面居中的部分就是一个 Container 。

SizedBox 

是 Flutter 中的一个布局组件,它可以用来创建一个固定尺寸的空间。SizedBox 可以在水平和垂直方向上设置固定的宽度和高度,用于限制子组件的大小或创建间距。

例如 Text 组件本身是不支持直接设置宽度和高度的,如果想要控制 Text 组件的宽度和高度,可以将其放在SizedBox 或 Container 里,然后设置SizedBox 或 Container 的宽高

 

如果只是设置尺寸,不涉及额外的装饰和样式,

优先使用 SizedBox 因为 Container 会增加一些性能开销。如果要使用样式,那么只能使用 Container 。

 

Image 

组件是 Flutter 中用于显示图像的部件,它可以显示网络图像、本地资源图像或者内存中的图像。

 
Image.network(
  "http://.com/open-assets/img/telangpu2.jpg",     // 设置背景颜色
  fit: BoxFit.cover,                               // 设置图片显示的适配模式
)

加载本地图片

在lib 的同级别 下配置地址倒入本地图片

 

然后需要在 pubspec.yaml 文件中配置资源文件夹的路径。

 而且必须要对其的

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Demo'),
        ),
        body: Center(
          child: Container(
            width: 300,
            height: 300,
            decoration: const BoxDecoration(
              color: Colors.lightBlue,              // 设置背景颜色
            ),
            // --------------------- 下面是加载本地图片 -----------------------------
            child: Image.asset(
              "assets/images/telangpu.jpg",
              fit: BoxFit.cover,                            // 设置图片适配模式
            ),
          ),
        ));
  }
}
View Code

 Container设置圆形图片

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Demo'),
        ),
        body: Center(
          child: Container(
            width: 200,
            height: 200,
            // --------------------- 通过BoxDecoration设置圆角 ---------------------
            decoration: BoxDecoration(
                color: Colors.lightBlue,              // 设置背景颜色
                borderRadius: BorderRadius.circular(100),
                image: const DecorationImage(
                    image: NetworkImage(
                        "http:/om/open-assets/img/telangpu.jpg"
                    ),
                    fit: BoxFit.cover
                )
            ),
          ),
        ));
  }
}
View Code

 

自定义布局:

我的理解就是那种CSS 中的flex 布局

水平布局组件Row

Row是一种水平排列子组件的布局组件。它将其子组件按照水平方向依次排列,可以用来创建水平的UI布局,比如按钮、文本、图标等。

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Demo'),
        ),
        body: Row(
          // ---------------------在Row中添加三个按钮,按钮是自定义的组件------------------------
          children: const [
            IconButton(icon: Icons.shop, color: Colors.lightBlue),
            IconButton(icon: Icons.house, color: Colors.lightGreen),
            IconButton(icon: Icons.fire_truck, color: Colors.red),
          ],
        )
    );
  }
}

// 自定义一个按钮组件
class IconButton extends StatelessWidget {
  final Color color;
  final double size;
  final IconData icon;

  // 自定义按钮组件,可以传递按钮的颜色和按钮上的图标,以及图标的尺寸
  const IconButton({super.key, required this.icon, this.color = Colors.blue, this.size = 32.0});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100.0,
      width: 100.0,
      color: color,
      child: Center(
          child: Icon(icon, size: size, color: Colors.white)
      ),
    );
  }
}
View Code

垂直布局组件Column

Column是一种垂直排列子组件的布局组件。它将其子组件按照垂直方向依次排列。

Column 组件和 Row 组件是非常相似的,使用方法基本一样。只是排列方向不一样,Row 组件的主轴方向是水平的,Column 的主轴方向是垂直的。

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Demo'),
        ),
        body: Container(
            height: 400,
            width: double.infinity,
            color: Colors.yellow,
            child: Column(
              // ---------------------在Column中添加三个按钮,按钮是自定义的组件------------------------
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: const [
                IconButton(icon: Icons.shop, color: Colors.lightBlue),
                IconButton(icon: Icons.house, color: Colors.lightGreen),
                IconButton(icon: Icons.fire_truck, color: Colors.red),
              ],
            ),
        )
    );
  }
}

// 自定义一个按钮组件
class IconButton extends StatelessWidget {
  final Color color;
  final double size;
  final IconData icon;

  const IconButton({super.key, required this.icon, this.color = Colors.blue, this.size = 32.0});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100.0,
      width: 100.0,
      color: color,
      child: Center(
          child: Icon(icon, size: size, color: Colors.white)
      ),
    );
  }
}
View Code

 弹性布局组件Flex和Expanded

Flex 组件可以沿着水平或垂直方向排列子组件,可以通过 direction 属性指定它是水平方向还是垂直方向。

如果指定它是水平方向的,那么它和 Row 是一样的,如果指定它是垂直方向的,

那么它和 Column 是一样的,因为 Row 和 Column 都继承自 Flex ,参数基本相同,所以能使用 Flex 的地方基本上都可以使用 Row 或 Column 来实现 。 FlexRowColumn 可以结合 Expanded 组件来实现弹性布局 。

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      // --------------------Flex 组件----------------------
      body: Flex(
        direction: Axis.horizontal,
        children: const [
          // -------------------- 通过Expanded组件指定占用的比例 ----------------------
          Expanded(
              flex: 2,      // 占用2份的空间,设置flex后,child的元素的宽度是失效的。
              child: IconButton(icon: Icons.shop, color: Colors.lightBlue)),
          Expanded(
              flex: 1,      // 占用1份的空间
              child: IconButton(icon: Icons.fire_truck, color: Colors.red))
        ],
      ),
    );
  }
}

// 自定义一个按钮组件
class IconButton extends StatelessWidget {
  final Color color;
  final double size;
  final IconData icon;

  const IconButton(
      {super.key,
      required this.icon,
      this.color = Colors.blue,
      this.size = 32.0});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100.0,
      width: 100.0,
      color: color,
      child: Center(child: Icon(icon, size: size, color: Colors.white)),
    );
  }
}
View Code

首先设置 Flex 元素的方向为水平方向,然后使用 Flex 组件包裹 Expanded 组件,通过 Expanded 设置占用的比例。

需要注意 Expanded 组件中的子组件的宽度是无效的,是由 Expanded 来控制的。

上面的 Flex 可以换成 Row ,效果是一样的。

 

我们还可以实现一种效果,就是固定一部分组件的尺寸不变,剩余的组件随着屏幕的尺寸进行自适应

右侧的按钮尺寸是固定的,左侧按钮随着屏幕的尺寸进行自适应。

只需要将自适应的组将使用Expanded组件包裹即可。

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      // --------------------Flex 组件----------------------
      body: Flex(
        direction: Axis.horizontal,
        children: const [
          // -------------------将自适应的组件使用Expanded组件包裹----------------------
          Expanded(
              child: IconButton(icon: Icons.shop, color: Colors.lightBlue)
          ),
          IconButton(icon: Icons.fire_truck, color: Colors.red)
        ],
      ),
    );
  }
}

// 自定义一个按钮组件
class IconButton extends StatelessWidget {
  final Color color;
  final double size;
  final IconData icon;

  const IconButton(
      {super.key,
      required this.icon,
      this.color = Colors.blue,
      this.size = 32.0});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100.0,
      width: 100.0,
      color: color,
      child: Center(child: Icon(icon, size: size, color: Colors.white)),
    );
  }
}
View Code

网格组件GridView

GridView 是一个用于展示网格布局的组件,它可以在水平和垂直方向上排列子组件,通常用于展示一系列相似的数据项,

比如图片、卡片、图标等。GridView 可以根据指定的行数、列数或交叉轴上的子组件的最大宽度来排列子组件。

GridView创建网格列表主要有下面三种方式

  • 通过GridView.count 实现网格布局

  • 通过GridView.extent 实现网格布局

  • 通过GridView.builder实现动态网格布局

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Demo'),
        ),
        // ------------------使用GridView.count创建GridView--------------------
        body: GridView.count(
          crossAxisCount: 4,      // 设置每一行元素的个数
          children: const [
            IconButton(icon: Icons.shop, color: Colors.lightBlue),
            IconButton(icon: Icons.house, color: Colors.lightGreen),
            IconButton(icon: Icons.fire_truck, color: Colors.red),
            IconButton(icon: Icons.settings, color: Colors.orange),
            IconButton(icon: Icons.logout, color: Colors.cyan),
            IconButton(icon: Icons.star, color: Colors.yellow),
            IconButton(icon: Icons.delete, color: Colors.lightGreen),
            IconButton(icon: Icons.rule, color: Colors.lightBlue),
            IconButton(icon: Icons.timeline, color: Colors.lightGreen),
            IconButton(icon: Icons.access_alarm, color: Colors.lightBlue),
          ],
        ));
  }
}

// 自定义一个按钮组件
class IconButton extends StatelessWidget {
  final Color color;
  final double size;
  final IconData icon;

  const IconButton(
      {super.key,
      required this.icon,
      this.color = Colors.blue,
      this.size = 32.0});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100.0,
      width: 100.0,
      color: color,
      child: Center(child: Icon(icon, size: size, color: Colors.white)),
    );
  }
}
View Code

容器组件Wrap

Wrap 是一个用于流式布局的组件,它可以将一系列子组件在水平或垂直方向上自动换行排列,适用于需要根据可用空间动态调整布局的情况。Wrap 可以在超出容器边界时自动将子组件放置到下一行或下一列,以适应不同尺寸的屏幕或容器。

我们之前学习了 Row 和 Column 组件,但是 Row 组件中的元素装不下不会换到下一行,但是 Wrap 组件可以。

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: DemoPage(),
    );
  }
}

/// 页面
class DemoPage extends StatelessWidget {
  const DemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Column(crossAxisAlignment: CrossAxisAlignment.center, children: [
        const Text("热门搜索"),
        const Divider(color: Colors.grey),
        // --------------- Wrap的使用 -------------------
        Wrap(
          spacing: 10,        // 子组件之间的间距
          runSpacing: 0,      // 行之间的间距
          children: [
            OutlinedButton(onPressed: () {}, child: const Text("曹操", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("刘玄德", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("关羽", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("张飞", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("诸葛孔明", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("夏侯惇", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("司马老贼", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("孙权", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("孙策", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("孙尚香", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("典韦", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("赵云", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("吕布", style: TextStyle(color: Colors.black54))),
            OutlinedButton(onPressed: () {}, child: const Text("马超", style: TextStyle(color: Colors.black54))),
          ],
        ),
      ]),
    );
  }
}
View Code
Wrap(
  alignment: WrapAlignment.center,  // 控制子组件的对齐方式
  spacing: 10,        // 子组件之间的间距
  runSpacing: 0,      // 行之间的间距
  children: [
    // ...
  ],
)

还使用了 spacing 属性来控制各个元素之间的间距,使用 runSpacing 属性控制行之间的间距。

还可以使用 alignment 子组件的对齐方式,例如设置居中对齐:

 

  标题栏AppBar

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {
  const MainPage({Key? key}) : super(key: key);

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Drawer Demo'),     // 标题
          centerTitle: true,                    // 标题居中
          backgroundColor:Colors.red,           // 背景颜色
          leading:IconButton(                   // 左侧按钮
              icon: const Icon(Icons.west),
              onPressed: (){
                print('点击左侧按钮');
              }),
          actions: [                            // 右侧按钮,可以有多个
          IconButton(
              icon: const Icon(Icons.search),
              onPressed: () {
                print('点击了搜索按钮');
              }),
          IconButton(
              icon: const Icon(Icons.more_horiz),
                  onPressed: (){
                  print('点击了更多按钮');
                })
            ],
        ),
        body: const Center(child: Text("Doubi")),
    );
  }
}
View Code

 

路由

什么是路由?

其实就是页面跳转。

Flutter 中的路由系统基于导航栈来管理不同页面的顺序和状态。

什么是导航栈?

导航栈(Navigation Stack)是在应用程序中用于管理页面或路由的一种数据结构。它类似于堆栈(Stack)数据结构,遵循先进后出(LIFO)的原则。

在 Flutter 中,导航栈用于存储打开的页面或路由,每当你打开一个新的页面或路由时,它会被推入(push)到导航栈的顶部。因为系统当前显示的页面就是当前在导航栈顶的的页面。当你执行返回操作时,最顶部的页面会被弹出(pop)出栈,回到上一个页面。

在 Flutter 中,Navigator 类负责管理导航栈,并提供了管理堆栈的方法。你可以使用 Navigator 的方法来推入新页面、弹出当前页面、查看当前栈中的页面等。导航栈在应用程序中起着重要的作用,它允许你实现页面之间的流畅切换、返回操作以及状态管理。

以下是 Navigator 类提供的一些常用的方法,了解一下,后面逐一介绍一下如何使用。

Navigator.push(context, MaterialPageRoute(builder: (context) => NewPage()));
  • 将当前页面弹出导航栈,返回上一个页面。
Navigator.pop(context);
  • 替换当前页面为新页面,从而实现页面切换并且移除当前页面。
Navigator.pushReplacementNamed(context, "/message");
  • 将导航栈中的页面依次弹出,直到某个指定页面。
Navigator.popUntil(context, ModalRoute.withName('/home'));
  • 检查是否可以执行返回操作(即是否还有页面可以弹出)。
Navigator.canPop(context)

封装路由

 

我们在 main.dart 中将路由配置定位为一个 Map 对象,其实这样代码混乱不利于管理,我们可以将路由配置和onGenerateRoute,抽离到一个单独的文件。

例如,新建一个 router.dart,代码如下:

首先引入路由的各个页面文件,然后定义路由配置和 onGenerateRoute 函数

import 'package:flutter/material.dart';
import '../pages/home.dart';
import '../pages/search.dart';
import '../pages/message.dart';

// 1、定义Map类型的routes
final Map routes = {
  '/': (context) => const HomePage(),
  '/search': (context, {arguments}) => SearchPage(arguments: arguments),
  '/message': (context) => const MessagePage(),
};

var onGenerateRoute = (RouteSettings settings) {
  // 统一处理
  final String? name = settings.name;
  final Function? pageContentBuilder = routes[name];
  if (pageContentBuilder != null) {
    if (settings.arguments != null) {
      final Route route = MaterialPageRoute(
          builder: (context) =>
              pageContentBuilder(context, arguments: settings.arguments));
      return route;
    } else {
      final Route route = MaterialPageRoute(
          builder: (context) => pageContentBuilder(context));
      return route;
    }
  }
  return null;
};

重新修改 main.dart

import 'package:flutter/material.dart';
// 引入路由配置
import './router/router.dart';

void main() => runApp(const MyApp());

/// App根Widget
class MyApp extends StatelessWidget {

  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      // 初始化路由,初始化进入的页面
      initialRoute: "/",
      // onGenerateRoute处理
      onGenerateRoute: onGenerateRoute,
    );
  }
}

 返回根路由

我们可以使用 Navigator.pushNamedAndRemoveUntil() 方法,它用于实现页面导航并清除导航栈中的页面,以达到指定条件的效果。具体而言,它的作用如下:

  1. 首先,它会压入(导航到)一个新的命名路由页面到导航栈。
  2. 压入新页面之前,它会从导航栈中删除所有指定条件之前的页面,以确保只剩下符合条件的页面。
// ----- 返回首页
Navigator.pushNamedAndRemoveUntil(
  context,
  '/', // 跳转到的页面名称
  (route) => false, // 始终返回false,表示一直删除,删除所有页面
);

上面的代码会跳转到 "/" 首页,第三个参数是一个回调函数,用于确定是否删除页面。当返回 true 时,删除停止,页面保留在导航栈中。上面一直返回false,则会清空导航栈。

再举一个例子:

从 / 跳转到 /a,从 /a 跳转到 /b ,从 /b 跳转到 /d ,在 /d 中如何返回 /a,在 /a 通过 Navigator.pop 返回到 /,那么在 /d 中该如何返回到 /a 呢?

Navigator.pushNamedAndRemoveUntil(
  context,
  '/a', // 返回到/a页面
  ModalRoute.withName('/'), // 删除中间的页面,直到根页面
);

 

页面切换风格

我们之前使用的风格是 Material 库的风格,Material 组件库中路由的切换是通过 MaterialPageRoute 组件实现的,MaterialPageRoute 组件会根据 Android 和 iOS 上显示不同的风格。例如在切换页面的时候,在 Android 上是上下滑动切换,iOS 是左右滑动切换。

如果想在 Android 上实现和 iOS 上一样的切换效果,可以使用 Cupertino 库,其中 CupertinoPageRoute 是 Cupertino 组件库提供的iOS 风格的路由切换组件。

所以修改之前的路由配置即可,也是很简单的,需要修改两个地方:

  1. 引入 cupertino.dart,删除 material.dart ;
  2. 将 MaterialPageRoute 替换为 CupertinoPageRoute

 

// 1.配置iOS分隔的路由,删掉material.dart,引入cupertino.dart
import 'package:flutter/cupertino.dart';
// import 'package:flutter/material.dart';
import '../pages/home.dart';
import '../pages/search.dart';
import '../pages/message.dart';

// 1、定义Map类型的routes
final Map routes = {
  '/': (context) => const HomePage(),
  '/search': (context, {arguments}) => SearchPage(arguments: arguments),
  '/message': (context) => const MessagePage(),
};

var onGenerateRoute = (RouteSettings settings) {
  // 统一处理
  final String? name = settings.name;
  final Function? pageContentBuilder = routes[name];
  if (pageContentBuilder != null) {
    if (settings.arguments != null) {
      // 2. 将MaterialPageRoute替换为
      final Route route = CupertinoPageRoute(
          builder: (context) =>
              pageContentBuilder(context, arguments: settings.arguments));
      return route;
    } else {
      final Route route = CupertinoPageRoute(
          builder: (context) => pageContentBuilder(context));
      return route;
    }
  }
  return null;
};

引入资源包

在pubspec.yaml 文件夹目录下引入

你需要的包

 

然后等vs code 安装完毕以后

这样就OK了

 

posted @ 2024-02-16 15:37  -鹿-  阅读(42)  评论(0编辑  收藏  举报