Flutter 开发学习笔记(2):第一个简单的Flutter项目(下)

文章目录

  • 前言
  • 官方Flutter案例
  • 侧边栏添加
    • 代码初始化
      • 展示效果
    • 子组件私有数据空间
      • 导航栏转为有状态Widget
      • setState
      • 手动转换页面
      • 实现效果
    • 响应式动态切换宽度
    • 添加收藏夹,跨Widget传数据
      • 实现效果
  • 完整代码
  • 后续进阶效果
  • 总结

前言

接着继续上一章的内容

官方Flutter案例

编写第一个 Flutter 应用

在这里插入图片描述

侧边栏添加

代码初始化

为了保证main.dart代码能正常跑通,我将完整的代码复制粘贴到这里

import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});@overrideWidget build(BuildContext context) {return ChangeNotifierProvider(create: (context) => MyAppState(),child: MaterialApp(title: 'Namer App',theme: ThemeData(useMaterial3: true,colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),),home: MyHomePage(),),);}
}//可通知视图修改的类
class MyAppState extends ChangeNotifier {//这个就相当于成员变量var current = WordPair.random();//手动声明回调函数,理论上来说,最好通过函数显性修改父节点属性void getNext(){current = WordPair.random();// 手动通知刷新视图元素notifyListeners();}//手动通知void notify(){notifyListeners();}var favorites = <WordPair>[];void toggleFavorite() {if (favorites.contains(current)) {favorites.remove(current);} else {favorites.add(current);}notifyListeners();}
}class MyHomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return Scaffold(body: Row(children: [SafeArea(child: NavigationRail(extended: false,destinations: [NavigationRailDestination(icon: Icon(Icons.home),label: Text('Home'),),NavigationRailDestination(icon: Icon(Icons.favorite),label: Text('Favorites'),),],selectedIndex: 0,onDestinationSelected: (value) {print('selected: $value');},),),Expanded(child: Container(color: Theme.of(context).colorScheme.primaryContainer,child: GeneratorPage(),),),],),);}
}class GeneratorPage extends StatelessWidget {@overrideWidget 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;@overrideWidget build(BuildContext context) {//获取父节点的主题final theme = Theme.of(context);//手动设置style,这个就是类似于css的样式传递final style = theme.textTheme.bodyMedium!.copyWith(color: theme.colorScheme.onPrimary,);return Card(color: theme.colorScheme.primary,child: Padding(padding: const EdgeInsets.all(8.0),child: Text(pair.asLowerCase,style: style),),);}
}

展示效果

由于官方的案例是按照横向布局来设置的,所以我们安卓实时效果不太一样。

在这里插入图片描述

子组件私有数据空间

我们目前的数据都是用MyApp的数据,但是我们不可能将所有的数据都放在父节点,子节点也应该有自己的私有数据空间。

在Flutter中,这称之为无状态Widget(StatelessWidget)和有状态widget(StatefulWidget)

导航栏转为有状态Widget

在这里插入图片描述
在这里插入图片描述

setState

在 Flutter 中使用 setState 时的 6 个简单技巧

在这里插入图片描述

手动转换页面

在这里插入图片描述

在return之前添加如下代码

Widget page;switch (selectedIndex) {case 0:page = GeneratorPage();break;case 1:page = Placeholder();break;default:throw UnimplementedError('no widget for $selectedIndex');}

在这里插入图片描述

实现效果

在这里插入图片描述

响应式动态切换宽度

将【Scaffold】替换为【Builder】,【Builder】替换为【LayoutBuilder】

在这里插入图片描述

添加收藏夹,跨Widget传数据

添加一个新的Widget

class FavoritesPage extends StatelessWidget {@overrideWidget 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),),],);}
}

在这里插入图片描述

实现效果

在这里插入图片描述

完整代码

