入门Flutter基础学习笔记记录,踩坑!
Flutter基础学习
1、环境准备
1.首先到官网https://flutter.dev/docs/get-started/install/windows里下载Flutter的SDK
2.还得有Android studio的环境支持,因为flutter是依赖于Android sutdio运行的,
3.有勒Android studio的环境支持后,在Android studio里安装插件Flutter.
4.配置Flutter的系统环境,把Flutter的bin目录填入Path中即可。
5.在cmd中测试是否系统环境配置成功,flutter -h,并检测flutter环境是否全部配置完成
flutter doctor:flutter内置用于检测环境是否全部配置完成,只要检测出有X的情况,就是
环境还没有配置成功。
2、创建项目
2.1、Android Studio中编译
- 1.打开Android sutdio里创建新项目总有一个 创建Flutter项目
- 2.点击第一个代表项目的意思,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lDWN0KnM-1590411478045)(E:\Typora_text\images\flutter1.png)]
- 3.下一步就是打包的包名,再一下不就是创建了(在这里可能会出现卡死状态,因为第一次 创建项目不来就要很久)
如果等的时间很久超过20分钟一般10分钟左右。
解决:
在flutter目录下两个cmd命令即可。
set PUB_HOSTED_URL=https://pub.flutter-io.cn
set FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
- 4.因为怕有网络卡死的情况,我们还需要改下网络配置
4.1、打开创建好的项目中的android—>build.gradle
此页面修改两处
repositories { // google() // jcenter()maven { url 'https://maven.aliyun.com/repository/google' }maven { url 'https://maven.aliyun.com/repository/jcenter' }maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }}
4.2、打开D:\Flutter\flutter\packages\flutter_tools\gradle---->flutter.gradle
修改移出
buildscript {repositories {//jcenter()// maven {// url 'https://dl.google.com/dl/android/maven2'// }maven{url 'https://maven.aliyun.com/repository/jcenter'}maven{url 'http://maven.aliyun.com/nexus/content/groups/public'}}dependencies {classpath 'com.android.tools.build:gradle:3.1.2'} }
2.2、使用VsCode来编写代码
当然环境配置啥的还是使用Android studio,vscode只是用来编写代码,因为这个比较轻量级。
- 1.vscode中添加Flutter插件同时他会帮你把Dart插件也装上,如果没自己装上即可。
- 2.准备一个bat打开虚拟机的文件(因为你总不能每次去Android里打开虚拟机吧!)
D:\AndroidSdk\emulator\emulator.exe -netdelay none -netspeed full -avd Pixel_2_API_28_noPB
注意:
1.前面的地址是由你安装AndroidSDK来决定的,不过有两个emulator.exe选择emulator文件夹里面的emulator.exe即可
-netdelay none:关闭网络延迟,-netspeed full全速运行
-avd 后面就是你虚拟机名,如果名字带有空格使用下划线(_)代替即可。
2.或点击vscode的右下角直接可以启动虚拟机
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hf6erA4U-1590411478047)(E:\Typora_text\images\flutter5.png)]
- 3.运行项目
1.cd到我们的项目地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GM8MYNtb-1590411478049)(E:\Typora_text\images\flutter2.png)]
2.运行
flutter run
这里可能有点慢,这是在处理依赖。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AMXTqWfB-1590411478051)(E:\Typora_text\images\flutter3.png)]
出现这个代表运行成功了。
4.相关插件
- Awesome Flutter Snippets:代码生成提示
- Flutter+Dart:内核
2.3.使用命令
2.3.1、VsCode
//热更新:使用Dug运行可以实现ctrl+s热更新
r
//热重启
R
//显示网格
p
//Android和Ios视图切换
O
2.3.2、Android sutdio
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-11zURco2-1590411478052)(E:\Typora_text\images\flutter4.png)]
其余功能都自带
3、项目基本组件
3.1、Text Widget组件
//导入ui库
import 'package:flutter/material.dart';//入口对象
void main() => runApp(MyApp());//继承组件
class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {//返回一个窗口然后里面填的是组件return MaterialApp(title: "Hello Word",home: Scaffold(appBar: AppBar(title: Text("标题"),),body: Center(//主要注意child: Text("Hello Word,I name is Tommy ,student Flutter jichu,so is luanxie yidian ",textAlign: TextAlign.center,maxLines: 1,overflow: TextOverflow.ellipsis,style: TextStyle(fontSize: 25.0,color: Color.fromARGB(255, 122, 122, 122),decoration: TextDecoration.underline,decorationStyle: TextDecorationStyle.solid),),),),);}
}
textAlign:代表文本对齐方式
maxLines:最多多少行
overflow:超出父容器的怎么处理
ellipsis:化为三点
style: 样式
TextStyle:字体样式
fontSize:大小(浮点型),color:颜色,decoration下划线,decorationStyle:下划线样式
3.2、 Container Widget组件
再主boody的Center里创建一个Container
Container 和div的思想一样,都是容器。
//导入ui库
import 'package:flutter/material.dart';//入口对象
void main() => runApp(MyApp());//继承组件
class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {//返回一个窗口然后里面填的是组件return MaterialApp(title: "Hello Word",home: Scaffold(appBar: AppBar(title: Text("标题"),),body: Center(child: Container(child: new Text("文本"),alignment: Alignment.center,width: 200,height: 200,color: Colors.blueAccent,padding: EdgeInsets.fromLTRB(10,0,0,0),margin: EdgeInsets.all(10),decoration: new BoxDecoration(gradient: const LinearGradient(colors: [Colors.blueAccent,Colors.lightGreenAccent,Colors.redAccent]),border: Border.all(width: 2, color: Colors.amberAccent)),),),),);}
}
注意是再Conter里有个child
child容器中有一个文本
alignment:对于容器里的组件的对齐方式-------->Alignment
width,height宽高(默认全屏)
color:容器的背景颜色----->Color来设置值
padding:内边距 ----->EdgeInsets来设置值—>fromLTRB四个方向
margin:外边距 --------->EdgeInsets来设置值---->all全部方向
decoration:设置背景渐变(与color冲突,其二选一)
BoxDecoration:背景渐变----->gradient设置颜色—>LinearGradient线性渐变
----->border:设置容器边框
3.3、Image Widget组件
//导入ui库
import 'package:flutter/material.dart';//入口对象
void main() => runApp(MyApp());//继承组件
class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {//返回一个窗口然后里面填的是组件return MaterialApp(title: "Hello Word",home: Scaffold(appBar: AppBar(title: Text("标题"),),body: Center(child: Container(child: new Image.network("https://www.baidu.com/img/dong_649e142b9088eaea580c3be34ac0bded.gif",fit: BoxFit.fill,color: Colors.amberAccent,colorBlendMode: BlendMode.darken,),width: 500,height: 500,),),),);}
}
- 首先得选择显示图片的模式
- network:以网络url显示
- file:以手机内存的图片显示
- aseet:以资源文件显示
- fit:图片填充模式
- BoxFit.fill:填充父容器大小
- BoxFit.contain:剧中显示…
- color:为图片叠加颜色-------->colorBlendMode:叠加颜色的模式
3.4、ListView Widget组件
3.4.1、常用语法
//导入ui库
import 'package:flutter/material.dart';//入口对象
void main() => runApp(MyApp());//继承组件
class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {//返回一个窗口然后里面填的是组件return MaterialApp(title: "Hello Word",home: Scaffold(appBar: AppBar(title: Text("标题"),),body: Center(child: Container(child: new MyList(),height: 200,),),),);}
}//万事皆组件
//List的组件,摘要出来就不会嵌套很深
class MyList extends StatelessWidget {@overrideWidget build(BuildContext context) {// TODO: implement buildreturn new ListView(children: <Widget>[new Container(width: 200,color: Colors.lightBlue,),new Container(width: 200,color: Colors.lime,),new Container(width: 200,color: Colors.lightGreenAccent,),new Container(width: 200,color: Colors.purpleAccent,)],scrollDirection: Axis.horizontal,);}
}
注意:在这里我提出来了List组件为了不嵌套太深。
- children:listview中的组件
- Container:listview中每一的样式。(这个也可以ListTile是自带的一个块级样式)
- scrollDirection:设置横向与纵向---->Axis.horizontal横向,Axis.vertical纵向
3.4.2、动态ListView
//导入ui库
import 'package:flutter/material.dart';//入口对象
void main() => runApp(MyApp(//传入一个参数items: new List<String>.generate(10000, (i) => "Item $i is") //使用 => 语法代替for复制 $接收i));//继承组件
class MyApp extends StatelessWidget {//接收一个参数final List<String> items;MyApp({Key key, @required this.items}); //此时items就是接收的参数@overrideWidget build(BuildContext context) {//返回一个窗口然后里面填的是组件return MaterialApp(title: "Hello Word",home: Scaffold(appBar: AppBar(title: Text("标题"),),body: Center(child: new ListView.builder(itemCount: items.length,itemBuilder: (context, index) {return new ListTile(title: new Text('${items[index]}'));})),),);}
}
- 基础Dart语言
- 入口时传入一个参数即可List
- MyApp({Key key, @required this.items})
- @required:必须接收一的参数
- ListView.builder:代表时动态的LIst
- itemCount:接收的数据一共有多少条
- itemBuilder:接收的数据以及显示样式
- ‘${items[index]}’:显示数据
3.5、GrideView Widget组件
Widget build(BuildContext context) {// TODO: implement buildreturn new GridView(
// 设置GridView的参数gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(//列数crossAxisCount: 3,//横项的间隔mainAxisSpacing: 2.0,//列的间隔crossAxisSpacing: 2.0,//格子容器和内容的对比度childAspectRatio: 0.7),
// 样式children: <Widget>[new Image.network("http://tu.sixco.shop/upload/vod/20191121-1/5e86d23df4120f652c945c7093a9ef6b.jpg"),new Image.network("http://tu.sixco.shop/upload/vod/20200405-1/230b33ba6f800b48c36146bab350b129.jpg"),new Image.network("https://tu.tianzuida.com/pic/upload/vod/2020-04-25/202004251587819345.jpg"),new Image.network("http://tu.sixco.shop/upload/vod/20200414-1/52cd2142d8ef51f3fea14370d54ec7c1.jpg"),new Image.network("http://tu.sixco.shop/upload/vod/20191119-1/77a250fba2e33f47e888a021d774d3ed.jpg"),new Image.network("http://tu.sixco.shop/upload/vod/20191029-3/287d9ab512f979f872fc879e61d4ec26.jpg")],);}
}
注意:这是组件的用法
- gridDelegate:设置GridView的参数
- crossAxisCount:列数
- mainAxisSpacing:横项的间隔
- crossAxisSpacing:列的间隔
- childAspectRatio:格子容器和内容的对比度
- children:数据样式
动态原理即可。
3.6、Flutter的布局组件
3.6.1、Row Widget水平布局
import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context){return MaterialApp(title: '布局样式',home: Scaffold(appBar: new AppBar(title: new Text("水平方向布局",)),
// Row横向布局body: new Row(children: <Widget>[
// 普通new RaisedButton(onPressed: (){},color: Colors.purpleAccent,child: new Text('按钮1'),),
// Expanded权重,占全距离Expanded(child: new RaisedButton(onPressed: (){},color: Colors.blueAccent,child: new Text('按钮2'),),),new RaisedButton(onPressed: (){},color: Colors.lightGreenAccent,child: new Text('按钮3'),)],),),);}}
主要注意的是Expanded权重
children:容器放入布局中的组件即可。
3.6.2、Column Widget 垂直布局
import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(title: '布局样式',home: Scaffold(appBar: new AppBar(title: new Text("水平方向布局",)),
// Row横向布局body: Center(child: Column(crossAxisAlignment: CrossAxisAlignment.center, //横轴对齐mainAxisAlignment: MainAxisAlignment.center, //纵轴对齐children: <Widget>[Text("第一段"),Expanded(child: Text("第二段"),),Text("第三段")],),)),);}
}
Center:剧中块
注意:
- crossAxisAlignment:横轴对齐
- mainAxisAlignment:纵轴对齐
- children:垂直布局中的容器
- Expanded:同样也是权重
3.6.3、Stack Widget 重叠布局
import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget {
// 实例化一个重叠布局为变量var stack = new Stack(
// 重叠布局的优先级alignment: const FractionalOffset(0.5, 0.8),
// 容器children: <Widget>[
// 圆角图片new CircleAvatar(backgroundImage: new NetworkImage("https://www.baidu.com/img/bd_logo1.png"),radius: 100,),new Container(decoration: new BoxDecoration(color: Colors.lightGreenAccent,),padding: EdgeInsets.all(5),child: Text("文字"),)new Positioned(child: new Text("定位布局"),top: 10,left: 60,)],);@overrideWidget build(BuildContext context) {return MaterialApp(title: '布局样式',home: Scaffold(appBar: new AppBar(title: new Text("水平方向布局",)),
// Row横向布局body: Center(child: stack,)),);}
}
注意:这里我们实例化了重叠布局,然后再放入body中的
- alignment:重叠的优先级
- children:容器
- CircleAvatar:圆角图片
注意:这里只能控制2个的字布局,如果有第三个,可以使用定位布局
- Positioned:定位布局,直接控制像素
3.6.4、card + ListTile 卡片布局+块级(图标 + 文字+把标题,固定好的)
// 实例化一个重叠布局为变量var card = new Card(child: Column(children: <Widget>[ListTile(title: new Text("第一条数据",style: TextStyle(fontWeight: FontWeight.w300),),subtitle: Text("副标题1"),leading: Icon(Icons.accessible_forward),),new Divider(),ListTile(title: new Text("第二条数据",style: TextStyle(fontWeight: FontWeight.w300),),subtitle: Text("副标题2"),leading: Icon(Icons.accessible_forward),),new Divider(),ListTile(title: new Text("第三条数据",style: TextStyle(fontWeight: FontWeight.w300),),subtitle: Text("副标题3"),leading: Icon(Icons.accessible_forward),),new Divider(),],),);
- card布局主要是带有阴影,它与容器差不多
- ListTile :块级(图标 + 文字+把标题,固定好的)
- children:card的容器
- ListTile:放入一个块级
- title:主标题
- subtitle:副标题
- leading:主图标
- Divider:分割线
3.7、导航跳转
3.7.1、普通跳转
import 'package:flutter/material.dart';//设置页面为home主页启动页
void main() => runApp(MaterialApp(title: "导航1",home: MyApp(),));class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar: AppBar(title: Text("导航页面"),),body: Center(child: RaisedButton(child: Text("查看第二个页面"),onPressed: () {//点击事件
// Navigator导航启动器Navigator.push(
// MaterialPageRoute跳入哪个子页面context, MaterialPageRoute(builder: (context) => new ToView()));},),),);}
}//静态组件:第二个页面
class ToView extends StatelessWidget {@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar: AppBar(title: Text("第二个页面")),body: Center(child: RaisedButton(child: Text("返回"),onPressed: () {//点击事件
// 返回上一个页面Navigator.pop(context);},),),);}
}
注意:这里所有的new谷歌建议不适用new 直接使用即可
再main里要注定home主页是哪个组件
onPressed:点击事件
Navigator.push:启动一个跳转页面
- MaterialPageRoute:路由。
- ToView:第二个组件(也就是页面)
Navigator.pop:传入上下文返回上一个页面
3.7.2、带有参数跳转界面
import 'package:flutter/material.dart';//准备一个对象
class Product {final String title;final String desc;//生成构造方法Product(this.title, this.desc);
}//设置页面为home主页启动页
void main() => runApp(MaterialApp(title: "导航1",home: MyApp(products:List.generate(20, (i) => Product("商品:$i", "详细商品$i"))), //传入参数));class MyApp extends StatelessWidget {//接收的参数final List<Product> products;MyApp({Key key, @required this.products}); //接收参数@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar: AppBar(title: Text("导航页面"),),body: Center(child: ListView.builder(itemCount: products.length,itemBuilder: (context, index) {return ListTile(title: Text(products[index].title),onTap: () {//点的单个列表事件//跳转并传入参数Navigator.push(context,MaterialPageRoute(
// 传入参数builder: (context) =>ToView(product: products[index])));},);}),),);}
}//静态组件:第二个页面
class ToView extends StatelessWidget {
// 接收参数Product product;ToView({Key key, @required this.product}); //接收参数@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar: AppBar(title: Text("${product.title}")),body: Center(child: Text("${product.desc}")),);}
}
注意:在这里我们自定义了一个Product对象。
- 首先传入了一个List给了第一个主界面
- Navigator.push:跳转页面
- MaterialPageRoute:设置路由
- ToView(product: products[index])));:跳转的页面中代入参数,以map的方式传入
- 同样以: ToView({Key key, @required this.product}); //接收参数
- 显示参数使用${}即可显示
3.7.3、返回页面带参数
import 'package:flutter/material.dart';//设置页面为home主页启动页
void main() => runApp(MaterialApp(title: "导航1", home: MyApp()));class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar: AppBar(title: Text("找人"),),body: Center(child: MyButton(),),);}
}
//如果使用Scaffold就不能把该组件嵌套到child中
class MyButton extends StatelessWidget {@overrideWidget build(BuildContext context) {// TODO: implement buildreturn RaisedButton(child: Text("要电话号码"),onPressed: (){//点击事件_navigateTo(context);},);}}
// 准备一个方法去往页面
_navigateTo(BuildContext context ) async{final res = await Navigator.push(context, MaterialPageRoute(builder: (context)=>ToView()));
// 底部对话框Scaffold.of(context).showSnackBar(SnackBar(content: Text('$res'),));
}//静态组件:第二个页面
class ToView extends StatelessWidget {@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar: AppBar(title: Text("人群")),body: Center(child: Column(children: <Widget>[RaisedButton(child:Text("张三:12321421"),onPressed: (){
// 点击事件Navigator.pop(context,"张三:12321421");},),RaisedButton(child:Text("李四:21412412"),onPressed: (){
// 点击事件Navigator.pop(context,"李四:21412412");},),],),),);}
}
注意:
- 如果要使用Scaffold.of他的调用组件不能嵌套,需要提出来(MyButtom)。
- Navigator.pop(context,“张三:12321421”):返回页面并携带参数
- 再跳转页面时返回的对象就时返回页面的携带值。(最好只加上async异步请求)
4、静态资源的管理
4.1、静态图片
- 首先修改pubspec.yml文件
#添加assets:#文件路径:根目录下的images- images/
- 使用
new Image.asset("images/img.png"),
4.2、修改logo图片以及软件名
-
修改软件名
-
android:android—>src–>main—>res—>AndroidManifest.xml里修改label
-
ios:ios—>Runner–>info.plist–>
<key>CFBundleName</key><string>flutter_dome02</string>
-
-
修改logo图标
-
把自己的logo图片修改名为:ic_launcher.png替换android—>src–>main—>res---->mipmap所有文件即可
当然,每个文件都有每个文件的大小。如果你有其他办法也可以使用
-
5、网络访问DIO使用
这里推荐一个easy-mock这个可以创建模拟接口给你测试(全网使用)
官网:https://www.easy-mock.com/login
功能:
- 创建url
- 创建接口get、post
5.1、导入DIO包
这里考虑到没有翻墙,然后有很多坑
首先在pubspec.yml 文件里
dependencies:上线状态
dependencies:flutter:sdk: flutter# The following adds the Cupertino Icons font to your application.# Use with the CupertinoIcons class for iOS style icons.cupertino_icons: ^0.1.2dio: ^3.0.0
注意yml时空格来决定格式的,dio:(这里有个空格) ^参数
dev_dependencies:开发状态
在dart文件中导入
import 'package:dio/dio.dart';
与创建项目一致,打开该项目的cmd控制台
输入命令跨网
- set PUB_HOSTED_URL=https://pub.flutter-io.cn
- set FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
在输入命令下载dio
- flutter packages get
5.2、get请求
// 准备一个测试网络的方法Future getHttp() async {try {Response response;response = await Dio().get("https://www.easy-mock.com/mock/5ead226ca9af2438fc69eeb0/tommy/getData
");return print(response);} catch (e) {return print(e);}}
注意:
- https://www.easy-mock.com/mock/5ead226ca9af2438fc69eeb0/tommy/getData这时eays-mock里自定义的
5.3、Post请求
// 准备一个测试网络的方法Future getHttp() async {try {Response response;var data = {"name":"fdsa"}; //准备参数对象//这个接口时easy-mock里自定义的post接口response = await Dio().post("https://www.easy-mock.com/mock/5ead226ca9af2438fc69eeb0/tommy/setData",
// 填入参数对象data: data);return print(response);} catch (e) {return print(e);}}
注意
- 接口同样也是asys-mock中的
- data是参数对象
5.4、获取后的json数据解析
- 导入包:import ‘dart:convert’; //引入json解析插件,具体方法参考<<导入DIO包>>
// 使用json把字符串转为json对象
var data = json.decode(getHttp().data.toString());
6、打包为apk
注意这里只有Android打包
6.1、打包前得生成签名文件
-
找到keytool.exe位置
flutter doctor -v
获取一个java地址
D:\AndroidStudio\jre\bin\java
当然你的可能不一样
-
运行官方提供的命令
D:\AndroidStudio\jre\bin\keytool -genkey -v -keystore D:\key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key
注意:
- 把java替换为keytool
- D:\key.jks这个时你需要输出的位置,需要自己修改
修改完成后,他会有一堆提问按提示输入即可,CN那个问题给一个y即可。
6.1、生成apk
- 首先得到android文件夹里创建一个文件夹key.properties,并存入钥匙。
storePassword=123456
keyPassword=123456
keyAlias=key
storeFile=D:/key.jks
- 配置key (1),修改android/app/build.gradle文件
def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
//-------
//android {
在android{前添加三行}
- 配置key(2)
//buildTypes {
// release {
// signingConfig signingConfigs.debug
// }
//}
//-----上替换为下
signingConfigs {release {keyAlias keystoreProperties['keyAlias']keyPassword keystoreProperties['keyPassword']storeFile file(keystoreProperties['storeFile'])storePassword keystoreProperties['storePassword']}
}
buildTypes {release {signingConfig signingConfigs.release}
}
将上边代码替换为下边。
- 最后生成apk
//命令
flutter build apk
生成后的地址
build---->app—>outpputs---->apk---->release---->app-release.apk
如果没有release文件夹可能时没签名成功。
6、实战电商笔记
6.1、布局总架构(底部导航)
- 进入main入口dart
import 'package:flutter/material.dart';
import 'package:flutter_electricity/pages/index_page.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget{@overrideWidget build(BuildContext context) {// TODO: implement buildreturn MaterialApp(title: "电商管理",debugShowCheckedModeBanner: false,theme: ThemeData(primaryColor: Colors.pink),home: Scaffold(
// appBar: new AppBar(title: Text("主页"),),body: Center(child: IndexPage(),),),);}}
注意两种类型:
import ‘package:flutter/material.dart’;------>这个是Android样式差不多
import ‘package:flutter/cupertino.dart’;------> 这个是ios样式差不多
import ‘package:flutter_electricity/pages/index_page.dart’------> 导入了主页页面.
-
准备四个页面
//适合Android的布局 import 'package:flutter/material.dart';void main() => runApp(CartPage());class CartPage extends StatelessWidget{@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(backgroundColor: Colors.pink,body: Center(child: Text("购物车"),),);}}
内容自定义
-
架构业 index_page.dart
//适合Android的布局
import 'package:flutter/material.dart';
//适合ios的布局
import 'package:flutter/cupertino.dart';
//导入页面
import 'package:flutter_electricity/pages/cart_page.dart';
import 'package:flutter_electricity/pages/category_page.dart';
import 'package:flutter_electricity/pages/home_page.dart';
import 'package:flutter_electricity/pages/member_page.dart';//动态布局,fragment
class IndexPage extends StatefulWidget {@override_IndexPageState createState() => _IndexPageState();
}class _IndexPageState extends State<IndexPage> {
// 准备图标与文字final List<BottomNavigationBarItem> bottmTabs = [BottomNavigationBarItem(icon: Icon(CupertinoIcons.home), title: Text("首页")),BottomNavigationBarItem(icon: Icon(CupertinoIcons.search), title: Text("分类")),BottomNavigationBarItem(icon: Icon(CupertinoIcons.shopping_cart), title: Text("购物车")),BottomNavigationBarItem(icon: Icon(CupertinoIcons.profile_circled), title: Text("会员中心")),];// 准备fragment页面final List tabBodies = [HomePage(), CateGoryPage(), CartPage(), MembarPage()];//选择页面的索引int currentIndex = 0;//选择的页面var currentPage;//初始化@overridevoid initState() {// 底部对话框currentPage = tabBodies[currentIndex];super.initState();}//布局@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(
// 设置背景也是backgroundColor: Color.fromRGBO(244, 245, 245, 1.0),body: currentPage,
// 设置底部按钮bottomNavigationBar: BottomNavigationBar(
// 设置一种类型type: BottomNavigationBarType.fixed,
// 设置当前页面索引currentIndex: currentIndex,
// 设置所有的页面对象items: bottmTabs,onTap: (index) {setState(() {
// 改变页面索引currentIndex = index;currentPage = tabBodies[currentIndex];});},),);}
}
注意:导入对象
- StatefulWidget:动态布局入口Fragment入口
- _IndexPageState:动态组件
- 首先准备BottomNavigationBarItem的list来存入图片与文字,当然flutter里就有自带图标BottomNavigationBarItem(icon: Icon(CupertinoIcons.home)
- 准备list来存入所有的Fragment子页面(当然这里只要填入页面中的入口类名即可。)
- 准备一个索引,用于存入当前位置currentIndex。
- 准备一个对象,用于存入页面currentPage。
- 初始化页面的回调中initState—>初始化最先显示的页面
- 其次就时布局
- 注意一定有一个body把currentPage当前界面存入
- bottomNavigationBar:底部导航,填入类型,当前页面索引,所有页面对象,以及实现onTap点击单个来切换页面。
6.2、构建网络请求框架
6.2.1、测试DIO的get请求
- 导入DIO包
这里考虑到没有翻墙,然后有很多坑
首先在pubspec.yml 文件里
dependencies:上线状态
dependencies:flutter:sdk: flutter# The following adds the Cupertino Icons font to your application.# Use with the CupertinoIcons class for iOS style icons.cupertino_icons: ^0.1.2dio: ^3.0.0
注意yml时空格来决定格式的,dio:(这里有个空格) ^参数
dev_dependencies:开发状态
在dart文件中导入
import 'package:dio/dio.dart';
与创建项目一致,打开该项目的cmd控制台
输入命令跨网
- set PUB_HOSTED_URL=https://pub.flutter-io.cn
- set FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
在输入命令下载dio
- flutter packages get
- home_page.dart
//适合Android的布局
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';void main() => runApp(HomePage());class HomePage extends StatelessWidget{@overrideWidget build(BuildContext context) {// TODO: implement buildgetHttp();return Scaffold(body: Center(child: Text("首页"),),);}
// 准备一个测试网络的方法
void getHttp() async{try{Response response;response = await Dio().get("https://v1.hitokoto.cn/");return print(response);}catch(e){return print(e);}
}
}
Response 和后台服务一样,是获取请求回来参数对象
6.2.2、网络框架
这样能减少项目开发的维护成本,以及统一性.
- 创建一个servce_url(用于管理url以及api调用)
//封装url
const servceUrl = "http://106.13.185.176:7777/manage/"; //准备一个url
const servcePath={'home':servceUrl+"getData" //获取主页api
};
注意:这里我使用的接口是自己第一个接口
- 创建service_method.dart(用于管理调用api接口的方法)
//封装访问接口方法
//导入习惯访问插件
import 'package:dio/dio.dart';
import 'dart:async';
import 'dart:io';
import 'package:flutter_electricity/config/servce_url.dart';
//打印
const TAG_OK = "正在调用接口:------------->";
const TAG_ERROR = "服务器出现问题:------------->";//获取主页内容
Future getHomePageData() async{try{print(TAG_OK+(servcePath['home']));Response response ;Dio dio = new Dio();response = await dio.post(servcePath["home"]);return response;}catch(e){return print(TAG_ERROR+e);}
}
注意:
- 导入相关所有插件
- 调用方法返回Futuer并用上异步请求
- 调用测试
// 准备一个测试网络的方法Future getHttp() {getHomePageData().then((val){setState(() {
// 这个方法时动态布局使用---->修改变量时,他会改变布局样式。textValue = val.toString();});});}
注意:
返回的Future使用then来解析数据
setState方法是动态布局中使用的,
- 它实现了双向绑定数据效果,修改数据,页面值也会修改。
6.3、主页开发
6.3.1、主页轮播图编写–>插件:flutter_swiper
- 导入组件:import ‘package:flutter_swiper/flutter_swiper.dart’; //导入轮播图插件,需要再pubspec.yml里
- home_page.dart
//适合Android的布局
import 'package:flutter/material.dart';
import 'package:flutter_swiper/flutter_swiper.dart'; //导入轮播图插件
import 'dart:convert'; //引入json解析插件//导入极客的头文件
import 'package:flutter_electricity/config/httpHead.dart';
import 'package:flutter_electricity/servceFun/servce_method.dart';class HomePage extends StatefulWidget {@overrideState<StatefulWidget> createState() {// TODO: implement createStatereturn HomePageState();}
}class HomePageState extends State<HomePage> {
// 声明数据:一定记得实例化TextEditingController inputValue = TextEditingController();String textValue = "";@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar: AppBar(title: Text("首页"),),
// 这个组件可以自动根据异步请求来渲染页面。body: FutureBuilder(
// 一个异步方法future: getHomePageData(),
// 构造器builder: (context,snapshot){if(snapshot.hasData){ //里面是否存在值
// 使用json把字符串转为json对象var data = json.decode(snapshot.data.toString());
// 因为这里需要的是List所以需要将json转为list
// List<Map> swiper = (data['data']['slides'] as List).cast();
// 这里因为没有接口所以,自己模拟数据List<String> listData = new List();listData.add("http://a1.att.hudong.com/05/00/01300000194285122188000535877.jpg");listData.add("http://a4.att.hudong.com/20/62/01000000000000119086280352820.jpg");listData.add("http://file02.16sucai.com/d/file/2014/0829/372edfeb74c3119b666237bd4af92be5.jpg");//返回我们的静态轮播图组件return SwiperWidget(swiperDataList: listData,);}else{return Text("正在加载...");}},),);}// 测试输入框void getInput(context) {showDialog(context: context,builder: (context) => AlertDialog(title: Text("文本框:" + inputValue.text.toString()),));}// 准备一个测试网络的方法Future getHttp() {getHomePageData().then((val) {setState(() {
// 这个方法时动态布局使用---->修改变量时,他会改变布局样式。textValue = val.toString();});});}
}//轮播图,静态组件
class SwiperWidget extends StatelessWidget {
// 接收一个list的参数final List swiperDataList;SwiperWidget({Key key, this.swiperDataList}) : super(key: key); //传入一个参数@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Container(height: 250,child: Swiper(
// 轮播图内容itemBuilder: (BuildContext context,int index){return Image.network("${swiperDataList[index]}" ,fit: BoxFit.fill,);},
// 个数itemCount: swiperDataList.length,
// 是否有移动小图标pagination: SwiperPagination(),
// 运行自动播放autoplay: true,),);}
}
注意:
- FutureBuilder: 这个组件可以自动根据异步请求来渲染页面。
- future:需要给一个异步请求方法
- builder:构造方法,填入相应的逻辑
- Swiper:轮播组件
- itemBuilder:构造方法,轮播的容器,字布局
- itemCount:轮播字布局的个数
- pagination:是否有小图标—>SwiperPagination()构造
- autoplay:是否自动播放
6.3.2、使用flutter_screenutil适配布局
- 导入组件:import ‘package:flutter_screenutil/flutter_screenutil.dart’; //导入适配组件—》需要再pubspec.yml里添加
- index_page.dart
//布局@overrideWidget build(BuildContext context) {// TODO: implement build//在主入口初始化screenutil适配器ScreenUtil.init(context,width: 750,height: 1334); //初始宽高return Scaffold(
// 设置背景也是backgroundColor: Color.fromRGBO(244, 245, 245, 1.0),
注意一般初始化插件值初始化一次,所以放在第一次进入的界面
- home_page.dart
return Container(height: ScreenUtil().setHeight(250),width: ScreenUtil().setWidth(750),child: Swiper(// 轮播图内容itemBuilder: (BuildContext context,int index){return Image.network("${swiperDataList[index]}" ,fit: BoxFit.fill,);},// 个数itemCount: swiperDataList.length,// 是否有移动小图标pagination: SwiperPagination(),// 运行自动播放autoplay: true,),
);
注意:
设置高宽以及字体大小
- height: ScreenUtil().setHeight(250),
- width: ScreenUtil().setWidth(750)
- fontSize: ScreenUtil().setSp(28,false)
- 这里的false参数书代表不会跟着系统字体改变
6.3.3、主页网格菜单栏布局
- home_page.dart
//适合Android的布局
import 'package:flutter/material.dart';
import 'package:flutter_swiper/flutter_swiper.dart'; //导入轮播图插件
import 'dart:convert'; //引入json解析插件
import 'package:flutter_screenutil/flutter_screenutil.dart'; //导入适配组件//导入极客的头文件
import 'package:flutter_electricity/config/httpHead.dart';
import 'package:flutter_electricity/servceFun/servce_method.dart';class HomePage extends StatefulWidget {@overrideState<StatefulWidget> createState() {// TODO: implement createStatereturn HomePageState();}
}
// 设置一个模拟网格菜单项数据的对象
class Navg{String img;String name;Navg(String img,String name);
}
class HomePageState extends State<HomePage> {
// 声明数据:一定记得实例化TextEditingController inputValue = TextEditingController();String textValue = "";@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar: AppBar(title: Text("首页"),),
// 这个组件可以自动根据异步请求来渲染页面。body: FutureBuilder(
// 一个异步方法future: getHomePageData(),
// 构造器builder: (context, snapshot) {if (snapshot.hasData) { //里面是否存在值
// 使用json把字符串转为json对象var data = json.decode(snapshot.data.toString());
// 因为这里需要的是List所以需要将json转为list
// List<Map> swiper = (data['data']['slides'] as List).cast();
// 这里因为没有接口所以,自己模拟数据----》轮播图List<String> listData = new List();listData.add("http://a1.att.hudong.com/05/00/01300000194285122188000535877.jpg");listData.add("http://a4.att.hudong.com/20/62/01000000000000119086280352820.jpg");listData.add("http://file02.16sucai.com/d/file/2014/0829/372edfeb74c3119b666237bd4af92be5.jpg");
// 模拟数据------》网格布局中的菜单项List<Map> navgatorList = new List();navgatorList.add({"img":"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1962359944,4033386090&fm=26&gp=0.jpg","name":"白酒"});navgatorList.add({"img":"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2644613255,429458660&fm=26&gp=0.jpg","name": "红酒"});navgatorList.add({"img":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=123433492,672306588&fm=11&gp=0.jpg","name": "啤酒"});navgatorList.add({"img":"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1971380632,2889601273&fm=11&gp=0.jpg", "name":"绿酒"});navgatorList.add({"img":"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2254386225,705619148&fm=26&gp=0.jpg", "name":"黑酒"});navgatorList.add({"img":"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1336046231,1070862462&fm=26&gp=0.jpg", "name":"酒神"});navgatorList.add({"img":"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3925608220,2911772755&fm=26&gp=0.jpg","name": "酒圣"});navgatorList.add({"img":"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2809691443,3777995480&fm=26&gp=0.jpg", "name":"铪酒"});navgatorList.add({"img":"https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1899337755,3087141316&fm=26&gp=0.jpg", "name":"米酒"});navgatorList.add({"img":"https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1235513397,588910321&fm=26&gp=0.jpg","name": "源酒"});//返回我们的静态轮播图组件return Column(children: <Widget>[SwiperWidget(swiperDataList: listData,),TopNavigator(navigatorList: navgatorList,),Image.network("https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1962359944,4033386090&fm=26&gp=0.jpg")],);} else {return Text("正在加载...", style: TextStyle(
// fontSize: ScreenUtil().setSp(28,false)),);}},),);}// 测试输入框void getInput(context) {showDialog(context: context,builder: (context) =>AlertDialog(title: Text("文本框:" + inputValue.text.toString()),));}// 准备一个测试网络的方法Future getHttp() {getHomePageData().then((val) {setState(() {
// 这个方法时动态布局使用---->修改变量时,他会改变布局样式。textValue = val.toString();});});}
}//轮播图,静态组件
class SwiperWidget extends StatelessWidget {
// 接收一个list的参数final List swiperDataList;SwiperWidget({Key key, this.swiperDataList}) : super(key: key); //传入一个参数@overrideWidget build(BuildContext context) {// TODO: implement build
// 使用ScreenUtil适配大小print('设备像素密度:${ScreenUtil.pixelRatio}');print('设备的高:${ScreenUtil.screenHeightDp}');print('设备的宽:${ScreenUtil.screenWidthDp}');return Container(height: ScreenUtil().setHeight(333),width: ScreenUtil().setWidth(750),child: Swiper(
// 轮播图内容itemBuilder: (BuildContext context, int index) {return Image.network("${swiperDataList[index]}", fit: BoxFit.fill,);},
// 个数itemCount: swiperDataList.length,
// 是否有移动小图标pagination: SwiperPagination(),
// 运行自动播放autoplay: true,),);}
}//网格布局
class TopNavigator extends StatelessWidget {final List navigatorList;TopNavigator({Key key, this.navigatorList}) :super(key: key);
// 设置一个字布局,Widget _gridViewIntemUI(BuildContext context, List<Map> item,int index) {return InkWell(onTap: () {print(("点击了导航"));},child: Column(children: <Widget>[Image.network(item[index]['img'], width: ScreenUtil().setWidth(95),),Text(item[index]['name'])],),);}@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Container(height: ScreenUtil().setHeight(320),padding: EdgeInsets.all(3.0),child: GridView.builder(itemCount: navigatorList.length,itemBuilder: (BuildContext context,int index){return _gridViewIntemUI(context, navigatorList,index);},gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5),));}}
注意:
- 获取数据返回GridView
return Column(children: <Widget>[SwiperWidget(swiperDataList: listData,),TopNavigator(navigatorList: navgatorList,), //返回网格菜单栏
- 准备一个字布局,返回Widget就行
// 设置一个字布局,Widget _gridViewIntemUI(BuildContext context, List<Map> item,int index) {return InkWell(onTap: () {print(("点击了导航"));},child: Column(children: <Widget>[Image.network(item[index]['img'], width: ScreenUtil().setWidth(95),),Text(item[index]['name'])],),);}
- 在网格布局中设置动态字布局
child: GridView.builder(//设置个数itemCount: navigatorList.length,itemBuilder: (BuildContext context,int index){return _gridViewIntemUI(context, navigatorList,index);},gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5), )
itemBuilder中返回动态组件就行。
gridDelegate:里设置类型
6.3.4、主页广告区
- home_page.dart
class AdBanner extends StatelessWidget{String imgUrl ;AdBanner({Key key,this.imgUrl}):super(key:key);@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Container(height: ScreenUtil().setHeight(100),width: ScreenUtil().setWidth(750),child: Image.network(imgUrl,fit: BoxFit.fill,),);}}
添加一个图片组件即可
6.3.5、主页点击拨打电话功能
-
导入插件:import ‘package:url_launcher/url_launcher.dart’; //导入拨打电话获取发短信插件
- 需在pubspec.yml里添加版本
-
home_page.dart
class LeaderPhone extends StatelessWidget{String imgUrl;String phone;LeaderPhone({Key key,this.imgUrl,this.phone}):super(key:key);@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Container(height: ScreenUtil().setHeight(200),width: ScreenUtil().setWidth(750),
// 水波布局(一半亮一半暗) height: ScreenUtil().setHeight(100),child: InkWell(onTap: _launder,child: Image.network(imgUrl, fit: BoxFit.fill,),));}
// 拨打电话方法void _launder() async{String uri = 'tel:'+phone;if(await canLaunch(uri)){ //Launch内置方法判断是否正确uriawait launch(uri); //如果正确,就去往}else{throw "------------>Error:launcher的uri不正确";}}
}
注意:
- 主要组件就一个图片即可
- url_launcher用法
- 准备一个url
- 电话:tel:电话
- 网页:http:----
- 短信:sum:
- canLaunch:用来判断uri是否正确
- launch:去往uri地址。
6.3.6、主页商品推荐开发
- home_page
//商品推荐组件
class Recommend extends StatelessWidget {
// 准备一个数据final List recommendList;Recommend({Key key, this.recommendList}) : super(key: key);//子组件---》标题Widget _titleItem() {return Container(
// 剧中靠左alignment: Alignment.centerLeft,padding: EdgeInsets.only(left: 10),decoration: BoxDecoration(color: Colors.white,border: Border(bottom: BorderSide(width: 0.5, color: Colors.grey))),child: Text("商品推荐",style: TextStyle(color: Colors.blueAccent),),);}//子组件--->ListView的子组件Widget _ListViewItme(index) {return InkWell(onTap: () {},child: Container(height: ScreenUtil().setHeight(330),width: ScreenUtil().setWidth(250),padding: EdgeInsets.all(2),decoration: BoxDecoration(color: Colors.white,border: Border(left: BorderSide(width: 0.5, color: Colors.grey))),child: Column(children: <Widget>[Image.network(recommendList[index]['img']),Text("¥${recommendList[index]['money']}"),Text("¥${recommendList[index]['price']}",
// 设置删除线style: TextStyle(decoration: TextDecoration.lineThrough, color: Colors.grey),)],),),);}// 子组件---ListView横向Widget _recommendList() {return Container(height: ScreenUtil().setHeight(350),child: ListView.builder(itemCount: recommendList.length,scrollDirection: Axis.horizontal,itemBuilder: (context, index) {return _ListViewItme(index);},),);}@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Container(height: ScreenUtil().setHeight(400),margin: EdgeInsets.only(top: 10),child: Column(children: <Widget>[_titleItem(), _recommendList()],),);}
}
注意:
- 这里我们把一个复杂的组件,分成三个小组件
- decoration:设置边框
6.3.7、主页火爆商品—流体布局+上拉刷新------>flutter_easyrefresh
- home_page.dart—>布局
// 火爆商品的流水布局与网格布局差不多Widget _wrapList() {if (this.hotGoods.length != 0) {
// 使用集合装子组件List<Widget> listWidget = hotGoods.map((val) {return InkWell(onTap: () {},child: Container(width: ScreenUtil().setWidth(372),color: Colors.white,padding: EdgeInsets.all(5),margin: EdgeInsets.only(bottom: 3),child: Column(children: <Widget>[Image.network(val['img'],width: ScreenUtil().setWidth(370),),Text(val["name"],maxLines: 1,overflow: TextOverflow.ellipsis,style: TextStyle(color: Colors.pink, fontSize: ScreenUtil().setSp(26)),),Row(children: <Widget>[Text('¥${val['money']}'),Text('¥${val['newMoney']}',style: TextStyle(color: Colors.grey,decoration: TextDecoration.lineThrough),),],)],),),);}).toList();
// 流水布局return Wrap(
// 两列spacing: 2,children: listWidget,);} else {return Text("没有数据...");}}
注意:
这里使用了流体布局,其实和网格布局一样。
首先把组件装入一个List中
然后返回一个Wrap流体布局
spacing:2列
children:字布局集合
- home_page.dart—>上拉刷新**
// 自定义上拉刷新底部footer: ClassicalFooter(
// 背景颜色bgColor: Colors.white,
// 字体颜色textColor: Colors.pink,
// 加载时颜色infoColor: Colors.pink,
// 加载时的主标题loadedText: "数据正在过来...",
// 到底的字体noMoreText: '到底了',
// 加载时的文字infoText: "正在准备数据中...",loadReadyText: "上拉加载"),child: ListView(children: <Widget>[SwiperWidget(swiperDataList: listData,),TopNavigator(navigatorList: navgatorList,),AdBanner(imgUrl:"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3708973878,1447368046&fm=26&gp=0.jpg",),LeaderPhone(imgUrl:"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=146387912,579346698&fm=11&gp=0.jpg",phone: "17674078238",),Recommend(recommendList: reommedList,),FloorLayout(floorImgs: floorImgs,),FloorLayout(floorImgs: floorImgs,),_hotGoods()],),onLoad: () async{
// 上拉刷新回调// 这里就不访问网络了,之间假数据List<Map> newGoodsList = [{"img":"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=146387912,579346698&fm=11&gp=0.jpg","name": "美酒"+this.page.toString(),"money": "123213","newMoney": "432"},{"img":"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=146387912,579346698&fm=11&gp=0.jpg","name": "美酒"+(this.page+1).toString(),"money": "123213","newMoney": "432"},];setState(() {
// 刷新页面hotGoods.addAll(newGoodsList);if(hotGoods.length>10){hotGoods.clear();}this.page++;this.page++;});},);
注意:
- 这里修改了以前的布局
- 外父容器中:EasyRefresh
- 里嵌套中使用ListView
- 使用footer来自定义
- ClassicalFooter里包括了值
- onLoad刷新的回调
6.4、分类开发
6.4.1、分类页左侧主导航----provide(状态管理也就是全局双向数据绑定)
- provide插件
这个是谷歌自己出来的一个插件,用于管理状态的。
可以理解为是一个双向数据绑定,而且是全局的。
双向数据绑定就是,数据改变页面也会跟着改变。
- pubspec.yml
dependencies:flutter:sdk: flutter# The following adds the Cupertino Icons font to your application.# Use with the CupertinoIcons class for iOS style icons.cupertino_icons: ^0.1.2dio: ^3.0.0flutter_swiper: ^1.1.4flutter_screenutil: ^1.0.2url_launcher: ^5.1.3flutter_easyrefresh: ^2.1.1provide: ^1.0.2
导入provide
- 创建一个counter.dart全局类
import 'package:flutter/material.dart';//存入一个全局双向数据
class Counter with ChangeNotifier{int value = 0;increment(index){value = index;
// 刷新数据notifyListeners();}
}
创建一个全局类,并准备一个修改属性的方法,方法得刷新。
- main.dart
//导入插件并添加依赖
import 'package:flutter/material.dart';
//ios样式
import 'package:flutter/cupertino.dart';
import 'package:flutter_electricity/pages/index_page.dart';
//导入内容通过这provide双向数据绑定
import 'package:provide/provide.dart';
import 'provide/counter.dart';//导入双向绑定数据里的数据类void main() {
// 绑定全局双向数据模板var counter = Counter();var providers = Providers();providers..provide(Provider<Counter>.value(counter));runApp(ProviderNode(child: MyApp(),providers: providers,));
}
在lib—>创建provide–>counter.dart
修改了mian方法,这是官网的一个模板,不好解释,具体看文档;
- category_page.dart
//适合Android的布局
import 'package:flutter/material.dart';
import 'package:flutter_electricity/servceFun/servce_method.dart';
import 'dart:convert'; //引入json解析插件
import 'package:flutter_screenutil/flutter_screenutil.dart'; //导入适配组件
//导入内容通过这provide双向数据绑定
import 'package:provide/provide.dart';
import '../provide/counter.dart';//导入双向绑定数据里的数据类class CateGoryPage extends StatefulWidget {@override_CateGoryPage createState() => _CateGoryPage();
}class _CateGoryPage extends State<CateGoryPage> {@override@overrideWidget build(BuildContext context) {return Container(child: Scaffold(appBar: AppBar(title: Text("分类"),),body: Container(child: Row(children: <Widget>[LeftCatgegoryNav(),Provide<Counter> (builder: (context,child,counter){return Text("${counter.value}");},)],),),),);}
}
//左侧主导航
class LeftCatgegoryNav extends StatefulWidget {@override_LeftCatgegoryNavState createState() => _LeftCatgegoryNavState();
}class _LeftCatgegoryNavState extends State<LeftCatgegoryNav> {List list = [];@overridevoid initState() {_getCategory();super.initState();}@overrideWidget build(BuildContext context) {return Container(width: ScreenUtil().setWidth(180),decoration: BoxDecoration(border: Border(right: BorderSide(color: Colors.grey,width: 1))),child: ListView.builder(itemCount: this.list.length,itemBuilder: (context,index){return _leftInkWell(index);},),);}
// 子组件Widget _leftInkWell(int index){return InkWell(onTap: (){Provide.value<Counter>(context).increment(index);},child: Container(height: ScreenUtil().setHeight(100),padding: EdgeInsets.only(left: 10,top: 20),decoration: BoxDecoration(color: Colors.white,border: Border(bottom: BorderSide(width: 1,color: Colors.grey))),child: Text(this.list[index]["navMain"],style: TextStyle(color: Colors.pink,fontSize: ScreenUtil().setSp(26)),),),);}
// 获取数据void _getCategory(){getHomePageData().then((val){//使用假数据List cateList = [{'navMain':"分类1"},{'navMain':"分类2"},{'navMain':"分类3"}];setState(() {this.list = cateList;});});}
}
注意:
- 首先得导入provide
- 使用全局数据
Provide<Counter> (builder: (context,child,counter){return Text("${counter.value}");},
调用方法改变数据
Provide.value<Counter>(context).increment(index);
在其他也是用导入包,操作一样即可。
6.4.2、分类页右侧二级导航
这里使用provide来保持状态
- counter.dar(状态保持类)
import 'package:flutter/material.dart';//存入一个全局双向数据
class StateRightRiCategoryNav with ChangeNotifier{int index = 0;increment(index){this.index = index;
// 刷新数据notifyListeners();}
}
因为假数据的原因,这里我只保存了一个索引值
- 修改main.dart注入provide依赖
void main() {
// 绑定全局双向数据模板var state_RightRiCategoryNav = StateRightRiCategoryNav();var providers = Providers();providers..provide(Provider<StateRightRiCategoryNav>.value(state_RightRiCategoryNav));runApp(ProviderNode(child: MyApp(),providers: providers,));
}
这里按模板注入即可
- category_page.dart二级导航
//右侧二级导航
class RightCategoryNav extends StatefulWidget {@override_RightCategoryNavState createState() => _RightCategoryNavState();
}class _RightCategoryNavState extends State<RightCategoryNav> {List list = [['名酒1', '宝丰1', '北京二锅头1', '大明1', '散酒1', '红酒1', '白酒1'],['名酒2', '宝丰2', '北京二锅头2', '大明2', '散酒2', '红酒2', '白酒2'],['名酒3', '宝丰3', '北京二锅头3', '大明3', '散酒3', '红酒3', '白酒3'],];@overrideWidget build(BuildContext context) {return Container(height: ScreenUtil().setHeight(80),width: ScreenUtil().setWidth(570),decoration: BoxDecoration(border: Border(bottom: BorderSide(width: 1, color: Colors.grey))),child: ListView.builder(scrollDirection: Axis.horizontal,itemCount: list.length,itemBuilder: (context, index) {
// 使用全局状态管理数据return Provide<StateRightRiCategoryNav>(builder: (context,child,counter){return _rightInkWell(list[counter.index][index]);},);
// return _rightInkWell(list[index]);},),);}// 子组件Widget _rightInkWell(String item) {return InkWell(onTap: () {},child: Container(padding: EdgeInsets.fromLTRB(5, 10, 5, 10),child: Text(item,style: TextStyle(fontSize: ScreenUtil().setSp(28)),),),);}
//
}
注意:
list是一个四数据
传入到子组件中的list是用provide状态管理来传入的
6.4.3、分类页右侧内容数据–>fluttertoast吐丝插件
- category_page
//适合Android的布局
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_electricity/servceFun/servce_method.dart';
import 'dart:convert'; //引入json解析插件
import 'package:flutter_screenutil/flutter_screenutil.dart'; //导入适配组件
//导入内容通过这provide双向数据绑定
import 'package:provide/provide.dart';
import '../provide/counter.dart'; //导入双向绑定数据里的数据类// 定义一个跳转listView列表
var scorllController = new ScrollController();class CateGoryPage extends StatefulWidget {@override_CateGoryPage createState() => _CateGoryPage();
}class _CateGoryPage extends State<CateGoryPage> {@override@overrideWidget build(BuildContext context) {return Container(child: Scaffold(appBar: AppBar(title: Text("分类"),),body: Container(child: Row(children: <Widget>[LeftCatgegoryNav(),Column(children: <Widget>[RightCategoryNav(), CategorGoods()],)],),),),);}
}//左侧主导航
class LeftCatgegoryNav extends StatefulWidget {@override_LeftCatgegoryNavState createState() => _LeftCatgegoryNavState();
}class _LeftCatgegoryNavState extends State<LeftCatgegoryNav> {List list = [];int listIndex = 0;@overridevoid initState() {_getCategory();super.initState();}@overrideWidget build(BuildContext context) {return Container(width: ScreenUtil().setWidth(180),decoration: BoxDecoration(border: Border(right: BorderSide(color: Colors.grey, width: 1))),child: ListView.builder(itemCount: this.list.length,itemBuilder: (context, index) {return _leftInkWell(index);},),);}// 子组件Widget _leftInkWell(int index) {bool isClickList = false;isClickList = (index == listIndex) ? true : false;return InkWell(onTap: () {setState(() {listIndex = index;});Provide.value<StateRightRiCategoryNav>(context).increment(index);},child: Container(height: ScreenUtil().setHeight(100),padding: EdgeInsets.only(left: 10, top: 20),decoration: BoxDecoration(color: isClickList ? Colors.black26 : Colors.white,border: Border(bottom: BorderSide(width: 1, color: Colors.grey))),child: Text(this.list[index]["navMain"],style:TextStyle(color: Colors.pink, fontSize: ScreenUtil().setSp(26)),),),);}// 获取数据void _getCategory() {//使用假数据List cateList = [{'navMain': "分类1"},{'navMain': "分类2"},{'navMain': "分类3"}];setState(() {this.list = cateList;});
// getHomePageData().then((val){
//
// });}
}//右侧二级导航
class RightCategoryNav extends StatefulWidget {@override_RightCategoryNavState createState() => _RightCategoryNavState();
}class _RightCategoryNavState extends State<RightCategoryNav> {int itemIndex = 0; //点击的子导航List list = [['全部', '名酒1', '宝丰1', '北京二锅头1', '大明1', '散酒1', '红酒1', '白酒1'],['全部', '名酒2', '宝丰2', '北京二锅头2', '大明2', '散酒2', '红酒2', '白酒2'],['全部', '名酒3', '宝丰3', '北京二锅头3', '大明3', '散酒3', '红酒3', '白酒3'],];@overrideWidget build(BuildContext context) {return Container(height: ScreenUtil().setHeight(80),width: ScreenUtil().setWidth(570),decoration: BoxDecoration(border: Border(bottom: BorderSide(width: 1, color: Colors.grey))),child: Provide<StateRightRiCategoryNav>(builder: (context, child, counter) {return ListView.builder(scrollDirection: Axis.horizontal,itemCount: this.list[counter.index].length,itemBuilder: (context, index) {
// 使用全局状态管理数据return _rightInkWell(list[counter.index][index], index);
// return _rightInkWell(list[index]);},);},),);}// 子组件Widget _rightInkWell(String item, index) {bool itemIs = itemIndex == index ? true : false;return InkWell(onTap: () {scorllController.jumpTo(0);setState(() {itemIndex = index;});},child: Container(padding: EdgeInsets.fromLTRB(5, 10, 5, 10),child: Text(item,style: TextStyle(fontSize: ScreenUtil().setSp(28),color: itemIs ? Colors.pink : Colors.black),),),);}
//
}//右侧主内容区
class CategorGoods extends StatefulWidget {@override_CategorGoodsState createState() => _CategorGoodsState();
}class _CategorGoodsState extends State<CategorGoods> {//设置假数据List goodsList = [{'img':"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=146387912,579346698&fm=11&gp=0.jpg","name": "北京二锅头 55度1","newMoney": "134","money": "1423"},{'img':"https://img.alicdn.com/imgextra/i4/2201274259957/O1CN01vGHsvY2NQMCIR3qfB_!!2201274259957.jpg_430x430q90.jpg","name": "白酒 123度1","newMoney": "43","money": "1643"},{'img':"https://img.alicdn.com/imgextra/i4/3395417731/O1CN01lW1Wrk26yqaCL9Tk2-3395417731.jpg_430x430q90.jpg","name": "红酒 22度1","newMoney": "44","money": "5435"},{'img':"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=146387912,579346698&fm=11&gp=0.jpg","name": "北京二锅头 55度2","newMoney": "134","money": "1423"},{'img':"https://img.alicdn.com/imgextra/i4/2201274259957/O1CN01vGHsvY2NQMCIR3qfB_!!2201274259957.jpg_430x430q90.jpg","name": "白酒 123度2","newMoney": "43","money": "1643"},{'img':"https://img.alicdn.com/imgextra/i4/3395417731/O1CN01lW1Wrk26yqaCL9Tk2-3395417731.jpg_430x430q90.jpg","name": "红酒 22度2","newMoney": "44","money": "5435"},];@overrideWidget build(BuildContext context) {return Expanded(child: Container(width: ScreenUtil().setWidth(570),
// 使用了Expanded伸缩父容器,就无需加高
// height: ScreenUtil().setHeight(950),child: EasyRefresh(
// 自定义上拉刷新底部footer: ClassicalFooter(
// 背景颜色bgColor: Colors.white,
// 字体颜色textColor: Colors.pink,
// 加载时颜色infoColor: Colors.pink,
// 加载时的主标题loadedText: "数据正在过来...",
// 到底的字体noMoreText: '到底了',
// 加载时的文字infoText: "正在准备数据中...",loadReadyText: "上拉加载"),child: ListView.builder(controller: scorllController,itemCount: this.goodsList.length,itemBuilder: (context, index) {return _listViewItem(this.goodsList[index], index);}),onLoad: () async {
// 模拟添加数据setState(() {Map addObj = {'img':"https://img.alicdn.com/imgextra/i4/3395417731/O1CN01lW1Wrk26yqaCL9Tk2-3395417731.jpg_430x430q90.jpg","name": "红酒 22度2","newMoney": "44","money": "5435"};goodsList.add(addObj);if (goodsList.length > 12) {//提示到底了Fluttertoast.showToast(msg: "到底了",//提示时间toastLength: Toast.LENGTH_LONG,//提示位置gravity: ToastGravity.BOTTOM,backgroundColor: Colors.pink,textColor: Colors.white,fontSize: ScreenUtil().setSp(16));}});},)),);}// 子组件--->listItemWidget _listViewItem(Map item, int index) {return InkWell(onTap: () {},child: Container(decoration: BoxDecoration(border: Border(bottom: BorderSide(width: 1, color: Colors.grey))),padding: EdgeInsets.all(10),width: ScreenUtil().setWidth(570),height: ScreenUtil().setHeight(200),child: Row(children: <Widget>[Image.network(item['img'],width: ScreenUtil().setWidth(200),),Container(margin: EdgeInsets.only(left: 20),child: Column(children: <Widget>[Container(child: Text("${item['name']}",style: TextStyle(fontSize: ScreenUtil().setSp(36),),maxLines: 1,overflow: TextOverflow.ellipsis,),width: ScreenUtil().setWidth(210),),Container(width: ScreenUtil().setWidth(210),margin: EdgeInsets.only(top: 10),child: Row(children: <Widget>[Text("价格:¥${item['newMoney']}",style: TextStyle(fontSize: ScreenUtil().setSp(26),color: Colors.pink),maxLines: 1,overflow: TextOverflow.ellipsis,),Text("¥${item['money']}",style: TextStyle(fontSize: ScreenUtil().setSp(16),decoration: TextDecoration.lineThrough),maxLines: 1,overflow: TextOverflow.ellipsis,),],),)],),)],),),);}
}
注意:这里是分类的全部代码
- ScrollController()是一个listview的跳转类
- 首先定义全局的:var scorllController = new ScrollController();
- 其次在跳转的listview中调节controller: scorllController,属性
- 最后是跳转代码:scorllController.jumpTo(0);这里是跳转到最前面;
- Expanded父容器布局是一个拉伸布局
- 它可以不用设置高.
- Fluttertoast用于吐丝的一个插件
6.5、详细数据页面开发
6.5.1、详细页面开发---->fluro路由插件
-
首先完成fluro框架
-
导入插件import ‘package:fluro/fluro.dart’;需要在pubspec.yml文件加入版本。
-
创建一个routers文件夹
- 创建routers.dart主配置文件
import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:flutter_electricity/routers/router_handler.dart';class Routers{ // 配置路由路径static String root='/';static String detailspage ='/detail';static void configureRouter(Router router){//找不到路由handlerFunc: (BuildContext context,Map<String,List<String>> pagems){print("找不到页面");};router.define(detailspage, handler: detailsHandler); //找到路由并跳转} }
注意:
- 配置的detail路径是用来访问页面的
- detailsHandler是跳转的下一个页面,这里再router_handler包下
- 创建一个router_handler.dart跳转配置文件
import 'package:flutter/material.dart'; import 'package:fluro/fluro.dart'; import '../pages/details_page.dart';Handler detailsHandler = Handler(handlerFunc: (BuildContext context,Map<String,List<String>> pagems){String goodsId = pagems['id'].first;print("页面id:${goodsId}");return DetailsPage(goodsId);} );
注意:
- 这里是配置一个跳转的handler路由文件
- pagems用来接收跳转时传入的一个参数
- 返回DetailsPage页面并把参数给页面
- ,Map<String,List> pagems是模板
- routerApplication.dart静态化router使得使用时,不需要实例化
import 'package:fluro/fluro.dart';//静态化router class routerApp{static Router router; }
这个可写可不写,建议写好。
-
在main.dart文件注入router依赖,并把路由显示到容器
class MyApp extends StatelessWidget{@overrideWidget build(BuildContext context) { // 注入路由显示final router = Router();Routers.configureRouter(router);//添加路由配置routerApp.router = router; //路由静态化// TODO: implement buildreturn MaterialApp(title: "电商管理",onGenerateRoute: routerApp.router.generator, //把路由来的页面放在容器中显示debugShowCheckedModeBanner: false,theme: ThemeData(primaryColor: Colors.pink),home: Scaffold( // appBar: new AppBar(title: Text("主页"),),body: Center(child: IndexPage(),),),);}}
注意:
- 在build方法内,注入router配置
- onGenerateRoute用来指定路由显示在那个容器中。
- routerApp.router.generator路由页面
-
-
在相应位置中,点击router跳转
// 一路由跳转到详细页面
routerApp.router.navigateTo(context, "/detail?id=${Random().nextInt(10)}");
注意:
- 参数1-上下文
- 参数2-路径+参数
6.5.2、详细数据页,使用Provdio来获取网络数据
- 在provide文件夹里新建一个details_info.dart文件
import 'dart:convert';import 'package:flutter/material.dart';
import 'package:flutter_electricity/model/details.dart';
import 'dart:async';
import '../servceFun/servce_method.dart';//注册商品详细的全局数据
class DateilsInfoProvide with ChangeNotifier{DetailsEntity detailsData = null;getGoodsInfo(){getHomePageData().then((val){
// 转为实体var details = json.decode(val.toString());detailsData = DetailsEntity.fromJson(details);//刷新notifyListeners();});}
}
注意:
- 这里使用全局绑定数据在detailsData
- 这里使用接收json转为实体对象,然后刷新
- 在main.dart中注入
void main() {
// 绑定全局双向数据模板var state_RightRiCategoryNav = StateRightRiCategoryNav();var dateilsInfoProvide= DateilsInfoProvide();var providers = Providers();providers..provide(Provider<StateRightRiCategoryNav>.value(state_RightRiCategoryNav));providers..provide(Provider<DateilsInfoProvide>.value(dateilsInfoProvide));runApp(ProviderNode(child: MyApp(),providers: providers,));
}
- providers…provide方式注入即可
- 这是就可以开始使用了
6.5.3、详细页面开发,ui基本布局----flutter_html显示网页
- details_page.dart
return Container(child: ListView(children: <Widget>[DetailsTopArea(), //这是详细页面--头部DetailsExplain(), //详细页面--通知DetailsTabbar(), //切换标签DetailsWeb() //显示切换页面],),
);
这里主要添加子页面
- 在details_page文件夹里创建一个details_tabbar.dart
import 'package:flutter/material.dart';
import 'package:flutter_electricity/provide/details_info.dart';
import 'package:flutter_screenutil/screenutil.dart';
import 'package:provide/provide.dart';class DetailsTabbar extends StatelessWidget {@overrideWidget build(BuildContext context) {return Provide<DateilsInfoProvide>(builder: (context, chuild, data) {return Container(color: Colors.white,margin: EdgeInsets.only(top: 10, left: 15),width: ScreenUtil().setWidth(750),child: Row(children: <Widget>[InkWell(onTap: () {Provide.value<DateilsInfoProvide>(context).updateIsMsg(1);},child: Container(decoration: BoxDecoration(border: Border(bottom: data.isMsg1? BorderSide(width: 2, color: Colors.pink): BorderSide(width: 0))),alignment: Alignment.center,width: ScreenUtil().setWidth(350),child: Text("详细",style: TextStyle(fontSize: ScreenUtil().setSp(30)),),),),InkWell(onTap: () {Provide.value<DateilsInfoProvide>(context).updateIsMsg(2);},child: Container(decoration: BoxDecoration(border: Border(bottom: data.isMsg2? BorderSide(width: 2, color: Colors.pink): BorderSide(width: 0))),alignment: Alignment.center,width: ScreenUtil().setWidth(350),child: Text("商品",style: TextStyle(fontSize: ScreenUtil().setSp(30)),),),)],),);});}
}
这个没什么技术难点,就两个便签利用provide值切换样式
- 同样在文件夹里创建dateils_web.dart
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import 'package:provide/provide.dart';
import 'package:flutter_electricity/provide/details_info.dart';class DetailsWeb extends StatelessWidget {@overrideWidget build(BuildContext context) {return Provide<DateilsInfoProvide>(builder: (context,chuild,data){int indexMsg = data.isMsg1?1:2;return Container(child: Html(data: data.detailsData["html"+indexMsg.toString()],),);});}
}
注意:
- 这里使用了flutter_html插件,用来显示html网页
- 导入flutter_html: any,我当前用的版本是1.0.0但与其他依赖冲突,所以使用any适配依赖注入
- 使用Provide里的值显示即可
- details_info.dat
import 'dart:convert';import 'package:flutter/material.dart';
import 'package:flutter_electricity/model/details.dart';
import 'dart:async';
import '../servceFun/servce_method.dart';//注册商品详细的全局数据
class DateilsInfoProvide with ChangeNotifier {Map detailsData = null;bool isMsg1 = true;bool isMsg2 = false;getGoodsInfo() async{getHomePageData().then((val) {// 转为实体var details = json.decode(val.toString());// detailsData = DetailsEntity.fromJson(details);detailsData = {"url":"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2809691443,3777995480&fm=26&gp=0.jpg","name": "红酒","num": "01110321","newMoney": "288","money": "490","html1":'自己网上找',"html2":'自己网上找'};// 这里就模拟数据,不用接口数据//刷新notifyListeners();});}//切换详细信息updateIsMsg(int msg) {if(msg == 1){this.isMsg1 = true;this.isMsg2 = false;}else{this.isMsg1 = false;this.isMsg2 = true;}notifyListeners();}
}
注意:
- 这里用的都是静态的,模拟数据。但调用了接口
6.5.4、详细页面开发-底部购买区
-
修改details_page页面的父布局为重叠布局
return Stack(children: <Widget>[// 内容详细Container(child: ListView(children: <Widget>[DetailsTopArea(), //这是详细页面--头部DetailsExplain(), //详细页面--通知DetailsTabbar(), //切换标签DetailsWeb() //显示切换页面],),),// 底部购买区域Positioned(bottom: 0,left: 0,child: DetailsBottom(),)], );
这里使用使用重叠布局,吧购买区域悬浮最下面
-
在details_page文件夹里创建details_bottom.dart
import 'package:flutter/material.dart';
import 'package:flutter_electricity/provide/details_info.dart';
import 'package:flutter_screenutil/screenutil.dart';
import 'package:provide/provide.dart';class DetailsBottom extends StatelessWidget {@overrideWidget build(BuildContext context) {return Container(width: ScreenUtil().setWidth(750),color: Colors.white,height: ScreenUtil().setHeight(100),child: Row(children: <Widget>[
// 图标InkWell(onTap: (){},child: Container(width: ScreenUtil().setWidth(110),alignment: Alignment.center,child: Icon(Icons.shopping_cart,size: 35,color: Colors.pink,),),),InkWell(onTap: (){},child: _BottomAdd(),),InkWell(onTap: (){},child: _BottomMai(),)],),);}
// 加入购物车
Widget _BottomAdd(){return Container(alignment: Alignment.center,width: ScreenUtil().setWidth(320),height: ScreenUtil().setHeight(100),color: Colors.pink,child: Text("加入购物车",style: TextStyle(color: Colors.white,fontSize: ScreenUtil().setSp(28)),),);
}
// 购买Widget _BottomMai(){return Container(alignment: Alignment.center,width: ScreenUtil().setWidth(320),height: ScreenUtil().setHeight(100),color: Colors.amberAccent,child: Text("立即购买",style: TextStyle(color: Colors.white,fontSize: ScreenUtil().setSp(28)),),);}
}
这里使用InkWell布局才能点击
6.6、购物车页面开发
6.6.1、使用shared_preferences来存入本地数据–测试------shared_preferences
- 首先导入插件,并在pubspec.yml导入版本
- 在provide文件夹里创建一个cart_info.dat文件
import 'dart:convert';import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';class CartProvide with ChangeNotifier {String cartString = null;// 保存方法save(goodsName, money, image) async {SharedPreferences prefs = await SharedPreferences.getInstance(); //实例化本地储存cartString = prefs.getString("cartInfo"); //获取本地值var temp = cartString == null? []: json.decode(cartString.toString()); //将字符串转为listList<Map> tempList = (temp as List).cast(); //转为list//判断重复并count++bool isSave = false;int ival = 0;tempList.forEach((item) {//循环if (item['goodsName'] == goodsName) {//如果找到一样的商品tempList[ival]['count'] = item['count'] + 1;isSave = true; //标记已经添加}ival++;});
// 真正的添加if (!isSave) {tempList.add({'goodsName': goodsName,'count': 1, //第一次添加为0'money': money,'image': image,});}// 将list转为字符串并存入本地cartString = json.encode(tempList).toString();prefs.setString("cartInfo", cartString);print(cartString);notifyListeners(); //刷新provide}// 清空方法remove() async {SharedPreferences prefs = await SharedPreferences.getInstance(); //实例化本地储存prefs.remove("cartInfo");print("清空完成--------------");notifyListeners();//刷新provide}
}
注意:
- 这里主要使用了SharedPreferences来储存数据
- SharedPreferences储存式只能储存字符串
- json.decode(cartString.toString()); //将字符串转为list
- List
- json.encode(tempList).toString();//将list转为字符串
- 准备了两个方法:save用于保存,remove用于清空,当然这里数据都是虚拟的。
- prefs.setString(“cartInfo”, cartString);存入即可.
-
main.dart中注入依赖
void main() { // 绑定全局双向数据模板var state_RightRiCategoryNav = StateRightRiCategoryNav();var dateilsInfoProvide= DateilsInfoProvide();var cartInfoProvide= CartProvide();//---var providers = Providers();providers..provide(Provider<StateRightRiCategoryNav>.value(state_RightRiCategoryNav));providers..provide(Provider<DateilsInfoProvide>.value(dateilsInfoProvide));providers..provide(Provider<CartProvide>.value(cartInfoProvide));//---runApp(ProviderNode(child: MyApp(),providers: providers,)); }
-
最后调用其方法
onTap: () {// 加入购物车Provide.value<CartProvide>(context).save(goodsInfo['name'], goodsInfo['newMoney'], goodsInfo['url']);
},
onTap: (){//清空购物车Provide.value<CartProvide>(context).remove();
},
6.6.2、购物车页面开发—公司规范性
- cart_info.dart数据处理文件
import 'dart:convert';
import 'dart:math';import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';class CartProvide with ChangeNotifier {String cartString = null;List<Map> listCart = null;double moneyAll = 0;int goodsCount = 0;bool isAllCheack = false;// 保存方法save(goodsName, money, image, isCheack) async {goodsName = goodsName + Random().nextInt(3).toString();SharedPreferences prefs = await SharedPreferences.getInstance(); //实例化本地储存cartString = prefs.getString("cartInfo"); //获取本地值var temp = cartString == null? []: json.decode(cartString.toString()); //将字符串转为listList<Map> tempList = (temp as List).cast(); //转为list//判断重复并count++bool isSave = false;int ival = 0;goodsCount = 0;tempList.forEach((item) {//循环if (item['goodsName'] == goodsName) {//如果找到一样的商品tempList[ival]['count'] = item['count'] + 1;isSave = true; //标记已经添加}if (item["isCheack"]) {goodsCount++;
// moneyAll+=;}});
// 真正的添加if (!isSave) {tempList.add({'goodsName': goodsName,'count': 1, //第一次添加为0'money': money,'image': image,'isCheack': isCheack});}// 将list转为字符串并存入本地cartString = json.encode(tempList).toString();prefs.setString("cartInfo", cartString);notifyListeners(); //刷新provide}// 清空方法remove() async {SharedPreferences prefs = await SharedPreferences.getInstance(); //实例化本地储存prefs.remove("cartInfo");print("清空完成--------------");notifyListeners(); //刷新provide}// 删除一个购物车商品deleteOneGoods(String goodsName) async {SharedPreferences prefs = await SharedPreferences.getInstance(); //实例化本地储存cartString = prefs.getString('cartInfo');List<Map> tempList = (json.decode(cartString.toString()) as List).cast();for (int i = 0; i < tempList.length; i++) {if (tempList[i]['goodsName'] == goodsName) {tempList.removeAt(i);break;}}cartString = json.encode(tempList).toString();prefs.setString("cartInfo", cartString);await getCartData();}//查询getCartData() async {SharedPreferences prefs = await SharedPreferences.getInstance(); //实例化本地储存cartString = prefs.getString("cartInfo");var temp = cartString == null? []: json.decode(cartString.toString()); //将字符串转为listlistCart = (temp as List).cast(); //转为listmoneyAll = 0;goodsCount = 0;double temMomey = 0;for (int i = 0; i < listCart.length; i++) {if (listCart[i]['isCheack']) {goodsCount++;temMomey = double.parse(listCart[i]['money']);}}moneyAll += temMomey;print(listCart.length);if (goodsCount == listCart.length)isAllCheack = true;elseisAllCheack = false;notifyListeners();}// 选择单个changeCheckState(goodsName) async {SharedPreferences prefs = await SharedPreferences.getInstance(); //实例化本地储存cartString = prefs.getString("cartInfo");List<Map> tempList =(json.decode(cartString.toString()) as List).cast(); //转为listfor (int i = 0; i < tempList.length; i++) {if (tempList[i]['goodsName'] == goodsName) {tempList[i]['isCheack'] = !tempList[i]['isCheack'];break;}}cartString = json.encode(tempList).toString();prefs.setString("cartInfo", cartString);await getCartData();}// 全选changeCheckALl(bool val) async {SharedPreferences prefs = await SharedPreferences.getInstance(); //实例化本地储存cartString = prefs.getString("cartInfo");List<Map> tempList =(json.decode(cartString.toString()) as List).cast(); //转为listfor (int i = 0; i < tempList.length; i++) {tempList[i]['isCheack'] = val;}cartString = json.encode(tempList).toString();prefs.setString("cartInfo", cartString);await getCartData();}// 商品加减addOrReduceData(goodsName, bool isAR) async {SharedPreferences prefs = await SharedPreferences.getInstance(); //实例化本地储存cartString = prefs.getString("cartInfo");List<Map> tempList =(json.decode(cartString.toString()) as List).cast(); //转为listfor (int i = 0; i < tempList.length; i++) {if (tempList[i]['goodsName'] == goodsName) {if (isAR) {//true为加if (tempList[i]['count'] < 10) tempList[i]['count']++;} else {//同理减tempList[i]['count']--;if (tempList[i]['count'] == 0) {deleteOneGoods(goodsName);}}break;}}cartString = json.encode(tempList).toString();prefs.setString("cartInfo", cartString);await getCartData();}
}
注意:
- 这个主要处理数据,然后通过prefs保存,最后provide显示
- cart_page.dart主界面
//适合Android的布局
import 'package:flutter/material.dart';
import 'package:flutter_electricity/provide/cart_info.dart';//导入内容通过这provide双向数据绑定
import 'package:provide/provide.dart';
import '../provide/counter.dart';
import 'cart_page/cart_bottom.dart';
import 'cart_page/cart_item.dart'; //导入双向绑定数据里的数据类void main() => runApp(CartPage());class CartPage extends StatelessWidget {@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar: AppBar(title: Text("购物车"),),body: FutureBuilder(future: _getCatData(context),builder: (context, data) {if (data.hasData) {return Stack(children: <Widget>[Provide<CartProvide>(builder: (context,chuild,data){List<Map> list = Provide.value<CartProvide>(context).listCart;print("---");print(list.toString()+"---");return ListView.builder(itemBuilder: (context, index) {return CartItem(list[index]);},itemCount: list.length,);}),Positioned(bottom: 0,left: 0,child: CartBottom(),)],);} else {return Text("正在加载...");}},),);}Future<String> _getCatData(BuildContext context) async {await Provide.value<CartProvide>(context).getCartData();return "调用获取购物车";}
}
注意:
- 这里我们把一个页面拆分了好几个组件显示
-
子组件
- cart_bottom.dart
import 'package:flutter/material.dart'; import 'package:flutter_electricity/provide/cart_info.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:provide/provide.dart';class CartBottom extends StatelessWidget {@overrideWidget build(BuildContext context) {return Container(padding: EdgeInsets.all(5.0),color: Colors.white,child:Provide<CartProvide>(builder: (context,chuil,data){return Row(children: <Widget>[_selectAllBtn(context),_allPriceArea(data.moneyAll),_goButton(data.goodsCount)],);},));}// 子组件Widget _selectAllBtn(BuildContext context) {return Container(child: Provide<CartProvide>(builder: (context,chuild,data){return Row(children: <Widget>[Checkbox(value: Provide.value<CartProvide>(context).isAllCheack,activeColor: Colors.pink,onChanged: (bool val) {Provide.value<CartProvide>(context).changeCheckALl(val);},),Text("全选")],);},));}//中价格Widget _allPriceArea(double moneyAll) {return Container(width: ScreenUtil().setWidth(430),child: Column(children: <Widget>[Row(children: <Widget>[Container(alignment: Alignment.centerRight,width: ScreenUtil().setWidth(280),child: Text("合计",style: TextStyle(fontSize: ScreenUtil().setSp(36)),),),Container(alignment: Alignment.centerLeft,width: ScreenUtil().setWidth(150),child: Text("¥${moneyAll}",style: TextStyle(fontSize: ScreenUtil().setSp(36), color: Colors.pink),),),],),Container(width: ScreenUtil().setWidth(430),alignment: Alignment.centerRight,child: Text("满10元免费配送,预购免配送费",style: TextStyle(color: Colors.black26, fontSize: ScreenUtil().setSp(22)),),)],),);} // 确认订单 Widget _goButton(int goodsCount){return Container(width: ScreenUtil().setWidth(160),padding: EdgeInsets.only(left: 10),child: InkWell(onTap: (){},child: Container(padding: EdgeInsets.all(10),alignment: Alignment.center,decoration: BoxDecoration(color: Colors.pink,borderRadius: BorderRadius.circular(3)),child: Text("结算(${goodsCount})",style: TextStyle(color: Colors.white),),),),); } }
- cart_item.dart
import 'package:flutter/material.dart'; import 'package:flutter_electricity/provide/cart_info.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:provide/provide.dart';class CartItem extends StatelessWidget { // 准备一个数据final Map item;CartItem( this.item) ;@overrideWidget build(BuildContext context) {return Container(height: ScreenUtil().setHeight(180),margin: EdgeInsets.all(5),padding: EdgeInsets.all(5),decoration: BoxDecoration(color: Colors.white,border: Border(bottom: BorderSide(width: 1, color: Colors.black26))),child: Row(children: <Widget>[_cartCheckBt(context,item['goodsName']),_cartImage(),_cartGoodsName(context,item),_cartPrice(context,item['goodsName'])],),);}//选择Widget _cartCheckBt(BuildContext context,goodsName) {return Container(child: Checkbox(value: item["isCheack"],activeColor: Colors.pink,onChanged: (bool val) {Provide.value<CartProvide>(context).changeCheckState(goodsName);},),);}//商品图片Widget _cartImage() {return Container(width: ScreenUtil().setWidth(150),padding: EdgeInsets.all(3),decoration:BoxDecoration(border: Border.all(width: 1, color: Colors.black26)),child: Image.network(item["image"]),);}//商品名称Widget _cartGoodsName(BuildContext context,item) {return Container(width: ScreenUtil().setWidth(300),padding: EdgeInsets.all(10),alignment: Alignment.topLeft,child: Column(children: <Widget>[Text("${item["goodsName"]}",overflow: TextOverflow.ellipsis,),_cartCount(context,item)],),);} // 商品个数Widget _cartCount(BuildContext context,item){return Container(width: ScreenUtil().setWidth(165),margin: EdgeInsets.only(top: 10),decoration: BoxDecoration(border: Border.all(width: 1,color: Colors.black26)),child: Provide<CartProvide>(builder: (context,chuild,data){return Row(children: <Widget>[InkWell(onTap: (){//减Provide.value<CartProvide>(context).addOrReduceData(item["goodsName"], false);},child: Container(width: ScreenUtil().setWidth(45),height: ScreenUtil().setHeight(45),alignment: Alignment.center,decoration: BoxDecoration(color: Colors.white,border: Border(right: BorderSide(width: 1,color: Colors.black26))),child: Text("-"),),),Container(width: ScreenUtil().setWidth(70),height:ScreenUtil().setHeight(45),alignment: Alignment.center,color: Colors.white,child: Text("${item['count']}"),),InkWell(onTap: (){//加Provide.value<CartProvide>(context).addOrReduceData(item["goodsName"], true);},child: Container(width: ScreenUtil().setWidth(45),height: ScreenUtil().setHeight(45),alignment: Alignment.center,decoration: BoxDecoration(color: Colors.white,border: Border(left: BorderSide(width: 1,color: Colors.black26))),child: Text("+"),),)],);},));} // 价格 Widget _cartPrice(BuildContext context,goodsName){return Container(width: ScreenUtil().setWidth(150),alignment: Alignment.centerRight,child: Column(children: <Widget>[Text("¥${item['money']}"),Container(margin: EdgeInsets.only(top: 30),child: InkWell(onTap: (){Provide.value<CartProvide>(context).deleteOneGoods(goodsName);},child: Icon(Icons.delete_outline,color: Colors.black26,size: 30,),),)],),); } }
6.7、会员中心页面开发
//适合Android的布局
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; //导入适配组件void main() => runApp(MembarPage());class MembarPage extends StatelessWidget {@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Scaffold(appBar: AppBar(title: Text("会员中心"),),body: Center(child: Container(child: ListView(children: <Widget>[_topHeader(), _orderTitile(), _orderType(),_orderList()],),)),);}_topHeader() {return Container(padding: EdgeInsets.only(top: 50),color: Colors.pink,child: Column(children: <Widget>[Container(child: ClipOval(child: Image.network("https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=146387912,579346698&fm=11&gp=0.jpg",width: ScreenUtil().setWidth(200),height: ScreenUtil().setHeight(200),),)),Container(child: Text("会员中心",style: TextStyle(color: Colors.white),),),],),);}//订单标题_orderTitile() {return Container(margin: EdgeInsets.only(top: 10),decoration: BoxDecoration(color: Colors.white,border: Border(bottom: BorderSide(width: 1, color: Colors.black26))),child: ListTile(leading: Icon(Icons.list),title: Text("我的订单"),trailing: Icon(Icons.arrow_forward),),);}// 订单模块_orderType() {return Container(margin: EdgeInsets.only(top: 5),width: ScreenUtil().setWidth(750),height: ScreenUtil().setHeight(150),padding: EdgeInsets.only(top: 20),color: Colors.white,child: Row(children: <Widget>[Container(width: ScreenUtil().setWidth(187),child: Column(children: <Widget>[Icon(Icons.query_builder,size: 30,),Text("待付款")],),),//------------------Container(width: ScreenUtil().setWidth(187),child: Column(children: <Widget>[Icon(Icons.access_alarms,size: 30,),Text("待发货")],),),//------------------Container(width: ScreenUtil().setWidth(187),child: Column(children: <Widget>[Icon(Icons.card_travel,size: 30,),Text("待收货")],),),//------------------Container(width: ScreenUtil().setWidth(187),child: Column(children: <Widget>[Icon(Icons.filter_vintage,size: 30,),Text("待评价")],),),//------------------],),);}// list
_orderList(){return Container(margin: EdgeInsets.only(top: 10),color: Colors.white,child: Column(children: <Widget>[Container(padding: EdgeInsets.only(left: 10,right: 10),child: ListTile(leading: Icon(Icons.filter,size: 20,),title: Text("获取优惠卷"),trailing: Icon(Icons.arrow_forward,size: 20,),),),Container(padding: EdgeInsets.only(left: 10,right: 10),child: ListTile(leading: Icon(Icons.filter,size: 20,),title: Text("已领取优惠卷"),trailing: Icon(Icons.adjust,size: 20,),),),Container(padding: EdgeInsets.only(left: 10,right: 10),child: ListTile(leading: Icon(Icons.filter,size: 20,),title: Text("地址管理"),trailing: Icon(Icons.pin_drop,size: 20,),),),Container(padding: EdgeInsets.only(left: 10,right: 10),child: ListTile(leading: Icon(Icons.filter,size: 20,),title: Text("客户电话"),trailing: Icon(Icons.phone,size: 20,),),),],));
}
}
到这里结束了。
最后打包apk记得添加权限
{{flutterPorject}}\android\app\src\main\AndroidManifest.xml
manifet文件夹里
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> //访问电话状态<uses-permission android:name="android.permission.INTERNET" /> //允许全部网络访问<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> //获取网络信息状态<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> //获取当前WiFi接入的状态以及WLAN热点的信息
实战–》遇见坑
启动错误,出现卡住
- 错误
Waiting for another flutter command to release the startup lock…
- 解决
- 打开后台,关闭所有的dart进程
- 打开flutter安装目录/bin/cache删除lockfile文件
- 打开越网
- set PUB_HOSTED_URL=https://pub.flutter-io.cn
- set FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
- 可以使用flutter命令了。
父容器越界(超出)
-
解决
//适合Android的布局 import 'package:flutter/material.dart'; import 'package:dio/dio.dart';class HomePage extends StatefulWidget{@overrideState<StatefulWidget> createState() {// TODO: implement createStatereturn HomePageState();}}class HomePageState extends State<HomePage> { // 声明数据:一定记得实例化TextEditingController inputValue = TextEditingController();@overrideWidget build(BuildContext context) {// TODO: implement buildreturn Container(child: Scaffold(appBar: AppBar(title: Text("首页"),),body: SingleChildScrollView(child: Column(children: <Widget>[TextField(controller: inputValue ,decoration: InputDecoration(labelText: "提示文本",helperText: "下边提示文本",contentPadding: EdgeInsets.all(10)),autofocus: false,),RaisedButton(child: Text("点击获取"),onPressed: (){getInput( context);},),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),],),)),);} // 测试输入框void getInput(context) {showDialog(context: context,builder: (context) => AlertDialog(title: Text("文本框:"+inputValue.text.toString()),));}// 准备一个测试网络的方法Future getHttp() async {try {Response response;response = await Dio().get("https://v1.hitokoto.cn/");return print(response);} catch (e) {return print(e);}} }
注意:
- 这里的Text是我故意越界
- 在body布局开始时加上SingleChildScrollView
- 里的child里布局
- 会更ListView冲突
访问接口出现451问题
- 问题解析
在计算机网上领域中,HTTP 451 因法律原因不可用(英语:HTTP 451 Unavailable For Legal Reasons)是一种HTTP协议的错误状态代码,当用户请求访问某个经政府审核等查核方法后认定不合法的来源时,就会显示这个错误代码。
-
解决问题
-
准备一个请求头—>接口里的---->Request Headers里全部
-
创建一个dart文件
const jikeHead = { 'Accept': 'application/json, text/plain, */*', 'Accept-Encoding':'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', 'Connection': 'keep-alive', 'Cookie': 'LF_ID=1588471987694-7544553-574131; _ga=GA1.2.60515761.1588471988; _gid=GA1.2.1683854147.1588471988; _gat=1; GRID=0b448de-8b6f706-eee4cd0-6806924; SERVERID=1fa1f330efedec1559b3abbcb6e30f50|1588472006|1588471988', 'Host': 'live.geekbang.org', 'Origin': 'https://time.geekbang.org', 'Referer': 'https://time.geekbang.org/', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-site', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', };
注意:
格式是键值关系,并且是字符串.
-
导入该文件
//导入极客的头文件 import 'package:flutter_electricity/config/httpHead.dart';
- DIO请求时设置头
Dio dio = new Dio(); dio.options.headers = jikeHead; response = await dio.get("https://live.geekbang.org/serv/v1/stage/live?channel_id=1");
-
动态页面—>页面保持状态
问题
主要问题:页面不能保持,每次切换页面时,都会重新调用节课,并重新渲染
解决
-
方法一
- 首先修改主动态组件框架里的body
body: IndexedStack(index: currentIndex,children: bodyList,));
- index:当前页面
- children:所有页面组合
- 把子页面混合一个AutomaticKeepAliveClientMixin并继承方法
class HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin { // 混入动态界面保持状态@override// TODO: implement wantKeepAlivebool get wantKeepAlive => true;
-
方法二
- 直接在主动态组件框架里的body添加Offstage
body: Stack(children: <Widget>[Offstage(offstage: currentIndex != 0,child: tabBodies[0],),Offstage(offstage: currentIndex != 1,child: tabBodies[1],),Offstage(offstage: currentIndex != 2,child: tabBodies[2],),Offstage(offstage: currentIndex != 3,child: tabBodies[3],),], ),
- offstage:如果不是当前页面
- child:当前页面
json对象转换为dart对象
与java中的Gost转为java对象差不多
-
首先进入网站得到对象
- https://javiercbk.github.io/json_to_dart/
- 得到对象后复制到你都dart文件即可。
-
其次代码转换即可
//对象.formJson(json串)
helperText: "下边提示文本",contentPadding: EdgeInsets.all(10)),autofocus: false,),RaisedButton(child: Text("点击获取"),onPressed: (){getInput( context);},),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),Text("fdsa"),],),)), );
}
// 测试输入框
void getInput(context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(“文本框:”+inputValue.text.toString()),
));
}// 准备一个测试网络的方法
Future getHttp() async {
try {
Response response;
response = await Dio().get(“https://v1.hitokoto.cn/”);
return print(response);
} catch (e) {
return print(e);
}
}
}> 注意: > > + 这里的Text是我故意越界 > + 在body布局开始时加上SingleChildScrollView > + 里的child里布局 > + 会更ListView冲突
访问接口出现451问题
- 问题解析
在计算机网上领域中,HTTP 451 因法律原因不可用(英语:HTTP 451 Unavailable For Legal Reasons)是一种HTTP协议的错误状态代码,当用户请求访问某个经政府审核等查核方法后认定不合法的来源时,就会显示这个错误代码。
-
解决问题
-
准备一个请求头—>接口里的---->Request Headers里全部
-
创建一个dart文件
const jikeHead = { 'Accept': 'application/json, text/plain, */*', 'Accept-Encoding':'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8', 'Connection': 'keep-alive', 'Cookie': 'LF_ID=1588471987694-7544553-574131; _ga=GA1.2.60515761.1588471988; _gid=GA1.2.1683854147.1588471988; _gat=1; GRID=0b448de-8b6f706-eee4cd0-6806924; SERVERID=1fa1f330efedec1559b3abbcb6e30f50|1588472006|1588471988', 'Host': 'live.geekbang.org', 'Origin': 'https://time.geekbang.org', 'Referer': 'https://time.geekbang.org/', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'same-site', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36', };
注意:
格式是键值关系,并且是字符串.
-
导入该文件
//导入极客的头文件 import 'package:flutter_electricity/config/httpHead.dart';
- DIO请求时设置头
Dio dio = new Dio(); dio.options.headers = jikeHead; response = await dio.get("https://live.geekbang.org/serv/v1/stage/live?channel_id=1");
-
动态页面—>页面保持状态
问题
主要问题:页面不能保持,每次切换页面时,都会重新调用节课,并重新渲染
解决
-
方法一
- 首先修改主动态组件框架里的body
body: IndexedStack(index: currentIndex,children: bodyList,));
- index:当前页面
- children:所有页面组合
- 把子页面混合一个AutomaticKeepAliveClientMixin并继承方法
class HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin { // 混入动态界面保持状态@override// TODO: implement wantKeepAlivebool get wantKeepAlive => true;
-
方法二
- 直接在主动态组件框架里的body添加Offstage
body: Stack(children: <Widget>[Offstage(offstage: currentIndex != 0,child: tabBodies[0],),Offstage(offstage: currentIndex != 1,child: tabBodies[1],),Offstage(offstage: currentIndex != 2,child: tabBodies[2],),Offstage(offstage: currentIndex != 3,child: tabBodies[3],),], ),
- offstage:如果不是当前页面
- child:当前页面
json对象转换为dart对象
与java中的Gost转为java对象差不多
-
首先进入网站得到对象
- https://javiercbk.github.io/json_to_dart/
- 得到对象后复制到你都dart文件即可。
-
其次代码转换即可
//对象.formJson(json串)
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- windows安装repo
https://juejin.im/post/5e3ad8376fb9a07c7e3d833d...
2024/4/24 7:21:21 - 面试题17.11 单词距离
有个内含单词的超大文本文件,给定任意两个单词,找出在这个文件中这两个单词的最短距离(相隔单词数)。如果寻找过程在这个文件中会重复多次,而每次寻找的单词不同,你能对此优化吗? 示例: 输入:words = [“I”,“am”,“a”,“student”,“from”,“a”,“university”,“…...
2024/4/24 7:21:21 - SVPWM原理
SVPWM原理空间矢量的定义PWM逆变器基本输出电压矢量SVPWM的实现 SVPWM已经是非常成熟且应用范围最为广泛的PWM调制方式之一了,所以本文也只是常规的原理介绍。 空间矢量的定义 交流电动机绕组的电压、电流、磁链等物理量都是随时间变化的,如果考虑到它们所在绕组的空间位置,…...
2024/4/16 20:39:38 - JavaScript习题(鼠标滑过的区域改变颜色,颜色可以叠加))
每滑过一次,叠加一次颜色 以下是JavaScript页面的代码 var ul = document.getElementsByTagName(ul)[0]; ul.onmouseover = function (e) {var event = e || window.event;//防止在不同浏览器运行有混乱var target = event.target || event.srcElement;//防止在不同浏览器运行…...
2024/4/15 7:18:08 - BraTs脑肿瘤分割结果不同组织上色
最近开始为写小论文做准备,其实自己的代码能力很差,写下这篇博客希望对志同道合的朋友有帮助 。 自己太菜了,参考了很多其他博主的算法,始终没有找到合适的,自己也搞了2,3天,也走了很多弯路,但是能够做出来,还是很开心心啦~,记录下自己的第一篇CSDN 脑肿瘤分割的目标是…...
2024/4/20 9:36:48 - 面试分享:2020-05-25
工信部线上招聘 ——华东地区企事单位专场 ——“制造业高质量发展”专区 申请企业和岗位 企业:中国电子科技南湖研究院 岗位:新一代人工智能方向科研人员 企业:中国兵器装备集团上海电控研究所 岗位:计算机视觉算法工程师 企业:浙江清华长三角研究院 岗位:智能装备中心—…...
2024/4/16 20:40:56 - 安卓开发-百度地图定位
百度地图定位 最终效果实验过程 在AndroidManifest.xml中添加权限、密钥<?xml version="1.0" encoding="utf-8"?>//获取设备网络状态,禁用后无法获取网络状态//网络权限,当禁用后,无法进行检索等相关业务//读取设备硬件信息,统计数据//读取系统…...
2024/4/19 19:40:11 - overload方法重载
overload方法重载 1、概念:一个类中的一组方法具有相同的名字,有不同(参数个数、参数类型、参数顺序)的参数列表。 2、作用:运用一个方法名,实现对不同参数的方法调用。 典型的方法重载:3、设计重载方法:通过方法参数类型来定位方法;如果传递的时候没有这个类型,会自…...
2024/4/15 7:18:04 - Hadoop与Spark搭建与应用程序开发
参考:http://dblab.xmu.edu.cn/blog/2441-2/ http://dblab.xmu.edu.cn/blog/install-hadoop-cluster/ http://dblab.xmu.edu.cn/blog/1187-2/ Hadoop与Spark搭建与应用程序开发 1.安装ssh 保证虚拟机可以连接外网。安装成功后,ssh登录本机。2.安装Java 在/usr/lib目录下新建j…...
2024/4/16 20:40:38 - 使用AOP记录后台删除更新操作
场景 需要使用AOP记录下后台删除更新操作,并存到数据库中作为备份,在记录更新操作的时候需要详细记录下哪个字段发生变化 思路 1、使用Spring AOP思想,并将切面设置为自定义注解,更具有灵活性。 2、在记录更新操作时,需要获取更新前参数,考虑到因为通用性,可以在自定义注…...
2024/4/16 20:41:02 - LFSR线性反馈移位寄存器
LFSR线性反馈移位寄存器 线性反馈移位寄存器(LFSR):通常由移位寄存器和异或门逻辑组成。其主要应用在:伪随机数,伪噪声序列,计数器,BIST,数据的加密和CRC校验等。 Part.1 线性反馈移位寄存器(LFSR)主要包括两大类:斐波那契(外部LFSR),又称many-to-one;伽罗瓦(内部LFSR)…...
2024/4/24 7:21:23 - sar 命令的使用
sar(System ActivityReporter系统活动情况报告)是目前Linux上最为全面的系统性能分析工具之一,可以从多方面对系统的活动进行报告,包括:文件的读写情况、系统调用的使用情况、磁盘I/O、CPU效率、内存使用状况、进程活动及IPC有关的活动等,SAR命令可以动态产生报告,也可以…...
2024/4/24 7:21:28 - C语言中的整型,浮点型之分以及所占的字节数
sizeof可以用来表示字节数...
2024/4/24 7:21:18 - SQL在线练习编译
在线练习网址:http://sample.jimstone.com.cn/xsql/TestSQL/1.html...
2024/4/24 7:21:17 - java核心类
字符串 字符串很常用,且字符串具有不可变特性. 用于比较字符串是否相同,用字符串自带的equals方法才能进行内容上的比较. java编译器,在编译的时候,会自动把相同字符串当作一个对象放入常量池. public class Main {public static void main(String[] args) {String s1 = "…...
2024/4/24 7:21:15 - 比较两个对象参数是否一致
场景 项目中需要将后台更新操作记录到数据库中,并且需要详细记录哪个字段发生改变 思路 大概思路就是使用反射。先获取到更新前后的参数,以更新后参数为比较依据获取属性名,再分别获取更新前后的值进行比较 代码 //比较两个Object类型参数是否一致 public static String com…...
2024/4/24 7:21:21 - 求字符串长度(不建立临时变量)
求字符串长度(不建立临时变量) 在解决这个问题之前,我们先来看看在建立临时变量的时候,这个功能是如何实现的? 算法分析: 一个字符串总是以转义字符‘\0’结束,那我们可以建立一个临时变量,运用循环语句从左到右依次判断该字符是不是‘\0’,如果不是,则临时变量加1。…...
2024/4/24 7:21:13 - WebDay03 JavaScript高级
JavaScript高级一 浏览器对象BOM对象1.1 BOM简介1.2 Window对象①三种弹框方式② 二种定时器方式1.3 Location对象二 DOM对象【重点】1.1 DOM简介1.2 DOM获取元素1.3 DOM操作内容1.4 DOM操作属性1.5 DOM操作样式1.6 DOM操作元素(标签)三 正则表达式【了解】四 综合案例4.1 表…...
2024/4/24 7:21:13 - python文件操作
打开文件以及保存文件的操作 1.保存个人密码操作: import timeusername = input("输入用户名:") password = input("输入密码(长度不少于6位)") ctime = time.ctime()while len(password) < 6:password = input("密码不得少于6位, 请重新输入:…...
2024/4/24 7:21:11 - vue+react 请求不到接口数据-ERROR:跨源请求:同源策略禁止读取位于 http://localhost:8888/department/findAll 的远程资源。(原因:CORS
报错:已拦截跨源请求:同源策略禁止读取位于 http://localhost:8888/department/findAll 的远程资源。(原因:CORS 头缺少 Access-Control-Allow-Origin)。配置:前端: axios.js// 1. axios的默认配置 axios.defaults.baseURL = "http://localhost:8888" axios.d…...
2024/4/28 14:45:28
最新文章
- JENKINS 安装,学习运维从这里开始
Download and deployJenkins – an open source automation server which enables developers around the world to reliably build, test, and deploy their softwarehttps://www.jenkins.io/download/首先点击上面。下载Jenkins 为了学习,从windows开始&#x…...
2024/4/30 16:15:28 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 【项目新功能开发篇】开发编码
作者介绍:本人笔名姑苏老陈,从事JAVA开发工作十多年了,带过大学刚毕业的实习生,也带过技术团队。最近有个朋友的表弟,马上要大学毕业了,想从事JAVA开发工作,但不知道从何处入手。于是࿰…...
2024/4/30 10:33:31 - 【蓝桥杯】省模拟赛
题目 1.奇数次数2.最小步数3.最大极小值和最小极大值 1.奇数次数 问题描述 给定一个仅包含数字字符的字符串,统计一下这个字符串中出现了多少个值为奇数的数位。 输入格式 输入一行包含一个字符串,仅由数字字符组成。 输出格式 输出一行包含一个整数&am…...
2024/4/30 3:29:13 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/4/29 23:16:47 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/4/29 6:03:24 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/29 2:29:43 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/4/29 14:21:50 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/27 17:58:04 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/27 14:22:49 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/28 1:28:33 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/30 9:43:09 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/27 17:59:30 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/4/25 18:39:16 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/28 1:34:08 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/29 20:46:55 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/25 18:39:14 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/4/26 23:04:58 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/4/27 23:24:42 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/28 5:48:52 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/30 9:42:22 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/4/30 9:43:22 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/30 9:42:49 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57