flutter開發中遇到的問題總結

文章目錄

flutter Error: Could not resolve the package ‘characters‘ in ‘package:characters/characters.dart‘.

背景:

升級flutter後,運行項目報錯。

解決過程:

修改項目目錄android/build.gradle裏的maven倉庫 無效!!!

flutter的issue搜索問題: Could not resolve the package ‘characters’ in ‘package:characters/characters.dart’.

解決方法:

使用命令:
flutter pub cache repair
flutter clean

成功。

兩個Contain嵌套,都設置尺寸,內部的Contain爲什麼尺寸不起作用

Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          width: 200,
          height: 200,
          color: Colors.yellow,
          child: Container(
            width: 100,
            height: 100,
            color: Colors.red,
          ),
        ),
      ),
    );
  }

顯示結果如下

image

解決辦法

給父Contain設置Alignment

class _HomePageState extends State<HomePage> {
  int _counter = 100;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          width: 200,
          height: 200,
          color: Colors.yellow,
          alignment: Alignment.center,
          child: Container(
            width: 100,
            height: 100,
            color: Colors.red,
          ),
        ),
      ),
    );
  }
}

如上面的頁面如何阻止事件冒泡

想辦法不要使用嵌套,比如使用stack進行佈局

充滿屏幕

遇到可用區域顯示不下

使用fitteedBox

多設備適配(推薦)

去掉安卓狀態欄半透明

在入口添加如下代碼

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 除半透明狀態欄
    if (Theme.of(context).platform == TargetPlatform.android) {
      // android 平臺
      SystemUiOverlayStyle _style = SystemUiOverlayStyle(statusBarColor: Colors.transparent);
      SystemChrome.setSystemUIOverlayStyle(_style);
    }
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: '美食廣場',
      theme: AppTheme.normalTheme,
      initialRoute: AppRouter.initRoute,
      routes: AppRouter.appRouters,
      onGenerateRoute: AppRouter.generateRouter,
      onUnknownRoute: AppRouter.unknowRouter,
    );
  }
}

解決ListView/GridView作爲Column的子Widget時候,會一片空白、不顯示。

如下圖,這種寫法下可滾動Widget顯示一片空白,編譯能通過。
image
方法一:
在Column中,再多使用Expanded包裹可滾動Widget,即可正常顯示。
image



方法二:
ListView/GridView的shrinkWrap改爲true值(默認false)。

flutter_swiper踩坑

flutter_swiper必須包裹在container中

Container(
  child:
     AspectRatio(
       aspectRatio: 20/9,
       child: Swiper(
         key: UniqueKey(),
         itemBuilder: (BuildContext context, int index) {
           return new Image.network(
             _Swiperlist[index]["path"].length>0?_Swiperlist[index]["path"]:"https://kt-1301681474.cos.ap-shanghai.myqcloud.com/app/rot/lbt_20200425181036.png",
             fit: BoxFit.fill,
           );
         },
         itemCount: _Swiperlist.length,
         viewportFraction: 0.8,
         scale: 0.9,
       ),
     )
 )

避免輪播圖尺寸在各設備上失真

採用AspectRatio來綁定尺寸

