Flutter项目开发实战(AI助学)课件 5Flutter路由与状态管理_第1页
Flutter项目开发实战(AI助学)课件 5Flutter路由与状态管理_第2页
Flutter项目开发实战(AI助学)课件 5Flutter路由与状态管理_第3页
Flutter项目开发实战(AI助学)课件 5Flutter路由与状态管理_第4页
Flutter项目开发实战(AI助学)课件 5Flutter路由与状态管理_第5页
已阅读5页,还剩38页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Flutter路由与状态管理Flutter项目开发实战(AI助学)05Flutter+AI目录02状态管理01路由路由(Route)是管理应用页面导航和状态的机制。通过路由,用户可以在不同的屏幕(页面)之间切换,并在这个过程中传递数据、保持状态。Flutter提供了多种路由管理方式,从基础的命令式路由到高级的命名路由,适用于不同规模和复杂度的应‍用。在使用路由时通常需要先定义路由表,然后使用Navigator类实现路由之间的跳转,路由跳转的时候也可以携带参数,跳转完成后可添加路由回调函数。5.1路由5.1.1路由表路由表(RouteTable)是一种预定义的路由配置方式,通过将路由名称映射到对应的页面组件,实现更结构化的导航管理。它是命名路由的核心机制,使导航逻辑更加集中和可维‍护。路由表是一个Map<String,WidgetBuilder>类型的对象,用于存储路由名称和对应的页面构建函‍数。定义路由表的方式如‍下。finalMap<String,WidgetBuilder>routes={'/':(context)=>HomePage(),'/second':(context)=>SecondPage(),'/third':(context)=>ThirdPage(),};定义路由表01默认路由是指应用启动时显示的第一个页面,可以通过initialRoute属性来设‍置。设置初始路由025.1.1路由表使用路由表进行页面跳转时,可以使用Navigator.pushNamed()方法,例如,使用Navigator.pushNamed()方法根据路由名称“/second”跳转到第2页,代码如‍下。Navigator.pushNamed(context,'/second');使用路由03例如,定义首页、第2页和第3页三个路由,分别对应“/”“/second”“/third”3个路由地址,初始路由为首页的路由,单击首页的“下一页”按钮页面跳转至第2页;再次单击“下一页”按钮,页面跳转至第3页;单击“返回”按钮,页面返回至第2页,代码如‍下。import'package:flutter/material.dart';voidmain(){finalMap<String,WidgetBuilder>routes={'/':(context)=>HomePage(),'/second':(context)=>SecondPage(),'/third':(context)=>ThirdPage(),};runApp(MaterialApp(initialRoute:'/',routes:routes));}classHomePageextendsStatelessWidget{constHomePage({super.key});@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('首页')),body:Center(child:ElevatedButton(onPressed:(){Navigator.pushNamed(context,'/second');},child:Text('下一页'),),),);}}5.1.1路由表classSecondPageextendsStatelessWidget{constSecondPage({super.key});@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('第2页')),body:Center(child:ElevatedButton(onPressed:(){Navigator.pushNamed(context,'/third');},child:Text('下一页'),),),);}}classThirdPageextendsStatelessWidget{constThirdPage({super.key});@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('第3页')),body:Center(child:ElevatedButton(onPressed:(){Navigator.pop(context);},child:Text('返回'),),),);}}图首页内容图第2页内容图第3页内容5.1.2命令式路由命令式路由(ImperativeRouting)是一种通过显式调用应用程序接口(ApplicationProgramInterface,API)来控制页面导航的方式。它基于Navigator类提供的方法(如push()、pop()),直接操作路由栈,实现页面的跳转、返回和参数传递。这种方式直观且灵活,适合中小型应用或简单导航场‍景。Navigator.push()是Flutter中用于实现页面跳转的一种命令式路由方法,该方法接收context上下文和MaterialPageRoute()方法这两个参数,MaterialPageRoute()方法接收build属性作为参数,对应的值为包含context上下文参数的回调函数,用于将新页面推入导航‍栈。例如,定义HomePage和SecondPage两个页面,默认打开首页,点击首页中的“跳转到第2页”按钮,页面会跳转到第2页并展示“这是第2页”的文案,代码如下。Navigator.push()01Navigator.pop()方法用于从导航栈中移除当前页面,并返回上一个页面。它接收context上下文作为参‍数。例如,定义HomePage和SecondPage两个页面,默认打开首页,点击首页中的“跳转到第2页”按钮,页面会跳转到第2页,点击第2页中的“返回首页”按钮,Navigator.pop()方法会将当前页面从导航栈中移除,并返回首页,代码如‍下。Navigator.pop()025.1.2命令式路由代码如下:import'package:flutter/material.dart';voidmain(){runApp(MaterialApp(home:HomePage()));}classHomePageextendsStatelessWidget{constHomePage({super.key});@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('首页')),body:Center(child:ElevatedButton(onPressed:(){Navigator.push(context,MaterialPageRoute(builder:(context)=>SecondPage()),);},child:Text('跳转到第2页'),),),);}}classSecondPageextendsStatelessWidget{constSecondPage({super.key});@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('第2页')),body:Center(child:Text('这是第2页')),);}}图首页内容图第2页内容5.1.2命令式路由代码如下:import'package:flutter/material.dart';voidmain(){runApp(MaterialApp(home:HomePage()));}classHomePageextendsStatelessWidget{constHomePage({super.key});@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('首页')),body:Center(child:ElevatedButton(onPressed:(){Navigator.push(context,MaterialPageRoute(builder:(context)=>SecondPage()),);},child:Text('跳转到第2页'),),),);}}classSecondPageextendsStatelessWidget{constSecondPage({super.key});@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('第2页')),body:Center(child:ElevatedButton(onPressed:(){Navigator.pop(context);},child:Text('返回首页'),),),);}}5.1.2命令式路由运行后,页面中默认显示首页的内容,如图所示;点击“跳转到第2页”按钮,页面跳转到第2页,显示第2页的内容,如图所示;点击第2页中的“返回首页”按钮,页面跳转回首‍页。图首页内容图第2页内容5.1.3命名路由与命令式路由不同,命名路由不需要手动创建Route对象,而是通过路由名称来进行页面跳转。它接收两个参数,第1个参数仍为上下文(context),第2个参数为路由表中的路由路径。它将路由路径与页面组件解耦,使导航逻辑更加集中和可维护,使用方法如‍下。//需要在路由表中定义好/second路由,如果路由表中未定义,则跳转不会生效Navigator.pushNamed(context,'/second');命名路由(NamedRoutes)是一种更加简洁和直观的路由方式,通过在MaterialApp()中定义路由表来实现页面的跳‍转。5.1.4路由回调路由回调(RouteCallback)是一种机制,用于处理路由跳转过程中的各种状态变化,它允许开发者在页面跳转的特定阶段执行自定义代码,常用于数据传递、状态保存、权限验证等操作。在页面跳转时,有时需要传递参数到目标页面,并在目标页面处理完后将结果返回。可以通过Navigator.push()方法来实现导航结果回调。实现方式有await回调和then()回调两种,代码如‍下。导航结果回调01路由守卫(RouteGuards)是一种机制,用于在路由导航发生前执行验证逻辑,控制是否允许用户访问特定页面。它类似于网页开发中的路由拦截器,常用于实现权限验证、登录状态检查、数据预处理等功‍能。在Flutter中,可以通过onGenerateRoute:()方法拦截路由,该方法有一个参数,包含当前的路由信息。路由守卫02//方式一:使用awaitfinalresult=awaitNavigator.push(context,MaterialPageRoute(builder:(context)=>SecondPage()),);print('返回结果:$result');//方式二:使用then()Navigator.push(context,MaterialPageRoute(builder:(context)=>SecondPage()),).then((result){if(result!=null){//处理返回结果}});5.1.4路由回调MaterialApp(onGenerateRoute:(settings){//检查是否需要身份验证if(=='/profile'&&!isLoggedIn){returnMaterialPageRoute(builder:(context)=>LoginPage());}//正常导航if(=='/profile'){returnMaterialPageRoute(builder:(context)=>ProfilePage());}//默认处理returnnull;},);可通过MaterialPageRoute()方法返回目标路由的页面,使用方法如‍下。onUnknownRoute:()方法用于处理未知的路由,当用户访问一个未定义的路由时,会进入该路由守卫,可以定义一个未知页面(UnknownPage),当访问的路由不在路由表中时,页面会跳转到该未知页‍面。5.1.4路由回调路由生命周期(RouteLifecycle)描述了路由从创建到销毁的整个过程,以及在这个过程中可以响应的关键事件。理解路由生命周期对于页面状态管理、资源释放、动画控制等场景至关重‍要。路由生命周期03(1)路由生命周期方法路由生命周期主要分为路由创建与插入、路由可见性变化和路由移除与销毁3个阶段,在不同的阶段会执行不同的方法,说明如表所‍示。阶段方法描述路由创建与插入createRoute()创建路由实例(由框架调用)install()将路由安装到导航器中didPush()在路由被推入导航栈时调用路由可见性变化didChangeNext()相邻路由变化时调用(如被新路由覆盖或覆盖消失)didChangePrevious()前一个路由变化时调用isCurrent判断当前路由是否为栈顶可见路由路由移除与销毁didPop()路由被弹出时调用dispose()路由被销毁前清理资源表路由生命周期不同阶段的方法5.1.4路由回调(2)监听路由生命周期Flutter提供了RouteAware和NavigatorObserver用于监听路由生命周期的变化,其中RouteAware可监听特定路由的生命周期事件,NavigatorObserver可监听全局路由变‍化。例如,使用RouteAware监听首页路由的生命周期,当首页被加载时页面上会显示“页面状态:被推入”,当离开页面时页面会显示“页面状态:被覆盖”,当重新进入页面时页面会显示“页面状态:重新可见”。代码如‍下。import'package:flutter/material.dart';//全局路由观察者finalRouteObserver<PageRoute>routeObserver=RouteObserver<PageRoute>();voidmain(){runApp(constMyApp());}classMyAppextendsStatelessWidget{constMyApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'RouteAware示例',navigatorObservers:[routeObserver],//注册路由观察者initialRoute:'/',5.1.4路由回调onGenerateRoute:(settings){switch(){case'/':returnMaterialPageRoute(builder:(context)=>HomePage());case'/second':returnMaterialPageRoute(builder:(context)=>SecondPage());default:returnnull;}},);}}classHomePageextendsStatefulWidget{constHomePage({super.key});@overrideState<HomePage>createState()=>_HomePageState();}class_HomePageStateextendsState<HomePage>withRouteAware{String_visibilityStatus='可见';@overridevoiddidChangeDependencies(){super.didChangeDependencies();//订阅当前路由的生命周期事件routeObserver.subscribe(this,ModalRoute.of(context)asPageRoute);}@overridevoiddispose(){//取消订阅以避免内存泄漏routeObserver.unsubscribe(this);super.dispose();}//路由被推入时调用@overridevoiddidPush(){print('HomePage:didPush');_updateStatus('被推入');}//新路由被推入,当前页面被覆盖时调用@overridevoiddidPushNext(){print('HomePage:didPushNext');_updateStatus('被覆盖');}5.1.4路由回调//前一个路由被弹出,当前页面重新可见时调用@overridevoiddidPopNext(){print('HomePage:didPopNext');_updateStatus('重新可见');}//路由被弹出时调用@overridevoiddidPop(){print('HomePage:didPop');_updateStatus('被弹出');}void_updateStatus(Stringstatus){setState((){_visibilityStatus=status;});}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('首页')),body:Center(child:Column(mainAxisAlignment:MainAxisAlignment.center,children:[Text('页面状态:$_visibilityStatus'),constSizedBox(height:16),ElevatedButton(onPressed:(){Navigator.pushNamed(context,'/second');},child:Text('跳转到第2页'),),],),),);}}classSecondPageextendsStatelessWidget{constSecondPage({super.key});@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('第2页')),body:Center(child:ElevatedButton(onPressed:(){Navigator.pop(context);},child:Text('返回首页'),),),);}}5.1.4路由回调运行后,页面中默认显示“页面状态:被推入”,如图所示;点击“跳转到第2页”按钮,页面跳转至第2页;点击第2页中的“返回首页”按钮,页面会跳转回首页,此时页面中显示“页面状态:重新可见”,如图所‍示。图初次加载首页图重新回到首页5.1.4路由回调使用NavigatorObserver监听全局路由变化的方法与RouteAware类似,只是将继承的类改为NavigatorObserver类,同时路由每个阶段的方法变成了didPush()、didPop()、didReplace()和didRemove(),分别对应路由被推入、路由被弹出、路由被替换和路由被移除几个阶段,使用方法如‍下。classMyRouteObserverextendsNavigatorObserver{@overridevoiddidPush(Route<dynamic>route,Route<dynamic>?previousRoute){print('路由被推入:${}');}@overridevoiddidPop(Route<dynamic>route,Route<dynamic>?previousRoute){print('路由被弹出:${}');}@overridevoiddidReplace({Route<dynamic>?newRoute,Route<dynamic>?oldRoute}){print('路由被替换:${oldRoute?.}→${newRoute?.}');}@overridevoiddidRemove(Route<dynamic>route,Route<dynamic>?previousRoute){print('路由被移除:${}');}}//在MaterialApp()中注册MaterialApp(navigatorObservers:[MyRouteObserver()],home:MyPage(),);5.1.5路由传参路由传参是在页面(路由)之间传递数据的机制。合理的参数传递方式能提升代码的可维护性和类型安全性。路由传参分为传递参数和接收参数两个阶段,常见的路由传参包括命名路由传参和命令式路由传参两‍种。命名路由传参时,可通过路由跳转的arguments参数传递多个参数。在目标页面中,可通过ModalRoute.of(context)?.settings.arguments获取传入的参数。使用方法如‍下。命名路由传参01///传递参数Navigator.pushNamed(context,'/detail',arguments:{'id':123,'title':'商品详情'},);//接收参数classDetailPageextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){//获取传递的参数finalargs=ModalRoute.of(context)?.settings.argumentsasMap;finalitemId=args['id'];finaltitle=args['title'];returnScaffold(appBar:AppBar(title:Text(title)),body:Text('ItemID:$itemId'),);}}5.1.5路由传参命令式路由传参是在MaterialPageRoute()方法的目标页面构造函数中传递参数,同时需要在目标页面构造函数中定义参数类型和接收参数的变量名。示例代码如‍下。命令式路由传参02Navigator.push(context,MaterialPageRoute(builder:(context)=>SecondPage(initialValue:'初始值'),),);classSecondPageextendsStatelessWidget{finalStringinitialValue;SecondPage({requiredthis.initialValue});}目录02状态管理01路由状态管理(StateManagement)是指管理应用中数据(状态)的变化,并将这些变化高效、可预测地反映到页面上。合理的状态管理能提升代码的可维护性、可测试性和性‍能。5.2状态管理状态管理一般分为局部状态管理和全局状态管理,局部状态管理指组件内部的状态管理,一般使用StatefulWidget来实现,适用于简单、独立的页面元素,单元3已经介绍过,这里不赘述;全局状态管理是指状态需要在多个组件之间共享,当状态发生变化时,所有用到该状态的组件都会实时更新页面。5.2.1安装provider库provider是官方推荐的状态管理库,它基于依赖注入(DependencyInjection)和变更通知(ChangeNotifications)机制,能够帮助开发者高效管理应用状态并在Widget树中共享数据。要使用provider库,需要先安装,安装步骤如‍下。01在pubspec.yaml文件中添加插件打开项目根目录下的pubspec.yaml文件,并在dependencies下添加“provider:^6.0.5”这行代码,表示安装6.0.5版本或更高版本的provider库。dependencies:flutter:sdk:flutterprovider:^6.0.5#版本号可根据实际情况更新02安装插件在VSCode中保存pubspec.yaml文件后会自动安装插件,如图所示。图VSCode自动安装插件5.2.1安装provider库图插件安装成功安装成功后会在输出窗口中输出安装成功的提示,如左图所‍示。也可以打开VSCode的终端窗口,然后执行“flutterpubget”命令来手动安装插件,如右图所‍示。图手动安装插件在使用provider库之前,还需要创建一个继承自ChangeNotifier(变更通知器)的类来管理状态数据,状态数据的改动都必须在这个类中实‍现。例如,创建Counter类继承自ChangeNotifier。该类包含一个私有变量_count和一个get()方法用于获取_count的值,以及一个increment()方法用于增加计数值。当调用increment()方法时,会调用notifyListeners()方法通知所有监听器状态发生了变化,代码如‍下。5.2.2准备状态数据import'package:flutter/material.dart';classCounterwithChangeNotifier{int_count=0;intgetcount=>_count;voidincrement(){_count++;notifyListeners();}}5.2.3使用状态数据01在顶层提供状态在MaterialApp之前使用ChangeNotifierProvider()方法提供状态,该方法的第1个参数是create,该参数的值是一个回调函数,提供Counter类中的全局状态,代码如‍下。voidmain(){runApp(ChangeNotifierProvider(create:(context)=>Counter(),//创建状态实例child:MyApp(),),);}02在组件中使用状态在组件中使用Provider.of<T>(context)来获取状态,此处的T代表实际的类,此处代表的是Count类,返回的是Counter类中定义的状态和方法,代码如‍下。classMyHomePageextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){

