日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

flutter_web 实战之文章列表与详情

發(fā)布時間:2025/6/17 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 flutter_web 实战之文章列表与详情 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在上一篇 【flutter_web 初體驗】中,簡單的介紹了下 flutter_web 創(chuàng)建一個項目和一些踩坑的解決方案,本篇將進一步講解搭建 flutter_web 項目的基本過程。

本文將講解以下要點:

  • 項目結(jié)構(gòu)介紹
  • 布局
  • 響應(yīng)式布局
  • 頁面路由
  • 網(wǎng)絡(luò)請求
  • markdown 渲染
  • 項目目錄結(jié)構(gòu)

    / ├── README.md ├── analysis_options.yaml ├── build # webdev build 編譯生成的目錄,用于部署 ├── lib # 工作區(qū) │?? ├── components # 組件(Widgets) │?? ├── kit # 工具、父類 │?? ├── main.dart # 入口 │?? ├── models # 數(shù)據(jù)模型 │?? ├── network # 網(wǎng)絡(luò) │?? ├── pages # 頁面 │?? │?? ├── detail # 詳情頁 │?? │?? │?? ├── bloc │?? │?? │?? ├── detail.dart │?? │?? │?? ├── model │?? │?? │?? └── page │?? │?? ├── index # 首頁 │?? │?? ├── pages.dart │?? │?? └── user # 用戶 │?? └── router # 頁面路由 ├── pubspec.lock ├── pubspec.yaml # 依賴 └── web├── assets # 資源區(qū)│?? ├── FontManifest.json # 字體│?? └── images # 圖片│?? └── swift_logo.png├── index.html└── main.dart 復(fù)制代碼

    主要劃分了 6 大部分:

    • network: 網(wǎng)絡(luò)
    • models: 模型
    • router: 路由
    • pages: 頁面
    • components:組件
    • kit: 工具、常量、基類等

    布局

    接下來,將要實現(xiàn) 2 個頁面, 效果分別如下:

    列表和詳情,頁面還是比較簡單的。

    整體布局就是頭部、內(nèi)容、尾部。比如尾部在首頁和詳情頁的底部都是一樣的,把它領(lǐng)出來作為一個公共組件。個人的開發(fā)習(xí)慣就是,相同的東西往上冒泡,讓文件目錄層次上浮。

    首頁布局

    因為頁面不存在懸浮情況,所以首頁布局還是比較簡單的:

    // pages/index/index_pages.dart// 添加頭部 List<Widget> lists = [_buildHeader(context)];// 添加列表內(nèi)容 lists.addAll(rows.map((item) {return _buildCell(item); }).toList());// 添加尾部 lists.add(Container(margin: EdgeInsets.only(top: 100),child: FooterView(), ));/// 整體內(nèi)容用 SingleChildScrollView 進行包裝 SingleChildScrollView(child: Container(color: Colors.white,child: Column(children: lists,),)) 復(fù)制代碼

    詳情頁布局

    詳情頁頭部是懸浮的,且文章采用 markdown,也是一個 ListView。 然后底部是通用的底部欄。

    那么懸浮的話就采用了 AppBar :

    Scaffold(backgroundColor: Colors.white,appBar: PreferredSize(child: HeaderView(), preferredSize: Size.fromHeight(50)),body: body) 復(fù)制代碼

    上面的 body 是通過 SingleChildScrollView 包裝:

    return SingleChildScrollView(child: Column(children: <Widget>[mdView, FooterView()],), ); 復(fù)制代碼

    響應(yīng)式布局

    在有使用過站點的初版的時候,當你改變?yōu)g覽器的大小的時候,布局會比較丑陋,且會發(fā)送一些布局警告。造成的原因是沒有適配各種屏幕的大小。如果做前端的,會有一些比較通用的解決辦法:

    • 媒體查詢
    • 百分比
    • rem
    • vw/vh

    如果對此感興趣可深入閱讀 《響應(yīng)式布局的常用解決方案對比(媒體查詢、百分比、rem和vw/vh)》

    那么如果 flutter_web 要做響應(yīng)是布局,該怎么辦?

    • 尺寸大小和位置不使用硬編碼
    • 使用 MediaQuery 獲取當前的窗口的大小
    • 使用 Flexible 和 Expanded 去布局界面,使用百分比而不是硬編碼。
    • 使用 LayoutBuilder 獲取父 widget 的 ConstraintBox
    • 使用 MediaQuery 或 OrientationBuilder 獲取設(shè)備的方向。
    • AspectRatio 和 FractionallySizedBox 是常用的百分比相關(guān)的 Widget。

    響應(yīng)式布局有兩篇文章推薦閱讀:

    • Build Responsive UIs in Flutter
    • Making Cross-platform Flutter Landing Page Responsive (Part 3)

    頁面路由

    // main.dart main() {Static.storage = Storage();runApp(SwiftClub()); }class SwiftClub extends StatelessWidget {@overrideWidget build(BuildContext context) {return MaterialApp(debugShowCheckedModeBanner: false,title: 'swiftclub',theme: ThemeData(fontFamily: "Montserrat"),onGenerateRoute: (setting) => buildRouters(setting),initialRoute: "/",);} } 復(fù)制代碼// router/router.dartRoute<dynamic> buildRouters(RouteSettings settings) {dynamic args = settings.arguments;switch (settings.name) {case "/login":return SimpleRoute(name: "/login", title: "login", builder: (context) => LoginPage());case "/detail":if (args == null) {// 直接刷新當前,參數(shù)可能不存在,返回首頁return defaultRoute();}// 解析頁面?zhèn)鬟f的參數(shù)final topicId = SafeValue.toInt(args['topicId']);return SimpleRoute(name: "detail",title: "detaila",builder: (context) => DetailPage(topicId: topicId,));case "/":return defaultRoute();default:return defaultRoute();} }SimpleRoute defaultRoute() {return SimpleRoute(name: '/', title: 'swiftclub', builder: (context) => IndexPage()); } 復(fù)制代碼

    flutter_web 的路由,跟 flutter 的路由管理是一樣的,主要是注意兩點:

    • 如果刷新當前頁面,之前其他頁面?zhèn)鬟f過來的參數(shù)就沒有了,刷新后,頁面獲取不到傳遞過來的參數(shù),進行網(wǎng)絡(luò)請求,報錯。所以這里做了判斷,如果參數(shù)不存在了,則返回到默認的首頁。

    • 路由參數(shù)取值,嘗試多次,發(fā)現(xiàn)

      ModalRoute.of(context).settings.arguments; 復(fù)制代碼

    獲取不到 arguments,但在判斷路由的時候可以獲取。

    網(wǎng)絡(luò)請求

    由于 dart:io 在 flutter_web 中還不支持,所以 dio 是不能使用的,官方建議使用 package:http

    Flutter for web: Frequently Asked Questions

    為此做了個 http 請求的封裝,可參考使用:

    import 'dart:convert'; import 'package:flutter_web/widgets.dart'; import 'package:http/http.dart' as http; import 'package:swiftclub/kit/macro/macro.dart';class Network {static getReq(String url, {Map params, Map headers}) async {var fullUrl = Macro.URL_base + url;return await _getReq(fullUrl, params: params, headers: headers);}static _getReq(String url, {Map params, Map headers}) async {var reqUri = _uriWith(url, queryParameters: params);http.Response response = await http.get(reqUri, headers: headers);var responseBody = json.decode(response.body);return responseBody;}static _postReq(String url, {Map headers, Map params}) async {var fullUrl = Macro.URL_base + url;if (headers != null && headers.isNotEmpty) {http.Response response =await http.post(Uri.parse(fullUrl), headers: headers, body: params);var responseBody = json.decode(response.body);return responseBody;} else {http.Response response =await http.post(Uri.parse(fullUrl), body: params);var responseBody = json.decode(response.body);return responseBody;}}static Uri _uriWith(String url, {Map queryParameters}) {String _url = url;String query = _urlEncodeMap(queryParameters);if (query.isNotEmpty) {_url += (_url.contains("?") ? "&" : "?") + query;}// Normalize the url.return Uri.parse(_url).normalizePath();}static String _urlEncodeMap(data) {StringBuffer urlData = StringBuffer("");bool first = true;void urlEncode(dynamic sub, String path) {if (sub is List) {for (int i = 0; i < sub.length; i++) {urlEncode(sub[i],"$path%5B${(sub[i] is Map || sub[i] is List) ? i : ''}%5D");}} else if (sub is Map) {sub.forEach((k, v) {if (path == "") {urlEncode(v, "${Uri.encodeQueryComponent(k)}");} else {urlEncode(v, "$path%5B${Uri.encodeQueryComponent(k)}%5D");}});} else {if (!first) {urlData.write("&");}first = false;urlData.write("$path=${Uri.encodeQueryComponent(sub.toString())}");}}urlEncode(data, "");return urlData.toString();} } 復(fù)制代碼

    markdown 渲染

    在 github 上巡游一番,應(yīng)該找不到針對 flutter_web 的 markdown 的支持庫。筆者在參考

    • flutter/flutter_markdown
    • JakeCai/flutter_web_markdown
    • alibaba/flutter-go

    封裝了在 flutter_web 上可用的 markdown 組件,具體實現(xiàn)可參考 swiftclub/site

    語法高亮現(xiàn)在只支持 dart 語言的。

    效果

    更多閱讀,請關(guān)注 SwiftOldBird 官方微信公眾號

    原文:swiftoldbird.loveli.site/2019/08/22/…

    轉(zhuǎn)載于:https://juejin.im/post/5d5e666ff265da03a715da36

    總結(jié)

    以上是生活随笔為你收集整理的flutter_web 实战之文章列表与详情的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。