AspectRatio(
           aspectRatio: 20/9,

接口中獲取輪播圖引發的一系列錯誤

Flutter Swiper是一個輪播圖組件,內部包含一個Widget List,當這個Widget List數量發生變化的時候如果出現類似這種異常情況導致輪播圖不滑動或者其他紅屏等錯誤,

ScrollController not attached to any scroll views.

解決辦法

給Swiper加一個LocalKey即可解決,我這裏加了個UniqueKey,屬於一個LocalKey

AspectRatio(
    aspectRatio: 20/9,
       child: Swiper(
         key: UniqueKey(),
         itemBuilder: (BuildContext context, int index) {
           return new Image.network(
             _Swiperlist[index]["path"].length>0?_Swiperlist[index]["path"]:"https://kt-1301681474.cos.ap-shanghai.myqcloud.com/app/rot/lbt_20200425181036.png",
             fit: BoxFit.fill,
           );
         },
         itemCount: _Swiperlist.length,
         viewportFraction: 0.8,
         scale: 0.9,
       ),
     )

webview請求網絡錯誤

ListView 或者SingleChildScrollView 嵌套 ListView.builder滑動衝突

原因

SingleChildScrollView 和 ListView 都有滾動屬性physics 他們默認是都是可以滾動的,所以一起使用會報錯

報錯信息爲

RenderBox was not laid out: _RenderScrollSemantics#ccded relayoutBoundary=up1 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
‘package:flutter/src/rendering/box.dart’:
Failed assertion: line 1681 pos 12: ‘hasSize’

解決方式

禁用 ListView 的滾動physics 保留 SingleChildScrollView 的滾動
Listview 執行 physics 屬性 new NeverScrollableScrollPhysics(), //禁用滾動事件

ListView.builder(
  shrinkWrap: true,
  physics: new NeverScrollableScrollPhysics(),
)

ListView 嵌套 ListView.builder報錯

特別注意 ListView 嵌套 ListView.builder 需要後者shrinkWrap = true,不然報錯

文字顯示不下,顯示點點點

 Expanded(
    child: Text(
      "硬幣*清代雲南八兩元寶代雲南八兩元寶代雲南八兩元寶",
      maxLines: 1,
      overflow: TextOverflow.ellipsis,
    ),
  ),

GestureDetector部分區域點擊無效

添加下面屬性

behavior: HitTestBehavior.opaque,

國際化

安裝插件

WX20200928-101210@2x.png

在pubspec.yaml添加

flutter_intl:
  enabled: true
flutter:
  uses-material-design: true

保存自動下載包後會初始化目錄
i10n.png

添加語言

mac下使用shift+command+p喚起命令界面
command.png
輸入flutter Intl就能看到Flutter Intl:Add locale,然後點擊就會彈出對話框,添加對應語言

刪除語言

同添加

如何控制APP全局語言類型

定義local_model

import 'package:flutter/material.dart';
import 'package:knowinApp/core/storage_manager.dart';
import 'package:knowinApp/generated/l10n.dart';

class LocaleModel extends ChangeNotifier {
//  static const localeNameList = ['auto', '中文', 'English'];
  static const localeValueList = ['zh', 'en', 'fr'];

  //
  static const kLocaleIndex = 'kLocaleIndex';

  int _localeIndex;

  int get localeIndex => _localeIndex;

  Locale get locale {
    if (_localeIndex > 0) {
      var value = localeValueList[_localeIndex].split("-");
      return Locale(value[0], value.length == 2 ? value[1] : '');
    }
    // 跟隨系統
    return null;
  }

  LocaleModel() {
    _localeIndex = StorageManager.sharedPreferences.getInt(kLocaleIndex) ?? 0;
  }

  switchLocale(int index) {
    _localeIndex = index;
    notifyListeners();
    StorageManager.sharedPreferences.setInt(kLocaleIndex, index);
  }

  static String localeName(index, context) {
    switch (index) {
      case 0:
        return S.of(context).autoBySystem;
      case 1:
        return '中文';
      case 2:
        return 'English';
      default:
        return '';
    }
  }
}

報錯before the binding was initialized.

Unhandled Exception: ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized.

在runApp(MyApp())前添加WidgetsFlutterBinding.ensureInitialized();
注意代碼的順序

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  Provider.debugCheckInvalidValueType = null;
  await StorageManager.init();
  // 初始化屏幕適配參數
  await SizeFit.init();
  // 獲取版本信息、設備信息
  await DeviceInfo.init();
  // 依賴注入service
  registerService();
  // SystemChrome.setEnabledSystemUIOverlays([]); //隱藏狀態欄,底部按鈕欄
  SystemUiOverlayStyle _style =
      SystemUiOverlayStyle(statusBarColor: Colors.transparent);
  SystemChrome.setSystemUIOverlayStyle(_style);

  runApp(MyApp());
}

那WidgetsFlutterBinding.ensureInitialized();這一行代碼到底幹啥的呢,WidgetsFlutterBinding字面意思呢,Widget和Flutter綁定,追溯一下源碼看看:

繼承自BindingBase ,然後還有一堆手勢綁定、服務綁定什麼的,一看就是初始化操作,然後看中間有一段註釋:

不細翻譯了,大意就是在需要的時候調用,那什麼時候需要呢,回到開頭,在訪問二進制文件或者初始化插件的時候,需要在runApp()之前調用WidgetsFlutterBinding.ensureInitialized() 。

自定義顏色不起作用

Color定義方式

方式一

Color(0xFF393943)

理解各部分的含義

  • 0x:16進制
  • FF:透明度
  • 393943:RGB色值

方式二

Color.fromARGB(1,255,134,245)

注意是ARGB不是RGBA

方式三


軟鍵盤彈出引起佈局報錯

解決辦法

return Scaffold(

 appBar: AppBar(
   title: new Text("通訊錄"),
 ),

resizeToAvoidBottomPadding: false, //輸入框抵住鍵盤 內容不隨鍵盤滾動

);

設置支持屏幕旋轉類型

導包

import 'package:flutter/services.dart';

支持橫堅屏切換

SystemChrome.setPreferredOrientations(
      [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);

全局設置

SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown])
  .then((_) {
    runApp(new MyApp());
});

