文章目錄
- 1、http get請求資料、post提交資料、以及渲染動態資料
- 2、Dio庫實作網路請求以及動態渲染資料
- 3、下拉重繪 上拉分頁加載更多
- 4、實作簡單的新聞系統渲染新聞詳情資料以及用flutter_html決議html
- 5、使用WebView組件flutter_inappbrowser加載遠程web頁面渲染新聞詳情資料
- 6、獲取設備資訊 以及 使用高德Api獲取地理位置
- 7、呼叫原生硬體Api實作照相機拍照和相冊選擇 以及拍照上傳到服務器
- 8、實作視頻播放
- 9、檢測網路連接,監聽網路變化
- 10、 本地存盤,封裝本地存盤類,實作最簡單的狀態管理
- 11、呼叫原生硬體Api實作掃碼 掃描條形碼 掃描二維碼
- 12、檢測應用版本號、服務器下載檔案以及實作App自動升級、安裝
- 13、打開外部瀏覽器、打開外部應用、撥打電話、發送短信
- 14、支付寶支付【上】
- 15、支付寶支付【下】
- 16、ListView嵌套GridView、不同終端螢屏適配方案
- 17、JSON的序列化和反序列化、創建模型類轉換Json資料
- 18、底部 Tab 切換保持頁面狀態的幾種方法
- 19、inappbrowser、StatefulBuilder 更新 Flutter showDialog、showModalBottomSheet中的狀態
- 20、官方推薦的狀態管理庫 provider 的使用
- 21、事件廣播 、事件監聽
- 22、點擊穿透問題、頁面禁止左右滑動
喜歡記得點個贊喲,我是王睿,很高興認識大家!
1、http get請求資料、post提交資料、以及渲染動態資料
效果圖:


匯入: http: ^0.12.0+2庫
Http_Back.dart
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class HttpDemo extends StatefulWidget {
HttpDemo({Key key}) : super(key: key);
_HttpDemoState createState() => _HttpDemoState();
}
class _HttpDemoState extends State<HttpDemo> {
List _list=[];
@override
void initState() {
// TODO: implement initState
super.initState();
this._getData();
}
_getData() async{
var apiUrl="http://a.itying.com/api/productlist";
var result=await http.get(apiUrl);
if(result.statusCode==200){
print(result.body);
setState(() {
this._list=json.decode(result.body)["result"];
/*
{
"result": [{
"_id": "5ac0896ca880f20358495508",
"title": "精選熱菜",
"pid": "0",
}, {
"_id": "5ac089e4a880f20358495509",
"title": "特色菜",
"pid": "0",
}
]
}
*/
});
}else{
print("失敗${result.statusCode}");
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("請求資料Demo"),
),
body: this._list.length>0?ListView(
children: this._list.map((value){
return ListTile(
title: Text(value["title"]),
);
}).toList(),
):Text("加載中...")
);
}
}
請求資料
//請求資料
_getData() async{
var apiUrl="http://192.168.0.5:3000/news";
var result=await http.get(apiUrl);
if(result.statusCode==200){
// print(json.decode(result.body));
setState(() {
this._news=json.decode(result.body)["msg"];
});
}else{
print(result.statusCode);
}
}
提交資料
_postData() async{
var apiUrl="http://192.168.0.5:3000/dologin";
var result=await http.post(apiUrl, body: {'username': '張三', 'age': '20'});
if(result.statusCode==200){
print(json.decode(result.body));
}else{
print(result.statusCode);
}
}
2、Dio庫實作網路請求以及動態渲染資料
匯入第三方庫:Dio庫
請求資料
_getData() async{
var apiUrl="http://192.168.0.5:3000/news";
Response response = await Dio().get(apiUrl);
print(response.data);
}
提交資料
_postData() async{
Map jsonData={
"username":"哈哈哈",
"age":20
};
var apiUrl="http://192.168.0.5:3000/dologin";
Response response = await Dio().post(apiUrl,data:jsonData);
print(response.data);
}
Dio Get請求資料、渲染資料
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
class HttpDemo extends StatefulWidget {
HttpDemo({Key key}) : super(key: key);
_HttpDemoState createState() => _HttpDemoState();
}
class _HttpDemoState extends State<HttpDemo> {
List _list=[];
@override
void initState() {
super.initState();
this._getData();
}
_getData() async{
var apiUrl="http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1";
Response result=await Dio().get(apiUrl);
// print(json.decode(result.data)["result"]);
setState(() {
this._list=json.decode(result.data)["result"];
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("請求資料Dio Demo"),
),
body: this._list.length>0?ListView(
children: this._list.map((value){
return ListTile(
title: Text(value["title"]),
);
}).toList(),
):Text("加載中...")
);
}
}
3、下拉重繪 上拉分頁加載更多
效果圖:



