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

相关推荐
用户965597361901 天前
Provider vs Bloc vs GetX vs Riverpod:Flutter 状态管理方案怎么选?
flutter
恋猫de小郭1 天前
Flutter Patchwork,不用 Fork 改依赖包源码的第三方工具
android·前端·flutter
程序员老刘2 天前
跑分第一的编程大模型,我为啥不用?
flutter·ai编程·vibecoding
恋猫de小郭2 天前
苹果 AirPods 协议,Android 也可以使用完整版 AirPods 能力
android·前端·flutter
张风捷特烈3 天前
Flutter 类库大揭秘#01 | path_provider架构与设计
android·flutter
恋猫de小郭5 天前
Android 限制侧载新进展,谷歌联合国内厂商推验证计划
android·前端·flutter
恋猫de小郭5 天前
解读 Android 17 全新内存限制,有没有“豁免”后门?
android·前端·flutter
程序员老刘7 天前
跨平台开发地图 | 2026年6月
flutter·ai编程·客户端
悟空瞎说8 天前
Flutter 架构详解:新手必懂底层原理
flutter
SoaringHeart8 天前
Flutter最佳实践:IM聊天文字链接自动识别跳转
前端·flutter