//获取状态finalcounter=Provider.of<Counter>(context);

returnElevatedButton(onPressed:()=>{},child:Text('Count:${counter.count}'),//使用状态值);}}5.2.2准备状态数据在使用provider库之前,还需要创建一个继承自ChangeNotifier(变更通知器)的类来管理状态数据,状态数据的改动都必须在这个类中实‍现。例如,创建Counter类继承自ChangeNotifier。该类包含一个私有变量_count和一个get()方法用于获取_count的值,以及一个increment()方法用于增加计数值。当调用increment()方法时,会调用notifyListeners()方法通知所有监听器状态发生了变化,代码如‍下。import'package:flutter/material.dart';classCounterwithChangeNotifier{int_count=0;intgetcount=>_count;voidincrement(){_count++;notifyListeners();}}5.2.3使用状态数据01在顶层提供状态在MaterialApp之前使用ChangeNotifierProvider()方法提供状态,该方法的第1个参数是create,该参数的值是一个回调函数,提供Counter类中的全局状态,代码如‍下。voidmain(){runApp(ChangeNotifierProvider(create:(context)=>Counter(),//创建状态实例child:MyApp(),),);}02在组件中使用状态在组件中使用Provider.of<T>(context)来获取状态,此处的T代表实际的类,此处代表的是Count类,返回的是Counter类中定义的状态和方法,代码如‍下。classMyHomePageextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){finalcounter=Provider.of<Counter>(context);//获取状态

returnElevatedButton(onPressed:()=>{},child:Text('Count:${counter.count}'),//使用状态值);}}当需要更改状态数据时,可通过调用状态管理类中定义的方法实现。以Counter类为例,只需调用其increment()方法即可修改全局状态,代码如‍下。5.2.4更改状态数据classMyHomePageextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){finalcounter=Provider.of<Counter>(context);//获取状态

returnElevatedButton(onPressed:()=>counter.increment(),//调用状态方法,child:Text('Count:${counter.count}'),//使用状态值);}}5.2.5监听状态数据修改全局状态后,组件中的状态并不会实时更新,需要使用Consumer组件监听状态数据的变化,并在状态变化时更新页‍面。Consumer组件提供了builder:()方法,该方法有counter参数,用于获取Counter类中的全局状态和方法,代码如‍下。Consumer<Counter>(builder:(context,counter,child){returnText('当前计数:${counter.count}');},);在上述代码中,Consumer组件会监听Counter类的变化,当Counter类的状态发生变化时,会调用builder()方法来更新页‍面。

【动手工坊】仿京东App—搭建个人中心及订单列表页面本单元动手工坊的主要任务是完成个人中心页面(即“我的”页面)及订单列表页面的搭建,分为3个步骤,分别是搭建个人中心页面布局、搭建订单列表页面布局、模拟个人中心数‍据。1.搭建个人中心页面布局点击底部“我的”图标时会进入个人中心页面,该页面顶部展示用户头像、用户昵称和用户会员等级信息,进入App时默认处于登录状态。页面中间展示一些页面的快捷入口,包括我的订单、地址管理、我的收藏、优惠券和联系客服等。点击“我的订单”右侧的“>”按钮跳转到订单列表页面,展示已经生成的订单信息。点击“地址管理”右侧的“>”按钮会跳转到收货地址管理页面,展示已经添加的收货地址信息。其他页面快捷入口的跳转暂未实现,仅做模拟展示,如图5.23所‍示。图个人中心页面

个人中心页面文件(位置:商业案例/jd_mall_app/lib/pages/profile_page.dart)代码如下所‍示。//个人中心页面文件//展示用户信息、订单列表页面快捷入口和常用页面快捷入口import'package:flutter/material.dart';import'package:provider/provider.dart';import'../data/mock_profile.dart';import'../provider/user_provider.dart';import'order_list_page.dart';import'address_manage_page.dart';classJDProfilePageextendsStatelessWidget{constJDProfilePage({super.key});//显示提示消息//[context]上下文//[msg]提示消息内容void_showSnackBar(BuildContextcontext,Stringmsg){ScaffoldMessenger.of(context).showSnackBar(SnackBar(content:Text(msg),duration:constDuration(milliseconds:800)),);}@overrideWidgetbuild(BuildContextcontext){finaluser=context.watch<UserProvider>().user;//用户信息未加载时显示加载指示器if(user==null){returnconstScaffold(body:Center(child:CircularProgressIndicator()));}【动手工坊】仿京东App—搭建个人中心及订单列表页面returnScaffold(//顶部应用栏appBar:AppBar(title:constText('我的'),backgroundColor:Colors.red,foregroundColor:Colors.white,elevation:0,),backgroundColor:constColor(0xFFF5F5F5),body:ListView(children:[//顶部渐变背景+用户信息Container(decoration:constBoxDecoration(gradient:LinearGradient(colors:[Colors.red,Color(0xFFFF6A00)],begin:Alignment.topLeft,end:Alignment.bottomRight,),),padding:constEdgeInsets.symmetric(vertical:32,horizontal:16),child:Row(children:[//用户头像CircleAvatar(radius:36,backgroundImage:AssetImage(user.avatar),),constSizedBox(width:18),//用户信息Column(crossAxisAlignment:CrossAxisAlignment.start,children:[//用户昵称Text(,style:constTextStyle(color:Colors.white,fontSize:22,fontWeight:FontWeight.bold,),),constSizedBox(height:8),Container(//用户等级标签padding:constEdgeInsets.symmetric(horizontal:10,vertical:3,),decoration:BoxDecoration(color:Colors.yellow.shade700,borderRadius:BorderRadius.circular(14),boxShadow:[BoxShadow(color:Colors.black12,blurRadius:4),],),【动手工坊】仿京东App—搭建个人中心及订单列表页面【动手工坊】仿京东App—搭建个人中心及订单列表页面child:Text(

user.level,style:constTextStyle(color:Colors.white,fontSize:13,),),),],),],),),//订单列表页面快捷入口区域Card(margin:constEdgeInsets.fromLTRB(14,18,14,0),shape:RoundedRectangleBorder(borderRadius:BorderRadius.circular(14),),elevation:4,child:Column(children:[//我的订单标题行ListTile(leading:Icon(IconData(0xe8b8,fontFamily:'MaterialIcons'),color:Colors.red,),title:constText('我的订单',style:TextStyle(fontWeight:FontWeight.bold),),trailing:constIcon(Icons.chevron_right),onTap:(){Navigator.push(context,MaterialPageRoute(builder:(context)=>constOrderListPage(),),);},),constDivider(height:1),//订单状态快捷入口Padding(padding:constEdgeInsets.symmetric(horizontal:8,vertical:10,),child:Row(mainAxisAlignment:MainAxisAlignment.spaceAround,children:orderEntries.map((item){returnGestureDetector(onTap:()=>_showSnackBar(context,'点击了${item['label']}'),child:Column(children:[Icon(IconData(item['icon'],fontFamily:'MaterialIcons',),color:Colors.red,size:28,),constSizedBox(height:4),Text(item['label'],style:constTextStyle(fontSize:12),),],),);}).toList(),),),],),),【动手工坊】仿京东App—搭建个人中心及订单列表页面