import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});@overrideWidget build(BuildContext context) {return ChangeNotifierProvider(create: (context) => MyAppState(),child: MaterialApp(title: 'Namer App',theme: ThemeData(useMaterial3: true,colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),),home: MyHomePage(),),);}
}//可通知视图修改的类
class MyAppState extends ChangeNotifier {//这个就相当于成员变量var current = WordPair.random();//手动声明回调函数,理论上来说,最好通过函数显性修改父节点属性void getNext(){current = WordPair.random();// 手动通知刷新视图元素notifyListeners();}//手动通知void notify(){notifyListeners();}var favorites = <WordPair>[];void toggleFavorite() {if (favorites.contains(current)) {favorites.remove(current);} else {favorites.add(current);}notifyListeners();}
}class MyHomePage extends StatefulWidget {@overrideState<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {var selectedIndex = 0;@overrideWidget 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: [SafeArea(child: NavigationRail(extended: false,destinations: [NavigationRailDestination(icon: Icon(Icons.home),label: Text('Home'),),NavigationRailDestination(icon: Icon(Icons.favorite),label: Text('Favorites'),),],selectedIndex: selectedIndex,onDestinationSelected: (value) {setState(() {selectedIndex = value;print('selected: $selectedIndex');});},),),Expanded(child: Container(color: Theme.of(context).colorScheme.primaryContainer,child: page,),),],),);});}
}class FavoritesPage extends StatelessWidget {@overrideWidget 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),),],);}
}class GeneratorPage extends StatelessWidget {@overrideWidget 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;@overrideWidget build(BuildContext context) {//获取父节点的主题final theme = Theme.of(context);//手动设置style,这个就是类似于css的样式传递final style = theme.textTheme.bodyMedium!.copyWith(color: theme.colorScheme.onPrimary,);return Card(color: theme.colorScheme.primary,child: Padding(padding: const EdgeInsets.all(8.0),child: Text(pair.asLowerCase,style: style),),);}
}

后续进阶效果

进阶代码链接

在这里插入图片描述

总结

唉,该怎么说呢,但凡Avalonia或者MAUI对移动端的支持好一点,我也不至于学一个Flutter。但是没办法。我记得有个数据,有将近50%的移动端开发用的就是Flutter。Flutter和Avalonia用的都是自绘的方式,而MAUI用的却是原生映射的方式。所以会出现很多很多的Bug。MAUI+Blazor或许是个不错的解决方案,但是我还是累了,不想陪微软折腾了。过两年再看看好了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/782321.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单了解策略模式

什么是策略模式&#xff1f; 策略模式提供生成某一种产品的不同方式 Strategy策略类定义了某个各种算法的公共方法&#xff0c;不同的算法类通过继承Strategy策略类&#xff0c;实现自己的算法 Context的作用是减少客户端和Strategy策略类之间的耦合&#xff0c;客户端只需要…

UE4 面试题整理

1、new与malloc的区别 new&#xff1a; new首先会去调用operator new函数&#xff0c;申请足够的内存&#xff08;大多数底层用malloc实现&#xff09;&#xff0c;然后调用类型的构造函数来初始化变量&#xff0c;最后返回自定义类型的指针&#xff0c;delete先调用析构函数&…

设计模式之装饰模式精讲

概念&#xff1a;动态地给一个对象添加一些额外的职责。 装饰器模式侧重于在不改变接口的前提下动态地给对象添加新功能&#xff0c;保持对象结构的透明性&#xff0c;客户端无感知。 以一个咖啡制作和装饰的例子来帮助大家理解&#xff1a; public interface Coffee {double…

QT-自定义参数设计框架软件

QT-自定义参数设计框架软件 前言一、演示效果二、使用步骤1.应用进行参数注册2.数据库操作单例对象3.参数操作单例对象 三、下载链接 前言 常用本地数据参数通常使用的是xml等文本的格式&#xff0c;进行本地的数据参数的存储。这种参数的保存方式有个致命的一点&#xff0c;就…

YOLOv9改进策略 :主干优化 | ConvNeXtV2:适应自监督学习,让 CNN “再一次强大”?

💡💡💡本文改进内容:完全卷积掩码自编码器框架 ConvNeXt V2,它显著提高了纯convnet在各种识别基准上的性能,包括ImageNet分类,COCO目标检测和ADE20k分割。还提供了各种尺寸的预训练ConvNeXt v2模型,从而在ImageNet上具有76.7%精度的3.7M Atto model和88.9%精度的650…

zabbix主动发现,注册及分布式监控

主动发现 结果 主动注册 结果 分布式监控 服务机&#xff1a;132 代理机&#xff1a;133 客户端&#xff1a;135 代理机 数据库赋权&#xff1a; 代理机配置 网页上配置代理 客户端配置 网页上配置主机 重启代理机服务 网页效果

排序第五篇 归并排序

一 简介 归并排序(Merge Sort) 的基本思想是&#xff1a; 首先将待排序文件看成 n n n 个长度为1的有序子文件&#xff0c; 把这些子文件两两归并&#xff0c; 得到 n 2 \frac{n}{2} 2n​ 个长度为 2 的有序子文件&#xff1b; 然后再把这 n 2 \frac{n}{2} 2n​ 个有序的子…

基于Tampermonkey 实现自动答题和视频播放

目录 一、环境准备 二、下载Tampermonkey 三、安装脚本 四、启用脚本 一、环境准备 微软自带的 edge 浏览器(电脑端) 二、下载Tampermonkey 安装地址&#xff1a;Tampermonkey 篡改猴(油猴脚本) 下载完成会在浏览器拓展中自动生成一个插件&#xff0c;此时点击管理拓展&…

WIFI驱动移植实验:WIFI从路由器动态获取IP地址与联网

一. 简介 前面两篇文章&#xff0c;一篇文章实现了WIFI联网前要做的工作&#xff0c;另一篇文章配置了WIFI配置文件&#xff0c;进行了WIFI热点的连接。文章如下&#xff1a; WIFI驱动移植实验&#xff1a;WIFI 联网前的工作-CSDN博客 WIFI驱动移植实验&#xff1a;连接WIF…

每日面经分享(Spring Boot: part2 DAO层)

1. Spring Boot DAO层的作用 a. 封装数据访问逻辑&#xff1a;DAO层的主要责任是封装与数据访问相关的逻辑。负责处理与数据库的交互&#xff0c;包括数据的增删改查等操作。通过将数据访问逻辑统一封装在DAO层中&#xff0c;可以提高代码的可维护性和可重用性。 b. 解耦业务逻…

pytest--python的一种测试框架--request请求加入headers

一、request headers中的cookie和session机制的作用与区别 Cookie 和 Session 是两种在客户端和服务器之间保持状态的技术。HTTP 协议本身是无状态的&#xff0c;这意味着服务器无法从上一次的请求中保留任何信息到下一次请求。Cookie 和 Session 机制就是为了解决这个问题。 …

Python算法学习

一、排序 排序算法是指将一组数据按照某种规则重新排列&#xff0c;使得数据呈现出递增或递减的顺序。常见的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序等。 1.冒泡排序 解释&#xff1a; 冒泡排序通过不断交换相邻两个元素的位置&#xff0c;使…

KingSCADA|问题处理:数据输入后,数据已经写入,但SCADA界面显示为0问题。

哈喽&#xff0c;你好啊&#xff01;我是雷工&#xff01; 最近做KingSCADA项目遇到这么一个问题&#xff1a; KingSCADA系统和三菱的PLC通讯&#xff0c;当数值输入数据需要数据后&#xff0c;输入的数值点击确定按钮可以写入到PLC内&#xff0c;但是点完确定SCADA界面显示0&a…

神经网络 各个模块介绍(Pytorch 07)

一 网络层和块 单个神经网络&#xff08;1&#xff09;接受一些输入&#xff1b;&#xff08;2&#xff09;生成相应的标量输出&#xff1b;&#xff08;3&#xff09;具有一组相关 参数&#xff08;parameters&#xff09;&#xff0c;更新这些参数 可以优化某目标函数。 当…

CSS3 (一)

一、CSS3 2D转换 转换&#xff08;transform&#xff09;是CSS3中具有颠覆性的特征之一&#xff0c;可以实现元素的位移、旋转、缩放等效果。转换&#xff08;transform&#xff09;你可以简单理解为变形。 移动&#xff1a;translate 、旋转&#xff1a;rotate 、缩放&#xf…

MATLAB 点云随机渲染赋色(51)

MATLAB 点云随机渲染赋色(51) 一、算法介绍二、算法实现1.代码2.效果总结一、算法介绍 为点云中的每个点随机赋予一种颜色,步骤和效果如图: 1、读取点云 (ply格式) 2、随机为每个点的RGB颜色字段赋值 3、保存结果 (ply格式) 二、算法实现 1.代码 代码如下(示例):…

pytest--python的一种测试框架--pycharm创建项目并进行接口请求

前言 学习request的使用&#xff0c;在用之前&#xff0c;用官方文档提供的接口&#xff1a;https://api.github.com/events&#xff1b; ctrl鼠标左键可以进入被调用函数源码&#xff0c;可以看到第一个参数URL是必须参数&#xff0c;params是选填&#xff0c;**kwargs是关键…

嵌入式|蓝桥杯STM32G431(HAL库开发)——CT117E学习笔记15:PWM输出

系列文章目录 嵌入式|蓝桥杯STM32G431&#xff08;HAL库开发&#xff09;——CT117E学习笔记01&#xff1a;赛事介绍与硬件平台 嵌入式|蓝桥杯STM32G431&#xff08;HAL库开发&#xff09;——CT117E学习笔记02&#xff1a;开发环境安装 嵌入式|蓝桥杯STM32G431&#xff08;…

css3之2D转换transform

2D转换transform 一.移动&#xff08;translate)(中间用&#xff0c;隔开&#xff09;二.旋转&#xff08;rotate)&#xff08;有单位deg)1.概念2.注意点3.转换中心点&#xff08;transform-origin)&#xff08;中间用空格&#xff09;4.一些例子(css三角和旋转&#xff09; 三…

基于微信小程序医院挂号系统的设计与实现(论文+源码)_kaic

摘 要 进入21世纪网络和微信小程序得到了飞速发展&#xff0c;并和生活进行了紧密的结合。目前&#xff0c;网络的运行速度以达到了千兆&#xff0c;覆盖范围更是深入到生活中的脚脚落落。这就促使微信小程序的发展。微信小程序可以实现远程处理事务&#xff0c;远程提交工…