很可能會出現這個錯誤:

E/flutter (12370): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized.
E/flutter (12370): If you're running an application and need to access the binary messenger before `runApp()` has been called (for example, during plugin initialization), then you need to explicitly call the `WidgetsFlutterBinding.ensureInitialized()` first.
E/flutter (12370): If you're running a test, you can call the `TestWidgetsFlutterBinding.ensureInitialized()` as the first line in your test's `main()` method to initialize the binding.

在main()中進行異步處理時,應編寫以下代碼

WidgetsFlutterBinding.ensureInitialized();

Flutter禁止橫屏

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
      .then((_) {
    runApp(new MyApp());
  });
}

ListView顯示滾動條

默認情況下,Flutter 的滾動組件(比如 ListView)沒有顯示滾動條,使用 Scrollbar 顯示滾動條:

Scrollbar(
  child: ListView.builder(
    reverse: false,
    itemBuilder: (BuildContext context, int index) {
      return Card(
        child: Container(
          height: 45,
          alignment: Alignment.center,
          child: Text('$index'),
        ),
      );
    },
    itemCount: 30,
    itemExtent: 50,
  ),
)

路由的跳轉

正常跳轉

Navigator.pushNamed(context,'/product');

路由替換

Navigator.pushReplacementNamed(context, '/productinfo',
     arguments: {"pid":778899}
);

返回上一頁

Navigator.of(context).pop();

返回根路由

Navigator.of(context).pushAndRemoveUntil(
    new MaterialPageRoute(builder: (context)=>new Tabs(index: 1)),
     (route)=>route==null
);

flutter文本下面有黃色

導至原因

導致這種情況發生的原因是因爲,Text widget 隸屬於Material 風格下的組件,如果根節點不是Material 相關組件,則會使用默認帶黃色下劃線的格式。如果根節點是Material 容器組件,則會採用其Material風格的樣式(即不帶有下換線)。

解決方式

採用根節點爲腳手架Scaffold組件

Scaffold(body: content,);

採用根節點爲Material 組件

Material(child: content);

逐個修改Text 組件的style 下的decoration爲TextDecoration.none

child: Text(
  "專欄的文章",
  overflow: TextOverflow.ellipsis,
  style: TextStyle(
    decoration: TextDecoration.none,
    color: Color(0xFF888888),
    fontSize: 14,
    fontWeight: FontWeight.bold,
    fontFamily: defaultFontFamily,
  ),
)

在項目中發現第一種和第二種不起作用,使用第三種解決了,具體原因沒有細查,理論上第一種和第二種是沒問題的

自定義下拉框

https://blog.csdn.net/gzx110304/article/details/103891991

無context跳轉

void main() {
  runApp(MyApp());
}
 
final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
 
class MyApp extends StatelessWidget {
  MyApp() {
  }
 
  // This widget is the view.common.root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: navigatorKey,
    );
  }

navigatorKey.currentState.pushName('跳轉url')

在父組件獲取子組件點擊事件

用 Listener的onPointerDown 包裹一下,就可以透傳點擊事件了。

Listener(
      child: body,
      onPointerDown: (enter){
        print("onPointerEnter");
        if (onTap != null){
          onTap();
        }
      },
    ),

監聽鍵盤事件

鍵盤彈出

 final FocusNode _focusNode = new FocusNode();
  new TextField(focusNode: _focusNode,),

請求收起鍵盤

FocusScope.of(context).requestFocus(new FocusNode());

監聽鍵盤是否顯示

WidgetsBinding.instance.addPostFrameCallback(() {
  setState(() {
    // 鍵盤高度:大於零,鍵盤彈出,否則,鍵盤隱藏
    MediaQuery.of(context).viewInsets.bottom > 0;
  });
});
class _KeyboardDetectorState extends State<KeyboardDetector>
 with WidgetsBindingObserver {
@override
void initState() {
 WidgetsBinding.instance.addObserver(this);
 super.initState();
}

@override
void didChangeMetrics() {
 super.didChangeMetrics();
 WidgetsBinding.instance.addPostFrameCallback((_) {
   setState(() {
     widget.keyboardShowCallback
         ?.call(MediaQuery.of(context).viewInsets.bottom > 0);
   });
 });
}

@override
void dispose() {
 WidgetsBinding.instance.removeObserver(this);
 super.dispose();
}

文本顯示不下,報錯顯示黃邊

使用expanded包裹父容器

監聽返回

WillPopScope(
    onWillPop: () async {
      return false;
    },
)

安卓固定屏幕的方法

設置 > 安全性和位置信息 > 高級 > 屏幕固定(更好的辦法是在設置中直接搜索“屏幕固定”)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章