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

相关推荐
不爱吃糖的程序媛28 分钟前
Flutter 三方库鸿蒙(OHOS)适配分析流程
flutter·华为·harmonyos
mocoding42 分钟前
我这样用鸿蒙化Flutter三方库file_selector实现单图片和多图片选择
flutter·华为·harmonyos
牛马1111 小时前
flutter Riverpod 中的 overrideWith
android·java·flutter
牛马1111 小时前
flutter riverpod AsyncNotifier 和 Notifier
flutter
不爱吃糖的程序媛2 小时前
如何判断Flutter三方库是否需要OHOS适配开发?附完整适配指导
flutter·华为·harmonyos
kirk_wang2 小时前
Flutter艺术探索-Flutter渲染管道:RenderObject与Layer深度解析
flutter·移动开发·flutter教程·移动开发教程
微祎_3 小时前
Flutter for OpenHarmony:构建一个 Flutter 点击狂热游戏,深入解析响应式交互、动态反馈与高性能状态管理
flutter·游戏·交互
晚霞的不甘3 小时前
Flutter for OpenHarmony实现高性能流体粒子模拟:从物理引擎到交互式可视化
前端·数据库·经验分享·flutter·microsoft·计算机视觉
晚霞的不甘3 小时前
Flutter for OpenHarmony 流体气泡模拟器:用物理引擎与粒子系统打造沉浸式交互体验
前端·flutter·ui·前端框架·交互
一起养小猫3 小时前
Flutter for OpenHarmony 实战:打造功能完整的记账助手应用
android·前端·flutter·游戏·harmonyos