學習之前需要匯入Dio庫,具體用法與匯入連接請查看我的博客
Flutter進階第2篇:Dio庫實作網路請求以及動態渲染資料
News.dart
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:dio/dio.dart';
class NewsPage extends StatefulWidget {
NewsPage({Key key}) : super(key: key);
_NewsPageState createState() => _NewsPageState();
}
class _NewsPageState extends State<NewsPage> {
List _list = [];
int _page = 1;
bool hasMore = true; //判斷有沒有資料
ScrollController _scrollController = new ScrollController();
@override
void initState() {
// TODO: implement initState
super.initState();
this._getData();
//監聽滾動條事件
_scrollController.addListener(() {
print(_scrollController.position.pixels); //獲取滾動條下拉的距離
print(_scrollController.position.maxScrollExtent); //獲取整個頁面的高度
if (_scrollController.position.pixels >
_scrollController.position.maxScrollExtent - 40) {
this._getData();
}
});
}
void _getData() async {
if (this.hasMore) {
var apiUrl =
"http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=${_page}";
var response = await Dio().get(apiUrl);
var res = json.decode(response.data)["result"];
setState(() {
this._list.addAll(res); //拼接
this._page++;
});
//判斷是否是最后一頁
if (res.length < 20) {
setState(() {
this.hasMore = false;
});
}
}
}
//下拉重繪
Future<void> _onRefresh() async {
await Future.delayed(Duration(milliseconds: 2000), () {
print('請求資料完成');
_getData();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("新聞串列"),
),
body: this._list.length > 0
? RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.builder(
controller: _scrollController,
itemCount: this._list.length, //20
itemBuilder: (context, index) {//19
if (index == this._list.length-1) { //串列渲染到最后一條的時候加一個圈圈
//拉到底
return Column(
children: <Widget>[
ListTile(
title: Text("${this._list[index]["title"]}",
maxLines: 1),
),
Divider(),
_getMoreWidget()
],
);
} else {
return Column(
children: <Widget>[
ListTile(
title: Text("${this._list[index]["title"]}",
maxLines: 1),
),
Divider()
],
);
}
},
))
: _getMoreWidget(),
);
}
//加載中的圈圈
Widget _getMoreWidget() {
if(hasMore){
return Center(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'加載中...',
style: TextStyle(fontSize: 16.0),
),
CircularProgressIndicator(
strokeWidth: 1.0,
)
],
),
),
);
}else{
return Center(
child: Text("--我是有底線的--"),
);
}
}
}
4、實作簡單的新聞系統渲染新聞詳情資料以及用flutter_html決議html
效果圖:
點擊這三個新聞串列的內容,即可進入新聞詳情




學習之前需要匯入Dio庫,具體用法與匯入連接請查看我的博客
Flutter進階第2篇:Dio庫實作網路請求以及動態渲染資料
還需要匯入決議HTML代碼的第三方庫:
flutter_html
新聞串列代碼:
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:dio/dio.dart';
class NewsPage extends StatefulWidget {
NewsPage({Key key}) : super(key: key);
_NewsPageState createState() => _NewsPageState();
}
class _NewsPageState extends State<NewsPage> {
List _list = [];
int _page = 1;
bool hasMore = true; //判斷有沒有資料
ScrollController _scrollController = new ScrollController();
@override
void initState() {
super.initState();
this._getData();
//監聽滾動條事件
_scrollController.addListener(() {
print(_scrollController.position.pixels); //獲取滾動條下拉的距離
print(_scrollController.position.maxScrollExtent); //獲取整個頁面的高度
if (_scrollController.position.pixels >
_scrollController.position.maxScrollExtent - 40) {
this._getData();
}
});
}
void _getData() async {
if (this.hasMore) {
var apiUrl =
"http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=${_page}";
var response = await Dio().get(apiUrl);
var res = json.decode(response.data)["result"];
setState(() {
this._list.addAll(res); //拼接
this._page++;
});
//判斷是否是最后一頁
if (res.length < 20) {
setState(() {
this.hasMore = false;
});
}
}
}
//下拉重繪
Future<void> _onRefresh() async {
await Future.delayed(Duration(milliseconds: 2000), () {
print('請求資料完成');
_getData();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("新聞串列"),
),
body: this._list.length > 0
? RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.builder(
controller: _scrollController,
itemCount: this._list.length, //20
itemBuilder: (context, index) {//19
if (index == this._list.length-1) { //串列渲染到最后一條的時候加一個圈圈
//拉到底
return Column(
children: <Widget>[
ListTile(
title: Text("${this._list[index]["title"]}",
maxLines: 1),
onTap: (){
Navigator.pushNamed(context, '/newscontent',arguments:{
"aid":this._list[index]["aid"]
});
},
),
Divider(),
_getMoreWidget()
],
);
} else {
return Column(
children: <Widget>[
ListTile(
title: Text("${this._list[index]["title"]}",
maxLines: 1),
onTap: (){
Navigator.pushNamed(context, '/newscontent',arguments:{
"aid":this._list[index]["aid"]
});
},
),
Divider()
],
);
}
},
))
: _getMoreWidget(),
);
}
//加載中的圈圈
Widget _getMoreWidget() {
if(hasMore){
return Center(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'加載中...',
style: TextStyle(fontSize: 16.0),
),
CircularProgressIndicator(
strokeWidth: 1.0,
)
],
),
),
);
}else{
return Center(
child: Text("--我是有底線的--"),
);
}
}
}
新聞詳情
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter_html/flutter_html.dart';
class NewsContent extends StatefulWidget {
Map arguments;
NewsContent({Key key,this.arguments}) : super(key: key);
_NewsContentState createState() => _NewsContentState(this.arguments);
}
class _NewsContentState extends State<NewsContent> {
Map arguments;
List _list=[];
_NewsContentState(this.arguments);
@override
void initState() {
// TODO: implement initState
super.initState();
print(this.arguments);
this._getData();
}
_getData() async{
var apiUrl="http://www.phonegap100.com/appapi.php?a=getPortalArticle&aid=${this.arguments["aid"]}";
var response=await Dio().get(apiUrl);
setState(() {
this._list=json.decode(response.data)["result"];
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("新聞詳情")
),
body:ListView(
children: <Widget>[
// Text("${this._list.length>0?this._list[0]["title"]:''}"),
// Text("${this._list.length>0?this._list[0]["content"]:''}")
Html(
data: """
${this._list.length>0?this._list[0]["content"]:''}
""",
//Optional parameters:
padding: EdgeInsets.all(8.0),
backgroundColor: Colors.white70,
defaultTextStyle: TextStyle(fontFamily: 'serif'),
linkStyle: const TextStyle(
color: Colors.redAccent,
),
onLinkTap: (url) {
// open url in a webview
}
)
],
)
);
}
}
記得配置路由時,要傳值:

5、使用WebView組件flutter_inappbrowser加載遠程web頁面渲染新聞詳情資料
效果圖
點擊這三個新聞串列的內容,即可進入新聞詳情




匯入第三方庫:flutter_inappbrowser
News.dart 新聞串列
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:dio/dio.dart';
class NewsPage extends StatefulWidget {
NewsPage({Key key}) : super(key: key);
_NewsPageState createState() => _NewsPageState();
}
class _NewsPageState extends State<NewsPage> {
List _list = [];
int _page = 1;
bool hasMore = true; //判斷有沒有資料
ScrollController _scrollController = new ScrollController();
@override
void initState() {
super.initState();
this._getData();
//監聽滾動條事件
_scrollController.addListener(() {
print(_scrollController.position.pixels); //獲取滾動條下拉的距離
print(_scrollController.position.maxScrollExtent); //獲取整個頁面的高度
if (_scrollController.position.pixels >
_scrollController.position.maxScrollExtent - 40) {
this._getData();
}
});
}
void _getData() async {
if (this.hasMore) {
var apiUrl =
"http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=${_page}";
var response = await Dio().get(apiUrl);
var res = json.decode(response.data)["result"];
setState(() {
this._list.addAll(res); //拼接
this._page++;
});
//判斷是否是最后一頁
if (res.length < 20) {
setState(() {
this.hasMore = false;
});
}
}
}
//下拉重繪
Future<void> _onRefresh() async {
await Future.delayed(Duration(milliseconds: 2000), () {
print('請求資料完成');
_getData();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("新聞串列"),
),
body: this._list.length > 0
? RefreshIndicator(
onRefresh: _onRefresh,
child: ListView.builder(
controller: _scrollController,
itemCount: this._list.length, //20
itemBuilder: (context, index) {//19
if (index == this._list.length-1) { //串列渲染到最后一條的時候加一個圈圈
//拉到底
return Column(
children: <Widget>[
ListTile(
title: Text("${this._list[index]["title"]}",
maxLines: 1),
onTap: (){
Navigator.pushNamed(context, '/newscontent',arguments:{
"aid":this._list[index]["aid"]
});
},
),
Divider(),
_getMoreWidget()
],
);
} else {
return Column(
children: <Widget>[
ListTile(
title: Text("${this._list[index]["title"]}",
maxLines: 1),
onTap: (){
Navigator.pushNamed(context, '/newscontent',arguments:{
"aid":this._list[index]["aid"]
});
},
),
Divider()
],
);
}
},
))
: _getMoreWidget(),
);
}
//加載中的圈圈
Widget _getMoreWidget() {
if(hasMore){
return Center(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'加載中...',
style: TextStyle(fontSize: 16.0),
),
CircularProgressIndicator(
strokeWidth: 1.0,
)
],
),
),
);
}else{
return Center(
child: Text("--我是有底線的--"),
);
}
}
}
NewsContent.dart 新聞詳情
import 'package:flutter/material.dart';
import 'package:flutter_inappbrowser/flutter_inappbrowser.dart';
class NewsContent extends StatefulWidget {
Map arguments;
NewsContent({Key key,this.arguments}) : super(key: key);
_NewsContentState createState() => _NewsContentState(this.arguments);
}
class _NewsContentState extends State<NewsContent> {
Map arguments;
bool _flag=true;
_NewsContentState(this.arguments);
@override
void initState() {
// TODO: implement initState
super.initState();
print(this.arguments);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("新聞詳情")
),
body:Column(
children: <Widget>[
this._flag?_getMoreWidget():Text(""),
Expanded(
child: InAppWebView(
initialUrl: "http://www.phonegap100.com/newscontent.php?aid=${this.arguments["aid"]}",
onProgressChanged: (InAppWebViewController controller, int progress) {
print(progress/100);
if((progress/100)>0.999){
setState(() {
this._flag=false;
});
}
},
),
)
],
)
);
}
//加載中的圈圈
Widget _getMoreWidget() {
return Center(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'加載中...',
style: TextStyle(fontSize: 16.0),
),
CircularProgressIndicator(
strokeWidth: 1.0,
)
],
),
),
);
}
}
記得配置路由時,要傳值:

注意事項:
SDK版本一定要大于等于17

6、獲取設備資訊 以及 使用高德Api獲取地理位置
效果圖:


