您的位置:

Flutter for web:从多个方面的介绍

一、快速入门

Flutter是谷歌在2017年推出的一个跨平台开发框架,可以轻松地在iOS和Android上构建高性能、高保真度的原生应用程序。而Flutter for web则是Flutter在Web平台上的扩展,它可以将现有的Flutter代码用于Web应用程序的构建。

Flutter for web的安装非常简单,只需要在Flutter命令行工具中使用以下命令即可:

 $ flutter channel beta
 $ flutter upgrade
 $ flutter config --enable-web

然后,使用以下命令检查Flutter是否已经支持web:

 $ flutter devices

如果看到了“Chrome(web)”,则表示Flutter for web已经成功配置好了。

二、Web特定的Widget和功能

Flutter for web提供了一些Web特定的Widget和功能,可以让你更方便的在Web上开发应用程序。

1. 容器的大小

在Web上,应用程序的大小和尺寸通常需要更具自适应性。Flutter for web提供了一个widget,名为“LayoutBuilder”,它可以让你更精确地控制容器的大小和尺寸。下面是一个实现自适应布局的示例:


  LayoutBuilder(
    builder: (BuildContext context, BoxConstraints constraints) {
      if (constraints.maxWidth >= 600) {
        // 在宽度大于等于600px时显示一个横向的布局
        return Row(
          children: [
            Container(width: 200, height: 200, color: Colors.red),
            Container(width: 400, height: 200, color: Colors.blue),
          ],
        );
      } else {
        // 在宽度小于600px时显示一个列形的布局
        return Column(
          children: [
            Container(width: 200, height: 200, color: Colors.red),
            Container(width: 200, height: 100, color: Colors.blue),
          ],
        );
      }
    },
  )

2. 可点击的链接(hyperlink)

在Web上,可点击的链接十分普遍。Flutter for web提供了一个内置的widget,名为“Hyperlink”,可以轻松地创建可点击的链接。下面是一个示例:


  Hyperlink(
    url: 'https://www.google.com',
    child: Text('点击跳转到Google'),
  )

3. 悬停效果

悬停效果在Web上也很常见,Flutter for web提供了一个名为“MouseRegion”的widget,可以让你轻松地实现鼠标悬停效果。下面是一个例子,当鼠标悬停在按钮上时,按钮的颜色会变为红色:


  MouseRegion(
    onHover: (PointerEvent details) {
      setState(() {
        _isHover = true;
      });
    },
    onExit: (PointerEvent details) {
      setState(() {
        _isHover = false;
      });
    },
    child: Container(
      width: 100,
      height: 50,
      color: _isHover ? Colors.red : Colors.grey,
      child: Center(child: Text('悬停')),
    ),
  )

三、Flutter for web与原生应用程序的不同之处

虽然Flutter for web与Flutter for native的语法非常相似,但它们之间仍然存在一些重要的区别。这里列举几个需要注意的点:

1. 不支持所有的Flutter widget

Flutter for web目前尚未支持所有的Flutter widget,其中一些最常见的widget包括“CupertinoPicker”、“SliderTheme”、“Stepper”等。如果你在Flutter for web中使用这些widget,则可能会收到错误消息。

2. Flutter for web的性能和Flutter for native的性能有所不同

由于Web平台的复杂性,Flutter for web的性能和Flutter for native的性能有所不同。在实践中,Flutter for web在大多数情况下都表现良好,但对于某些要求较高的应用程序(例如游戏或大型应用程序),Flutter for native可能会更快一些。

3. Flutter for web的样式和布局可能与Web开发人员习惯的方式不同

Flutter for web的样式和布局是基于“flex”的框架,这可能与Web开发人员习惯的方式有所不同。例如,在Flutter for web中,你可以使用“Expanded”来填充可用空间,而不是使用CSS中常用的“width: 100%”等语法。

四、示例代码

下面是一个用Flutter for web构建的简单的TODO应用程序。它允许你添加、编辑和删除TODO项。


import 'package:flutter/material.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';

void main() {
  setUrlStrategy(PathUrlStrategy());
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'TODO Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'TODO Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State
    {
  List<String> _todoList = [];
  final TextEditingController _textEditingController =
      TextEditingController();

  void _addTodo() {
    setState(() {
      final todo = _textEditingController.text;
      if (todo.isNotEmpty) {
        _todoList.add(todo);
        _textEditingController.clear();
      }
    });
  }

  void _editTodo(int index, String todo) {
    setState(() {
      _todoList[index] = todo;
    });
  }

  void _deleteTodo(int index) {
    setState(() {
      _todoList.removeAt(index);
    });
  }

  void _showEditDialog(int index) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        final todoController = TextEditingController(text: _todoList[index]);
        return AlertDialog(
          title: Text('修改TODO'),
          content: TextFormField(
            controller: todoController,
          ),
          actions: <Widget>[
            TextButton(
              onPressed: () {
                Navigator.of(context).pop();
              },
              child: Text('取消'),
            ),
            ElevatedButton(
              onPressed: () {
                _editTodo(index, todoController.text);
                Navigator.of(context).pop();
              },
              child: Text('保存'),
            ),
          ],
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: SafeArea(
        child: Column(
          children: <Widget>[
            Expanded(
              child: ListView.builder(
                itemCount: _todoList.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text(_todoList[index]),
                    trailing: Row(
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        IconButton(
                          icon: Icon(Icons.edit),
                          onPressed: () {
                            _showEditDialog(index);
                          },
                        ),
                        IconButton(
                          icon: Icon(Icons.cancel),
                          onPressed: () {
                            _deleteTodo(index);
                          },
                        ),
                      ],
                    ),
                  );
                },
              ),
            ),
            Row(
              children: <Widget>[
                Expanded(
                  child: Padding(
                    padding: EdgeInsets.all(8.0),
                    child: TextFormField(
                      controller: _textEditingController,
                    ),
                  ),
                ),
                IconButton(
                  icon: Icon(Icons.add),
                  onPressed: () {
                    _addTodo();
                  },
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}