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 嵌套太多 太多分层组件 面向对象太多继承 不太简洁

相关推荐
yuanlaile4 小时前
2026年全新Flutter 跨平台开发全栈学习资料整理
flutter·getx·鸿蒙 next·flutter开发鸿蒙·flutter入门实战·flutter全栈
恋猫de小郭14 小时前
Genkit Dart 1.0 发布,Flutter 原生的 AI Agent 终于完整了
android·前端·flutter
第10086个小白15 小时前
flutter桌面端打包方式(Inno Setup Compiler)版本
前端·flutter
陆断枫1 天前
Flutter 3.47 动画引擎盘点:Impeller 全平台,和那些"新特性"
flutter
程序员老刘1 天前
Flet 1.0 思路很好,可惜来晚了
flutter·ai编程·客户端
m0_738185822 天前
Flutter 鸿蒙化实战:qr_code_scanner_plus 适配 OpenHarmony,二维码扫描
flutter·华为·harmonyos·鸿蒙
恋猫de小郭2 天前
Flutter + EmbeddingGemma 2,谷歌发布完全端侧的 AI Edge Foresight
android·前端·flutter
君赏2 天前
基于 FlutterPatch 快速接入 Flutter 热更新
flutter
律宏阔2 天前
Dart FFI 内存管理:用 using + Arena 替代嵌套 try-finally
前端·flutter
律宏阔2 天前
Flutter 调用 Go:从 c-shared + ffigen 到 @Native + Native Assets 踩坑记录
前端·flutter