引入第三方庫:device_info
Device.dart
import 'package:flutter/material.dart';
import 'package:device_info/device_info.dart';
class DevicePage extends StatefulWidget {
DevicePage({Key key}) : super(key: key);
_DevicePageState createState() => _DevicePageState();
}
class _DevicePageState extends State<DevicePage> {
@override
void initState() {
// TODO: implement initState
super.initState();
this._getDevice();
}
_getDevice() async{
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
print('設備號 ${androidInfo.androidId}'); // e.g. "Moto G (4)"
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter Native Device演示"),
),
body: Text("看控制臺 資訊已經列印到控制臺了"),
);
}
}
第一步:使用高德定位準備作業獲取 key
1、申請成為開發者
2、創建應用配置獲取Key
點擊查看教程
第二步:引入第三方庫
amap_location
第三步:修改 你的專案目錄e /app/build.gradle 在 在 g android/defaultConfig 節點修 改 改 manifestPlaceholders, 新增高德地圖 y key 配置
android {
.... 你的代碼
defaultConfig {
.....
manifestPlaceholders = [
AMAP_KEY : "aa9f0cf8574400f2af0078392c556e25", // 高德
地圖 key
]
}
...你的代碼
dependencies {
/// 注意這里需要在主專案增加一條依賴,否則可能發生編譯不通過的
情況
implementation 'com.amap.api:location:latest.integration'
...你的代碼
}

7、呼叫原生硬體Api實作照相機拍照和相冊選擇 以及拍照上傳到服務器
效果圖:

相冊

拍照

拍照后的照片顯示在界面上

7.1丶 呼叫原生硬體Api實作照相機拍照和相冊選擇
匯入第三方庫:image_picker
拍照
_takePhoto() async {
var image = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_imgPath = image;
});
}
相冊
_openGallery() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_imgPath = image;
});
}
7.2丶 拍照上傳到服務器
匯入第三方庫:上傳圖片到服務器
上傳圖片代碼
_uploadData(imageFile) async{
FormData formData = new FormData.from({
"name": "wendux",
"age": 25,
'file': new UploadFileInfo(imageFile, "imageFileName.jpg")
});
var response = await Dio().post("http://jd.itying.com/imgupload", data: formData);
print(response);
}
完整代碼:
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:dio/dio.dart';
class ImagePickerPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _ImagePickerState();
}
}
class _ImagePickerState extends State<ImagePickerPage> {
var _imgPath;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("ImagePicker"),
),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_ImageView(_imgPath),
RaisedButton(
onPressed: _takePhoto,
child: Text("拍照"),
),
RaisedButton(
onPressed: _openGallery,
child: Text("選擇照片"),
),
],
),
));
}
/*圖片控制元件*/
Widget _ImageView(imgPath) {
if (imgPath == null) {
return Center(
child: Text("請選擇圖片或拍照"),
);
} else {
return Image.file(
imgPath,
);
}
}
/*拍照*/
_takePhoto() async {
var image = await ImagePicker.pickImage(source: ImageSource.camera,maxWidth: 400);
_uploadData(image); //上傳
setState(() {
_imgPath = image;
});
}
/*相冊*/
_openGallery() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_imgPath = image;
});
}
_uploadData(imageFile) async{
FormData formData = new FormData.from({
"name": "wendux",
"age": 25,
'file': new UploadFileInfo(imageFile, "imageFileName.jpg")
});
var response = await Dio().post("http://jd.itying.com/imgupload", data: formData);
print(response);
}
}
8、實作視頻播放
效果圖:

引入第三方庫:chewie
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:chewie/chewie.dart';
class ChewieVideoDemo extends StatefulWidget {
ChewieVideoDemo({Key key}) : super(key: key);
_ChewieVideoDemoState createState() => _ChewieVideoDemoState();
}
class _ChewieVideoDemoState extends State<ChewieVideoDemo> {
VideoPlayerController videoPlayerController;
ChewieController chewieController;
@override
void initState() {
// TODO: implement initState
super.initState();
videoPlayerController = VideoPlayerController.network(
'http://vfx.mtime.cn/Video/2019/02/04/mp4/190204084208765161.mp4');
chewieController = ChewieController(
videoPlayerController: videoPlayerController,
aspectRatio: 3 / 2,
autoPlay: true,
looping: true,
);
}
/*銷毀*/
@override
void dispose() {
videoPlayerController.dispose();
chewieController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('在線視頻播放'),
),
body: Center(
child: Chewie(
controller: chewieController,
)
),
);
}
}
9、檢測網路連接,監聽網路變化
效果圖:



引入第三方庫:connectivity
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:chewie/chewie.dart';
class ChewieVideoDemo extends StatefulWidget {
ChewieVideoDemo({Key key}) : super(key: key);
_ChewieVideoDemoState createState() => _ChewieVideoDemoState();
}
class _ChewieVideoDemoState extends State<ChewieVideoDemo> {
VideoPlayerController videoPlayerController;
ChewieController chewieController;
@override
void initState() {
// TODO: implement initState
super.initState();
videoPlayerController = VideoPlayerController.network(
'http://vfx.mtime.cn/Video/2019/02/04/mp4/190204084208765161.mp4');
chewieController = ChewieController(
videoPlayerController: videoPlayerController,
aspectRatio: 3 / 2,
autoPlay: true,
looping: true,
);
}
/*銷毀*/
@override
void dispose() {
videoPlayerController.dispose();
chewieController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('在線視頻播放'),
),
body: Center(
child: Chewie(
controller: chewieController,
)
),
);
}
}
10、 本地存盤,封裝本地存盤類,實作最簡單的狀態管理
引入第三方庫:shared_preferences
設定值:
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString(key, value);
prefs.setBool(key, value)
prefs.setDouble(key, value)
prefs.setInt(key, value)
prefs.setStringList(key, value)
獲取值:
SharedPreferences prefs = await SharedPreferences.getInstance();
var data=prefs.getString("name");
洗掉值:
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.remove(key); //洗掉指定鍵
prefs.clear();//清空鍵值對
完整代碼:
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class StoragePage extends StatefulWidget {
StoragePage({Key key}) : super(key: key);
_StoragePageState createState() => _StoragePageState();
}
class _StoragePageState extends State<StoragePage> {
_saveData() async{
SharedPreferences sp=await SharedPreferences.getInstance();
sp.setString("username", "張三111");
sp.setString("age", "26");
}
_getData() async{
SharedPreferences sp=await SharedPreferences.getInstance();
print(sp.getString("username"));
print(sp.getString("age"));
}
_removeData() async{
SharedPreferences sp=await SharedPreferences.getInstance();
print(sp.remove("age"));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("本地存盤"),
),
body: Center(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
RaisedButton(
child: Text('保存資料'),
onPressed: _saveData,
),
SizedBox(height: 10),
RaisedButton(
child: Text('獲取資料'),
onPressed:_getData,
),
SizedBox(height: 10),
RaisedButton(
child: Text('清除資料'),
onPressed:_removeData,
)
]),
),
);
}
}
簡單封裝:
import 'package:shared_preferences/shared_preferences.dart';
class Storage{
static Future<void> setString(key,value) async{
SharedPreferences sp=await SharedPreferences.getInstance();
sp.setString(key, value);
}
static Future<String> getString(key) async{
SharedPreferences sp=await SharedPreferences.getInstance();
return sp.getString(key);
}
static Future<void> remove(key) async{
SharedPreferences sp=await SharedPreferences.getInstance();
sp.remove(key);
}
}
11、呼叫原生硬體Api實作掃碼 掃描條形碼 掃描二維碼
效果圖:



第一步:
匯入第三方庫:barcode_scan
第二步:
<uses-permission android:name="android.permission.CAMERA" />
第三步:
3.1 的 編 輯 你 的 d android 的 目 錄 下 面 的 e build.gradle ( Edit your project-level
build.gradle file to look like this)
注意: : 官方檔案配置的 kotlin_version 的版本是 1.2.31,但是實際發現 1.2.31
會報錯,所以本專案使用 1.3.0,
buildscript {
ext.kotlin_version = '1.3.0'
...
dependencies {
...
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
第四步:編輯你 的 p android/app 的 目 錄下 面 的 e build.gradle ( Edit your app-levelbuild.gradle file to look like this)
apply plugin: 'kotlin-android'
...
dependencies {
implementation
"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
...
}
import 'package:flutter/material.dart';
import 'package:barcode_scan/barcode_scan.dart';
import 'package:flutter/services.dart';
class ScanPage extends StatefulWidget {
ScanPage({Key key}) : super(key: key);
_ScanPageState createState() => _ScanPageState();
}
class _ScanPageState extends State<ScanPage> {
String barcode;
Future _scan() async {
try {
String barcode = await BarcodeScanner.scan();
setState(() {
return this.barcode = barcode;
});
} on PlatformException catch (e) {
if (e.code == BarcodeScanner.CameraAccessDenied) {
setState(() {
return this.barcode = 'The user did not grant the camera permission!';
});
} else {
setState(() {
return this.barcode = 'Unknown error: $e';
});
}
} on FormatException {
setState(() => this.barcode =
'null (User returned using the "back"-button before scanning anything. Result)');
} catch (e) {
setState(() => this.barcode = 'Unknown error: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.photo_camera),
onPressed: _scan,
),
appBar: AppBar(
title: Text("掃碼"),
),
body: Text("${barcode}")
);
}
}
12、檢測應用版本號、服務器下載檔案以及實作App自動升級、安裝
12.1丶 配置版本號:
<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1"
package="io.jdshop.demo" xmlns:android="http://schemas.android.com/apk/res/android">
12.2丶 升級 app 之前的準備作業配置權限
配置 AndroidMenifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
12.3丶 Android 升級 app 涉及的 API 庫

12.4、獲取版本資訊
https://pub.dev/packages/package_info
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String appName = packageInfo.appName;
String packageName = packageInfo.packageName;
String version = packageInfo.version;
String buildNumber = packageInfo.buildNumber;
print("appName:${appName}");
print("packageName:${packageName}");
print("version:${version}");
print("buildNumber:${buildNumber}");
12.5、獲取檔案存盤路徑.
https://pub.dev/packages/path_provider
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
var directory = await getExternalStorageDirectory();
String storageDirectory=directory.path;
print("tempPath:${tempPath}");
print("appDocDir:${appDocPath}");
print("StorageDirectory:${storageDirectory}");
12.6、下載檔案
https://pub.dev/packages/flutter_downloader
final directory = await getExternalStorageDirectory();
String _localPath = directory.path;
final taskId = await FlutterDownloader.enqueue(
url: "http://www.ionic.wang/jdshop.apk",
savedDir: _localPath,
showNotification:
true, // show download progress in status bar (for Android)
openFileFromNotification:
true, // click on notification to open downloaded file (for Android)
);
12.7、打開檔案
https://pub.dev/packages/open_file
OpenFile.open("${_localPath}/jdshop.apk");
12.8、注意事項
1、服務器的 App 版本必須大于本地 App 版本
2、本地 App 和服務器 App 的包名稱 簽名必須一致,這樣的話服務器的包才可以替換本地
的包,
13、打開外部瀏覽器、打開外部應用、撥打電話、發送短信
效果圖:

打開外部瀏覽器

發送短信

撥打電話

打開外部應用

匯入第三方庫:url_launcher
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
class UrlLauncher extends StatefulWidget {
UrlLauncher({Key key}) : super(key: key);
_UrlLauncherState createState() => _UrlLauncherState();
}
class _UrlLauncherState extends State<UrlLauncher> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('UrlLauncher'),
),
body: Center(
child: Padding(
padding: EdgeInsets.all(20),
child: ListView(children: [
RaisedButton(
child: Text('打開外部瀏覽器'),
onPressed: () async{
const url = 'https://cflutter.com';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
},
),
SizedBox(height: 10),
RaisedButton(
child: Text('撥打電話'),
onPressed: () async{
var tel = 'tel:10086';
if (await canLaunch(tel)) {
await launch(tel);
} else {
throw 'Could not launch $tel';
}
},
),
SizedBox(height: 10),
RaisedButton(
child: Text('發送短信'),
onPressed: () async{
var tel = 'sms:10086';
if (await canLaunch(tel)) {
await launch(tel);
} else {
throw 'Could not launch $tel';
}
},
),
SizedBox(height: 10),
RaisedButton(
child: Text('打開外部應用'),
onPressed: () async{
/*
weixin://
alipays://
*/
var url = 'alipays://'; //支付寶的 scheme碼
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
},
)
]),
)));
}
}
打開其他APP的scheme碼:
https://www.cflutter.com/topic/5d0853733b57e317a4d0af01
14、支付寶支付【上】
一丶 準備作業、接入支付寶:
1. 必須注冊企業支付寶賬戶,如果已有企業支付寶賬戶忽略此步驟
2. 百度搜索《支付寶開放平臺》,或者點擊下面鏈接進入支付寶開發接入頁面:
https://open.alipay.com/developmentAccess/developmentAccess.htm