//常用页面快捷入口区域Card(margin:constEdgeInsets.fromLTRB(14,18,14,0),shape:RoundedRectangleBorder(borderRadius:BorderRadius.circular(14),),elevation:4,child:Column(children:[//常用页面快捷入口列表for(inti=0;i<commonEntries.length;i++)...[ListTile(leading:Icon(IconData(commonEntries[i]['icon'],fontFamily:'MaterialIcons',),color:Colors.red,),title:Text(commonEntries[i]['label']),trailing:constIcon(Icons.chevron_right),

onTap:(){//地址管理功能,点击跳转到收货地址管理页面if(commonEntries[i]['label']=='地址管理'){Navigator.push(context,MaterialPageRoute(builder:(context)=>constAddressManagePage(),),);}else{//其他功能显示提示消息_showSnackBar(context,'点击了${commonEntries[i]['label']}');}},),//分隔线(最后一项不显示)if(i!=commonEntries.length-1)constDivider(height:1,indent:16,endIndent:16),],],),),],),);}}用户状态管理文件(位置:商业案例/jd_mall_app/lib/provider/profile_page.dart)代码如下所‍示。//用户状态管理文件//负责用户数据的加载和管理import'package:flutter/material.dart';import'../model/user.dart';import'../data/mock_profile.dart'asmock;///用户状态管理类///使用provider模式管理用户数据classUserProviderwithChangeNotifier{///当前用户信息User?_user;///获取当前用户信息User?getuser=>_user;///加载用户数据///在实际应用中,这里应该从数据库或API获取用户信息///目前使用模拟数据voidloadUser(){_user=mock.user;notifyListeners();}}【动手工坊】仿京东App—搭建个人中心及订单列表页面仿京东App开发精讲

点击“我的订单”右侧的“>”按钮会跳转到订单列表页面,展示已经生成的订单信息,包含商品名称、总价和下单时间等,订单列表中的信息不支持修改,如图5.24所‍示。订单列表页面文件(位置:商业案例/jd_mall_app/lib/pages/order_list_page.dart)代码如下所‍示。2.搭建订单列表页面布局【动手工坊】仿京东App—搭建个人中心及订单列表页面//订单列表页面文件//展示用户的所有订单信息import'package:flutter/material.dart';import'package:provider/provider.dart';import'../provider/order_provider.dart';import'../model/order.dart';import'../model/cart_item.dart';//订单列表页面组件//展示用户的所有订单,按时间倒序排列classOrderListPageextendsStatelessWidget{constOrderListPage({super.key});@overrideWidgetbuild(BuildContextcontext){finalorders=context.watch<OrderProvider>().orders;//获取订单列表returnScaffold(//顶部应用栏appBar:AppBar(title:constText('订单列表'),backgroundColor:Colors.red,foregroundColor:Colors.white,automaticallyImplyLeading:true,),【动手工坊】仿京东App—搭建个人中心及订单列表页面body:orders.isEmpty?constCenter(child:Text('暂无订单')):ListView.builder(itemCount:orders.length,itemBuilder:(context,index){//最新订单在前显示finalOrderorder=orders[orders.length-1-index];//finalList<CartItem>items=order.items;returnCard(margin:constEdgeInsets.symmetric(horizontal:12,vertical:8,),child:Padding(padding:constEdgeInsets.all(12.0),child:Column(crossAxisAlignment:CrossAxisAlignment.start,children:[//订单头部信息:时间和总价Row(children:[Text('下单时间:${order.time}',style:constTextStyle(fontSize:13,color:Colors.grey,),), constSpacer(),Text('总价:¥${order.total.toStringAsFixed(2)}',style:constTextStyle(fontSize:15,color:Colors.red,fontWeight:FontWeight.bold,),),],),constSizedBox(height:8),//订单商品列表...items.map((CartItemitem)=>Row(children:[

//商品图片,如果以http开头代表网络图片,否则为本地图片item.image.startsWith('http')?Iwork(item.image,width:40,height:40,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论