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;
    },
)

安卓固定屏幕的方法

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

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值