3. 點擊支付應用

4. 填寫對應應用名稱 圖示 點擊創建:

官方答復:應用型別分為兩大類:第三方應用、自用型應用 第三方應用:適用于服務商,
為商戶開發應用,拓展商戶使用,詳見供他人使用;目前僅支持小程式的三方接入,接入小
程式前,必須先申請小程式的公測; 自用型應用:使用開放的功能,為自己或自己公司開
發應用,詳見自己使用;自研型應用分為網頁/移動,AR(僅企業支付寶),小程式(僅企
業支付寶),生活號
網頁&移動應用 和 第三方應用的區別是一個是自己使用,一個是幫助第三方去簽約相關產
品
5.設定應用公鑰,然后提交審核, 如何創建公鑰繼續往后看…

二丶 介面加密簽名
- 下載簽名工具,
https://docs.open.alipay.com/291/106097/
2.簽名,并保存好私鑰、公鑰


三丶 配置簽名、提交審核



設定完成以后支付寶后臺也會給我們生成一個公鑰,注意兩個不一樣



四丶 安裝支付流程
官方支付流程檔案:https://docs.open.alipay.com/59/103658/
15、支付寶支付【下】
一丶 支付寶客戶端支付流程
官方支付流程檔案:https://docs.open.alipay.com/59/103658/
二丶 準備已有的 Flutter 專案安裝插件
https://pub.dev/packages/sy_flutter_alipay
三丶服務器端呼叫支付寶 sdk 生成訂單資訊
- 服務端 sdk 下載地址:https://docs.open.alipay.com/54/103419/
- 本教程采用的 php 的 sdk,看演示
四丶 客戶端呼叫服務器端介面生成訂單簽名資訊,呼叫支付插件完成支付
import 'package:flutter/material.dart';
import 'package:sy_flutter_alipay/sy_flutter_alipay.dart';
import 'package:dio/dio.dart';
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
_doPay() async{
var apiUrl='http://agent.itying.com/alipay/index.php';
var myPayInfo =await Dio().get(apiUrl);
final payInfo =myPayInfo.data;
print(payInfo);
var result = await SyFlutterAlipay.pay(
payInfo,
// urlScheme: '你的 ios urlScheme', //前面配置的 urlScheme
// isSandbox: true //是否是沙箱環境,只對 android 有效
);
print(result);
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(height: 20),
RaisedButton(
child: Text('支付寶支付'),
onPressed: _doPay,
),
SizedBox(height: 20),
],
),
);
}
}
五丶 服務器端異步回呼更新訂單資訊
當支付成功后支付寶會異步給服務器 post 資料,服務器更新訂單資訊

服務端 sdk 下載地址:https://docs.open.alipay.com/54/103419/
本教程采用的 php 的 sdk,看演示
六丶 Flutter 在 Xcode 上編譯提示:Target ‘Runner’: script phase “[CP] Embed Pods Frameworks” 的解決辦法

