flutter写后感 构建您的第一个 Flutter 应用

最近在学flutter 以下以web前端视角对比看待

教程

codelabs.developers.google.com/codelabs/fl...

效果

代码

js 复制代码
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
import 'package:provider/provider.dart';

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

class MyApp extends StatelessWidget{
  const MyApp({super.key});
  @override
  Widget build(BuildContext context){
    return ChangeNotifierProvider(
      create: (context)=>MyAppState(),
      child:MaterialApp(
        title: "Namer App",
        theme:ThemeData(
          useMaterial3: true,
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.green)
        ),
        home: MyHomePage()
      )
    );
  }
}

class MyAppState extends ChangeNotifier{
  var current = WordPair.random();

  void getNext(){
    current = WordPair.random();
    notifyListeners();
  }

  var favorites = <WordPair>[];
  void toggleFavorite(){
    if(favorites.contains(current)){
      favorites.remove(current);
    }else{
      favorites.add(current);
    }
    notifyListeners();
  }

}

class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  var selectedIndex = 1;
  var selectedIndexInAnotherWidget =0;
  var indexInYetAnotherWidget = 42;
  var optionASelected = false;
  var optionBSelected = false;
  var loadingFromNetwork = false;

  @override
  Widget build(BuildContext context) {
    Widget page;
    switch (selectedIndex){
      case 0:
        page = GeneratorPage();
        break;
      case 1:
        page = FavoritesPage();
        break;
      default:
        throw UnimplementedError('no widget for $selectedIndex');
    }

    return LayoutBuilder(
      builder: (context, constraints) {
        return Scaffold(
          body:Row(
            children: [
              Expanded(
                child: SafeArea(
                  child: NavigationRail(
                    extended: constraints.maxWidth>=600,
                    destinations: [
                      NavigationRailDestination(
                        icon: Icon(Icons.home),
                        label: Text('Home')
                      ),
                      NavigationRailDestination(
                        icon: Icon(Icons.favorite),
                        label: Text('Favorites')
                      ),
                    ],
                    selectedIndex:selectedIndex,
                    onDestinationSelected: (value){
                      setState(() {
                        selectedIndex = value;
                      });
                    },
                  ),
                ),
              ),
              Expanded(
                child: Container(
                  color:Theme.of(context).colorScheme.primaryContainer,
                  child:page,
                )
              )
            ],
          )
        );
      }
    );
  }
}


class GeneratorPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();
    var pair = appState.current;

    IconData icon;
    if(appState.favorites.contains(pair)){
      icon = Icons.favorite;
    }else{
      icon = Icons.favorite_border;
    }

    return Center(
      child:Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          BigCard(pair: pair),
          SizedBox(
            height: 10,
          ),
          Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              ElevatedButton.icon(
                onPressed: (){
                  appState.toggleFavorite();
                },
                icon:Icon(icon),
                label: Text('Like')
              ),
              SizedBox(width: 10,),
              ElevatedButton(
                onPressed: (){
                  appState.getNext();
                },
                child: Text('Next'),
              )
            ],
          )
        ],
      )
    );
  }
}


class BigCard extends StatelessWidget {
  const BigCard({
    super.key,
    required this.pair,
  });

  final WordPair pair;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final style = theme.textTheme.displayMedium!.copyWith(
      color:theme.colorScheme.onPrimary
    );
    return Card(
      color: theme.colorScheme.primary,
      child: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Text(
          pair.asLowerCase,
          style:style,
          semanticsLabel: "${pair.first} ${pair.second}",
        ),
      ),
    );
  }
}

class FavoritesPage extends StatefulWidget {
  @override
  State<FavoritesPage> createState() => _FavoritesPageState();
}

class _FavoritesPageState extends State<FavoritesPage> {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();
    if(appState.favorites.isEmpty){
      return Center(
        child: Text('No favorites yet.'),
      );
    }
    return ListView(
      children: [
        Padding(
          padding: const EdgeInsets.all(20),
          child: Text('You have '
          '${appState.favorites.length} favorites:'),
        ),
        for (var pair in appState.favorites)
          ListTile(
            leading: Icon(Icons.favorite),
            title: Text(pair.asLowerCase),
          )
      ],
    );
  }
}

功能

  1. 启动 flutter run
    package script vue-cli vite webpack dev-server
  2. 入口 runApp
    createRoot new Vue createApp 没有css html xml dsl形式 没有mount
  3. app StatelessWidget或者StatefulWidget
    类组件 React.component h
  4. render Widget build(BuildContext context) {
    setup render template
  5. 组件 结构样式逻辑一切皆组件 混在一起 没有css html xml dsl形式
    html css js ts
    vue template script style
    react jsx tsx className style
  6. 状态管理
    ChangeNotifierProvider ChangeNotifier->notifyListeners context.watch
    react context 纯传递 functionCompnent定义数据与方法再传递进去
    createContext context.Provier setState useContext vue inject provide 纯传递 pinia defineStore 直接引用 react类组件与flutter类似 要手动触发更新 notifyListeners setState 手动挡
    vue响应式不需要传递修改值即可 自动挡
  7. 组件库
    官方根据android与ios风格 Material与cupertino 平台->官方 二选一 vue react ui库 自行找组件库 自由选择

组件

  1. StatelessWidget
  2. ChangeNotifierProvider ChangeNotifier
  3. MaterialApp ThemeData
  4. StatefulWidget State
  5. LayoutBuilder
  6. Scaffold SafeArea
  7. Container Row Column Expanded Center SizedBox Padding
  8. NavigationRail NavigationRailDestination
  9. ElevatedButton Icon Card Text
  10. ListView ListTile

思想

一切皆组件无限嵌套

组件多级封装 组件语法糖 比如 SizedBox->Container Column|Row->Center

组件更新

1.ChangeNotifier->notifyListeners();

2.StatefulWidget->setState

第一反应

语言感觉不上不下 优点 语法糖 比如具名参数 空判断 assert性能优化 官方主导统一库与工具链 缺点 落后写法 比如类型后置 没有dsl 嵌套太多 太多分层组件 面向对象太多继承 不太简洁

相关推荐
XI锐真的烦1 小时前
Flutter Windows 下“Running Gradle task ‘assembleDebug‘...” 卡住一整天的终极解决办法
windows·flutter
苦逼的搬砖工10 小时前
基于 easy_rxdart 的轻量响应式与状态管理架构实践
android·flutter
SoaringHeart11 小时前
Flutter组件封装:标签拖拽排序 NDragSortWrap
前端·flutter
天天开发14 小时前
Flutter每日库: local_auth本地设备验证插件
flutter
天天开发15 小时前
Flutter每日库: logger自定义日志格式并输出到文件
flutter
美摄科技15 小时前
为什么选择Flutter美颜SDK?
flutter
程序员老刘1 天前
跨平台开发地图:客户端技术选型指南 | 2025年11月 |(Valdi 加入战场)
flutter·react native·客户端
西西学代码1 天前
Flutter---Listview横向滚动列表(2)
linux·运维·flutter
未来猫咪花1 天前
🔥 神奇的 Dart Zone 机制
flutter