解決方法:https://www.cflutter.com/topic/5d09a1c73b57e317a4d0af08
16、ListView嵌套GridView、不同終端螢屏適配方案
一丶 豎向 ListView 嵌套橫向 ListView ,以 及ListView 嵌套 GridView
1 、 豎向 ListView 嵌套橫向 ListView 注意事項:
在豎向 ListView 中嵌套橫向 ListView 的時候要注意給橫向 ListView 外層加一個容器,然后外
層這個容器要設定高度,外層這個容器可以是 SizedBox ,也可以是 Container,
2 、ListView 嵌套 GridView 注意事項:
由于 GridView 和 ListView 都是可以滾動的組件,所以嵌套的時候要注意把里面的組件改為不可滾動組件,
重要屬性:
shrinkWrap: true, //解決無限高度問題
physics:NeverScrollableScrollPhysics(), //禁用滑動事件
二丶 不同終端螢屏適配方案
匯入第三方庫: flutter_screenutil
import 'package:flutter/material.dart';
class ScreenUtil {
static ScreenUtil instance = new ScreenUtil();
//設計稿的設備尺寸修改
double width;
double height;
bool allowFontScaling;
static MediaQueryData _mediaQueryData;
static double _screenWidth;
static double _screenHeight;
static double _pixelRatio;
static double _statusBarHeight;
static double _bottomBarHeight;
static double _textScaleFactor;
ScreenUtil({
this.width = 1080,
this.height = 1920,
this.allowFontScaling = false,
});
static ScreenUtil getInstance() {
return instance;
}
void init(BuildContext context) {
MediaQueryData mediaQuery = MediaQuery.of(context);
_mediaQueryData = mediaQuery;
_pixelRatio = mediaQuery.devicePixelRatio;
_screenWidth = mediaQuery.size.width;
_screenHeight = mediaQuery.size.height;
_statusBarHeight = mediaQuery.padding.top;
_bottomBarHeight = _mediaQueryData.padding.bottom;
_textScaleFactor = mediaQuery.textScaleFactor;
}
static MediaQueryData get mediaQueryData => _mediaQueryData;
///每個邏輯像素的字體像素數,字體的縮放比例
static double get textScaleFactory => _textScaleFactor;
///設備的像素密度
static double get pixelRatio => _pixelRatio;
///當前設備寬度 dp
static double get screenWidthDp => _screenWidth;
///當前設備高度 dp
static double get screenHeightDp => _screenHeight;
///當前設備寬度 px
static double get screenWidth => _screenWidth * _pixelRatio;
///當前設備高度 px
static double get screenHeight => _screenHeight * _pixelRatio;
///狀態欄高度 dp 劉海屏會更高
static double get statusBarHeight => _statusBarHeight;
///底部安全區距離 dp
static double get bottomBarHeight => _bottomBarHeight;
///實際的 dp 與設計稿 px 的比例
get scaleWidth => _screenWidth / instance.width;
get scaleHeight => _screenHeight / instance.height;
///根據設計稿的設備寬度適配
///高度也根據這個來做適配可以保證不變形
setWidth(double width) => width * scaleWidth;
/// 根據設計稿的設備高度適配
/// 當發現設計稿中的一屏顯示的與當前樣式效果不符合時,
/// 或者形狀有差異時,高度適配建議使用此方法
/// 高度適配主要針對想根據設計稿的一屏展示一樣的效果
setHeight(double height) => height * scaleHeight;
///字體大小適配方法
///@param fontSize 傳入設計稿上字體的 px ,
///@param allowFontScaling 控制字體是否要根據系統的“字體大小”輔助選項來進行縮
放,默認值為 false,
///@param allowFontScaling Specifies whether fonts should scale to respect Text Size
accessibility settings. The default is false.
setSp(double fontSize) => allowFontScaling
? setWidth(fontSize)
: setWidth(fontSize) / _textScaleFactor;
}
17、JSON的序列化和反序列化、創建模型類轉換Json資料
一、Flutter JSON 序列化反序列化
1、使用 dart:convert 手動序列化 JSON
2、模型類中序列化 JSON
小專案中使用 dart:convert 手動序列化 JSON 非常好,也非常快速,但是隨著專案的增大,
dart:convert 手動序列化 JSON 的話失去了大部分靜態型別語言特性:型別安全、自動補全和
最重要的編譯時例外,這樣一來,我們的代碼可能會變得非常容易出錯,
當我們訪問 name 或 email 欄位時,我們輸入的很快,導致欄位名打錯了,但由于這個 JSON
在 map 結構中,所以編譯器不知道這個錯誤的欄位名,
為了解決上面的問題在大型專案中使用的更多的是在模型類中序列化 JSON,
二、 Flutter JSON 字串和 Map 換 型別的轉換 dart:convert手動序列化 JSON
import 'dart:convert'
var mapData={"name":"張三","age":"20"};
var strData='{"name":"張三","age":"20"}';
print(json.encode(mapData)); //Map 轉換成 Json 字串
print(json.decode(strData)); //Json 字串轉化成 Map 型別
三丶 Flutter 在模型類中序列化 JSON
class FocusModel {
String sId;
String title;
String status;
String pic;
String url;
FocusModel ({this.sId, this.title, this.status, this.pic, this.url});
FocusModel .fromJson(Map<String, dynamic> json) {
sId = json['_id'];
title = json['title'];
status = json['status'];
pic = json['pic'];
url = json['url'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['_id'] = this.sId;
data['title'] = this.title;
data['status'] = this.status;
data['pic'] = this.pic;
data['url'] = this.url;
return data;
}
}
var strData='{"_id":"59f6ef443ce1fb0fb02c7a43","title":"筆記本電腦
","status":"1","pic":"public\\upload\\UObZahqPYzFvx_C9CQjU8KiX.png","
url":"12"
}';
var data= FocusModel.fromJson( strData )
可參考: https://flutterchina.club/json/
四丶 json_to_dart 自動生成模型類
https://javiercbk.github.io/json_to_dart/
18、底部 Tab 切換保持頁面狀態的幾種方法
一、IndexedStack 保持頁面狀態
IndexedStack 和 Stack 一樣,都是層布局控制元件, 可以在一個控制元件上面放置另一
個控制元件,但唯一不同的是 IndexedStack 在同一時刻只能顯示子控制元件中的一個控
件,通過 Index 屬性來設定顯示的控制元件,
IndexedStack 來保持頁面狀態的優點就是配置簡單,IndexedStack 保持頁面狀
態的缺點就是不方便單獨控制每個頁面的狀態,
k IndexedStack 用法:
Container(
width: double.infinity,
height: double.infinity,
child: new IndexedStack(
index: 0,
alignment: Alignment.center,
children: <Widget>[
Image.network("https://www.itying.com/images/flutter/list1.jpg",fit:
BoxFit.cover,),
Image.network("https://www.itying.com/images/flutter/list2.jpg",fit:
BoxFit.cover)
],
),
)
結合底部 tab 切換
body:IndexedStack(
children: this._pageList,
index: _currentIndex,
),
二丶 AutomaticKeepAliveClientMixin 保持頁面狀態
AutomaticKeepAliveClientMixin 結合 tab 切換保持頁面狀態相比 IndexedStack 而言配置起來稍
微有些復雜,它結合底部 BottomNavigationBar 保持頁面狀態的時候需要進行如下配置,
import 'package:flutter/material.dart';
import 'Home.dart';
import 'Category.dart';
import 'Cart.dart';
import 'User.dart';
class Tabs extends StatefulWidget {
Tabs({Key key}) : super(key: key);
_TabsState createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
int _currentIndex=1;
//創建頁面控制器
var _pageController;
@override
void initState(){
//頁面控制器初始化
_pageController = new PageController(initialPage : _currentIndex);
super.initState();
}
List<Widget> _pageList=[
HomePage(),
CategoryPage(),
CartPage(),
UserPage()
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("jdshop"),
),
//必須用 PageView 加載不同的頁面
body: PageView(
controller: _pageController,
children: this._pageList,
onPageChanged: (index){
_currentIndex = index;
},
),
bottomNavigationBar: BottomNavigationBar(
currentIndex:this._currentIndex ,
onTap: (index){
setState(() {
//this._currentIndex=index;
//頁面控制器進行跳轉
_pageController.jumpToPage(this._currentIndex);
});
},
type:BottomNavigationBarType.fixed ,
fixedColor:Colors.red,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text("首頁")
),
BottomNavigationBarItem(
icon: Icon(Icons.category),
title: Text("分類")
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart),
title: Text("購物車")
),
BottomNavigationBarItem(
icon: Icon(Icons.people),
title: Text("我的")
)
],
),
);
}
}
需要持久化的頁面加入如下代碼:
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin{
@override
bool get wantKeepAlive => true;
}
19、inappbrowser、StatefulBuilder 更新 Flutter showDialog、showModalBottomSheet中的狀態
一丶 Flutter WebView 組件 inappbrowser的使用
https://pub.dev/packages/flutter_inappbrowser
注意事項:

二丶 StatefulBuilder 更新 Flutter showDialog、showModalBottomSheet中的狀態
參考:https://www.cflutter.com/topic/5d202202403aa10564178c65
20、官方推薦的狀態管理庫 provider 的使用
一丶 狀態管理
通俗的講:當我們想在多個頁面(組件/Widget)之間共享狀態(資料),或者一個頁面(組
件/Widget)中的多個子組件之間共享狀態(資料),這個時候我們就可以用 Flutter 中的狀
態管理來管理統一的狀態(資料),實作不同組件直接的傳值和資料共享,
現在 Flutter 的狀態管理方案很多,redux、bloc、state、provide、provider,
目前我們推薦使用 provider,這個是官方提供的狀態管理解決方案,相比其他狀態管理庫使
用起來比較方便,
二、 關于 于flutter provider 庫和 和 flutter provide 庫
provider 是 Flutter 團隊推出的狀態管理模式,
官方地址為: https://pub.dev/packages/provider
注意:p rovider 和 provide 是兩個庫哦,Flutter 官方推薦使用的是 provider 哦,provider 是
flutter 官方出的,provide 不是 Flutter 官方寫的哦
三丶 flutter provider 的使用
1、配置依賴 provider: ^3.0.0+1
2、新建一個檔案夾叫 provider,在 provider 檔案夾里面放我們對于的狀態管理類
3、在 provider 里面新建 Counter.dart
4、Counter.dart 里面新建一個類繼承 minxins 的 ChangeNotifier 代碼如下
import 'package:flutter/material.dart';
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
5、找到 main.dart 修改代碼如下
import 'package:flutter/material.dart';
import 'routers/router.dart';
import 'package:provider/provider.dart';
import 'provider/Counter.dart';
void main() =>runApp(MyApp());
// void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
// Provider<Counter>.value(value: foo),
ChangeNotifierProvider(builder: (_) => Counter()),
],
child: MaterialApp(
// home: Tabs(),
debugShowCheckedModeBanner: false,
initialRoute: '/productContent',
onGenerateRoute: onGenerateRoute,
theme: ThemeData(
// primaryColor: Colors.yellow
primaryColor: Colors.white),
),
);
}
}
6、獲取值、以及設定值
import 'package:provider/provider.dart';
import '../../provider/Counter.dart';
Widget build(BuildContext context) {
final counter = Provider.of<Counter>(context);
// counter.init();
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: (){
counter.increment();
},
),
body: Text("counter 的值:${counter.count}")
);
}
21、事件廣播 、事件監聽
一丶 event_bus 介紹
在前面的課程我們給大家講過狀態管理 Provider 的使用,
通俗的講狀態管理就是:當我們想在多個頁面(組件/Widget)之間共享狀態(資料),或
者一個頁面(組件/Widget)中的多個子組件之間共享狀態(資料),這個時候我們就可以
用 Flutter 中的狀態管理來管理統一的狀態(資料),實作不同組件直接的傳值和資料共享,
那么這一講給大家講的 event_bus 主要是實作不同組件之間的資料傳值,以及在一個組件中
執行另一個組件的方法,
二丶 event_bus 使用事件廣播 、事件監聽
https://pub.dev/packages/event_bus
1 、配置安裝依賴
event_bus: ^1.1.0
2 、 新建一檔案 EventBus.dart 配置如下代碼
import 'package:event_bus/event_bus.dart';
//Bus 初始化
EventBus eventBus = EventBus();
class ProductContentEvent {
String text;
ProductContentEvent(String text){
this.text = text;
}
}
3 、 在需要廣播事件的頁面引入上面的 EventBus.dart類 然后配置如下代碼
eventBus.fire(new ProductContentEvent('購物車'));
4 、 在需要監聽廣播的地方引入上面的 EventBus.dart 類,然后配置如下代碼
void initState() {
super.initState();
//監聽廣播
eventBus.on<ProductContentEvent>().listen((event){
print(event);
this._attrBottomSheet();
});
}
三丶 event_bus 取消事件監聽
var actionSubscription =eventBus.on<ProductContentEvent>().listen((event){
print(event);
this._attrBottomSheet();
});
actionSubscription.cancel();
22、點擊穿透問題、頁面禁止左右滑動
一丶 點擊穿透問題
HitTestBehavior.deferToChild 只有有子 Widget 通過了 Hit-Test,才接收一系列的事件,接收
區域也會被限制在該子 Widget 區域中,
HitTestBehavior.opaque 能夠通過 Hit-Test,接收事件,且能阻止在它之前的 Widget(直觀
來看就是被它擋住的 Widget)接收事件,簡單來說就是事件 不能透傳,
HitTestBehavior.translucent 能夠通過 Hit-Test,接收事件,且不會阻止它之前的 Widget(直
觀來看就是被它擋住的 Widget)接收事件,簡單來說就是事件 能透傳,
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
return false;
}
)
二丶 頁面禁止左右滑動
部分真機詳情左右滑動太靈敏 導致詳情上下滑動不好滑動,這個時候也可禁用詳情Tab滑動
physics: NeverScrollableScrollPhysics(), //禁止 pageView 滑動
喜歡記得點個贊喲,我是王睿,很高興認識大家!
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/291070.html
標籤:其他
