The ‘Pods-wii’ target has frameworks with conflicting names: iflymsc.framework 原因是:iflymsc.framework接入 native 中和之前 flutter 中的iflymsc.framework冲突了
解决方式:flutter 缓存删除即可(从主工程的 development pods 的xxx_msc_plugin中删除)
TabController addListener两次回调 问题:这个监听在点击切换tab的时候会回调两次,左右滑动切换tab正常调用一次。
TabController addListener两次回调问题 1 2 3 4 5 6 7 8 9 10 _tabController = new TabController( length: 3 , vsync: this , initialIndex: currentTabIndex); _tabController.addListener(() { if (_tabController.index == _tabController.animation.value) { } } });
flutter 解决中英文自动换行 1 2 3 4 5 6 extension FixAutoLines on String { String fixAutoLines() { return Characters(this ).join('\u{200B}' ); } }
pageKey 区分不同页面 UniqueKey().toString() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 handleMsg(arguments) { setState(() { isShowOverlay = false ; }); Map changeParam = Map %3 CString, dynamic %3 E.from(arguments ?? Map ); if (widget.pageKey == changeParam[AppConstant.PAGE_KEY]) { hardCoveTipInfo = null ; param.clear(); changeParam.forEach((key, value) { if (TextUtils.isNotEmpty(value) && AppConstant.PAGE_KEY != key) { param[key] = value; } }); if (param[AppConstant.CHANNELTYPE] == AppConstant.C4) { } else { } } } jumpC4Board() { Map <String , dynamic > localParam = Map .castFrom(widget.param); localParam["fromC4C5Board" ] = "1" ; localParam["pageKey" ] = UniqueKey().toString(); FlutterBoost.singleton .open(AnalysisRouteApi.nativeAnalysisHome, urlParams: localParam); }
图片处理 MultipartFile 转 jpg 失败 1 2 3 4 5 6 List <int > imageData = await asset.originBytes;MultipartFile multipartFile = new MultipartFile.fromBytes( imageData, filename: "asset.jpg" , contentType: MediaType("image" , "jpg" ), );
原因是苹果原生相机图片格式 heic 不能直接转 jpg,需要
1 借助 native 将 heic 转 jpg
2 直接压缩 heic 资源:thumbDataWithSize
解决方式一:借助 native插件实现 heic 转 jpg(方法见文末0x0000001)
原生方法:jpegData(compressionQuality: CGFloat)-> -> Data? // return image as JPEG. May return nil if image has no CGImageRef or invalid bitmap format. compression is 0(most)..1(least)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class HeicToJPGPlugin { static const String _channel = "com.xxxx/heicConvertJpg" ; static const String _methodConvertJpg= "convertToJPG" ; static const _perform = const MethodChannel(_channel); static Future<String > convertToJPG(String path) { return _perform.invokeMethod(_methodConvertJpg, {"heicPath" : path}); } } bool isHeic = false ;List <int > heicData;if (asset.title.contains(".HEIC" )) { isHeic = true ; File assetFile =await asset.originFile; String jpgPath = await HeicToJPGPlugin.convertToJPG(assetFile.path); File jpgFile = File(jpgPath); final Uint8List byteData = await jpgFile.readAsBytes(); heicData = List .from(byteData); } List <int > imageData = await asset.originBytes;
解决方式 二: 直接压缩heic asset.thumbDataWithSize
1 2 3 4 5 6 7 8 9 10 File assetFile =await asset.originFile; List <int > imageData = await asset.thumbDataWithSize(asset.size.width.toInt(), asset.size.height.toInt(),quality:await getCompressRate(assetFile.path));if (imageData != null ) { MultipartFile multipartFile = new MultipartFile.fromBytes( imageData, filename: "asset.jpg" , contentType: MediaType("image" , "jpg" ), ); }
阿里通过原生传递图片内存地址,将指针类 Point 处理成 Image 1 2 3 4 5 6 7 8 9 Pointer<Uint8> pointer = Pointer<Uint8>.fromAddress(handle); Uint8List pixels = pointer.asTypedList(length); ui.PixelFormat pixelFormat = Platform.isAndroid ? ui.PixelFormat. rgba8888 : ui.PixelFormat.bgra8888; ui.decodeImageFromPixels(pixels, width, height, pixelFormat, (ui.Image image) { }, rowBytes: rowBytes);
将原生处理后的图片地址,使用 File 处理为Uint8List 1 2 3 4 5 6 7 8 9 10 import 'dart:typed_data' ;File assetFile =await asset.originFile; String jpgPath = await HeicToJPGPlugin.convertToJPG(assetFile.path); File jpgFile = File(jpgPath); final Uint8List byteData = await jpgFile.readAsBytes(); List <int > heicData = List .from(byteData);
压缩 1 2 List <int > compressedImageData = await asset.thumbDataWithSize(asset.size.width.toInt(), asset.size.height.toInt(), quality: 80 );
代码 0x0000001 Swift 插件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class FlutterHeicToJpgPlugin : FlutterChannelType { public var name: String { return "com.xxx.xxx/plugin/heicConvertJpg" } public var method: String { return "convertToJPG" } public func handleMessage (arguments : [String : Any ]? , completion : @escaping FlutterChannelCompletion ) { if let arg = arguments, let heicPath = arg["heicPath" ] as? String { var jpgPath = heicPath if jpgPath.count == 0 { jpgPath = NSTemporaryDirectory ().appendingFormat("%d.jpg" , Date ().timeIntervalSince1970 * 1000 ) } let finalPath = fromHeicToJpg(heicPath: heicPath, jpgPath: jpgPath) completion(.success(finalPath)) } } func fromHeicToJpg (heicPath : String , jpgPath : String ) -> String ? { let heicImage : UIImage ? = UIImage (named:heicPath) if heicImage == nil { return nil } let jpgImageData = heicImage! .jpegData(compressionQuality: 1.0 ) FileManager .default.createFile(atPath: jpgPath, contents: jpgImageData, attributes: nil ) return jpgPath } }
0x00000002 TabController addListener定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 @override void addListener(VoidCallback listener) { assert (_debugAssertNotDisposed()); _listeners!.add(_ListenerEntry(listener)); } Animation<double >? get animation => _animationController?.view; AnimationController? _animationController; ```>)
字体 FLutter 字体默认不会跟随系统, Android 端默认使用 Roboto,而在 iOS 端默认使用 San Francisco。- 出处
文本 flutter 文本自动换行 Row
和 Column
是 Flex
组件,是无法滚动的,如果没有足够的空间,flutter就提示溢出错误。
这时候我们可以使用Expanded
或 Flexible
组件可用作长文本的自动换行。
Column Expanded Text maxLines多行文本计算报错 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Text( result!.trackName!, style: TextStyle(fontSize: 18 , fontWeight: FontWeight.bold), maxLines: 2 , ), ), SizedBox( height: 10 , ), Text( result!.artistName!, style: TextStyle(fontSize: 12 , fontWeight: FontWeight.bold), ), ], )
这是因为我们没有给Column 确定的高度,Expanded可以拓展高度但是需要知道边界在哪里。
所以我们修改如下,使用 Container 包裹 Column 来给定高度,同时给 Container 包裹 Expanded
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 Expanded( child: Container( height: 80 , child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Text( result!.trackName!, style: TextStyle(fontSize: 18 , fontWeight: FontWeight.bold), maxLines: 2 , ), ), SizedBox( height: 10 , ), Text( result!.artistName!, style: TextStyle(fontSize: 12 , fontWeight: FontWeight.bold), ), ], ), ), )
图片问题 压缩png: https://tinypng.com/
网络图片圆角显示-ClipRRect 1 2 3 4 5 6 7 8 ClipRRect( borderRadius: BorderRadius.circular(15 ), child: Image.network( result!.artworkUrl100.toString(), width: 60 , height: 60 , ), )
MethodChannel通信 Flutter端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; ... class _MyHomePageState extends State<MyHomePage> { static const platform = const MethodChannel('samples.flutter.io/battery'); @override Widget build(BuildContext context) { return Material( child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ RaisedButton( child: Text('Get Battery Level'), onPressed: _getBatteryLevel, ), Text(_batteryLevel), ], ), ), ); } // Get battery level. String _batteryLevel = 'Unknown battery level.'; Future<void> _getBatteryLevel() async { String batteryLevel; try { final int result = await platform.invokeMethod('getBatteryLevel'); batteryLevel = 'Battery level at $result % .'; } on PlatformException catch (e) { batteryLevel = "Failed to get battery level: '${e.message}'."; } setState(() { _batteryLevel = batteryLevel; }); } }
iOS端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 __weak typeof(self) weakSelf = self [batteryChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { if ([@"getBatteryLevel" isEqualToString:call.method]) { int batteryLevel = [weakSelf getBatteryLevel]; if (batteryLevel == -1) { result([FlutterError errorWithCode:@"UNAVAILABLE" message:@"Battery info unavailable" details:nil]); } else { result(@(batteryLevel)); } } else { result(FlutterMethodNotImplemented); } }];
Android端 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import io.flutter.app.FlutterActivity; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; public class MainActivity extends FlutterActivity { private static final String CHANNEL = "samples.flutter.io/battery"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( new MethodCallHandler() { @Override public void onMethodCall(MethodCall call, Result result) { // TODO } }); } } @Override public void onMethodCall(MethodCall call, Result result) { if (call.method.equals("getBatteryLevel")) { int batteryLevel = getBatteryLevel(); if (batteryLevel != -1) { result.success(batteryLevel); } else { result.error("UNAVAILABLE", "Battery level not available.", null); } } else { result.notImplemented(); } }
4、Flutter报错记录 1、Invalid Podfile
file: cannot load such file – ../flutter_module/.ios/Flutter/podhelper.rb 原因一是flutter_module文件下缺少.ios /Flutter/podhelper.rb
目录
其他原因:podfile.lock 缺少Flutter
1、flutter clean
2、flutter build ios
3、flutter pub get
cd 到iOS项目
执行pod install
即可解决问题
2、 No podspec found for Flutter
in ../xxx/xxx/.ios/Flutter/engine
原因是:flutter中的.ios需要重新编译
1、flutter clean
2、flutter build ios
3、flutter pub get
第二步 cd 到iOS项目
执行pod install
即可解决问题
bitcode bundle could not be generated because ‘/Users/xxx/Desktop/Dev/xxx/xxx/.ios/Flutter/engine/Flutter.framework/Flutter’ was built without full bitcode. All frameworks and dylibs for bitcode must be generated from Xcode Archive or Install build file ‘/Users/xxx/Desktop/Dev/xxx/xxx/.ios/Flutter/engine/Flutter.framework/Flutter’ for architecture armv7
使用了flutter的话 需要重新编译flutter
1 2 flutter clean flutter build ios
4、[!] Invalid Podfile
file: cannot load such file – ../xxx/xxx/.ios
/Flutter/podhelper.rb.
5、Flutter :MediaQuery.of() called with a context that does not contain a MediaQuery
MediaQuery.of() called with a context that does not contain a MediaQuery.
No MediaQuery ancestor could be found starting from the context that was passed to MediaQuery.of().
1 This can happen because you do not have a WidgetsApp or MaterialApp widget (those widgets introduce a MediaQuery), or it can happen if the context you use comes from a widget above those widgets.
The context used was: Scaffold dirty state: ScaffoldState#ba049(lifecycle state: initialized, tickers: tracking 2 tickers)
意思是你使用不包含mediaquery的上下文调用mediaquery.of()。
解决方案:MaterialApp()中home:里包裹你写好的页面即可
6、The following NoSuchMethodError was thrown building *DatePickerDialog(dirty, dependencies: [*LocalizationsScope-[GlobalKey#3867d], MediaQuery, InheritedTheme], state: DatePickerDialogState#9687b):
1 The method 'formatMediumDate' was called on null.
Receiver: null
Tried calling: formatMediumDate(Instance of ‘DateTime’)
The relevant error-causing widget was:
MaterialApp file:///Users/xxx/github/FlutterCoding/flutter_widgets/lib/main.dart:12:12
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 _DatePickerDialogState.build (package:flutter/src/material/pickers/date_picker_dialog.dart:350:23)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4619:28)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4502:15)
#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4675:11)
…
这是在增加国际化语言 locale: Locale(‘zh’), 后报错:原因是没有在MateirialApp添加supportedLocales:[]
在pubspec.yaml添加支持:
1 2 3 4 5 dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter
在顶级控件MaterialApp添加国际化支持:
1 2 3 4 5 6 7 8 9 10 11 12 MaterialApp( localizationsDelegates: [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], supportedLocales: [ const Locale('zh', 'CH'), const Locale('en', 'US'), ], locale: Locale('zh'), ... )
设置showDatePicker
的local参数如下:
1 2 3 4 showDatePicker( locale: Locale('zh'), ... )
7、Waiting for another flutter command to release the startup lock… 解决办法:
当你的项目异常关闭,或者android studio用任务管理器强制关闭,下次启动就会出现上面的一行话,
此时需要打开 flutter/bin/cache/lockfile,删除就行了
使用:rm ./flutter/bin/cache/lockfile
如果:flutter doctor
没有反应,先使用flutter --version
5 打包 ![image](/Users/longhuadmin/Library/Application Support/typora-user-images/image-20200723163111932.png)
6 flutter 禁止字体大小跟随系统字体改变大小 1、适配页面:修改MaterialApp
1 2 3 4 5 6 7 MaterialApp( builder: (BuildContext context, Widget child){ return MediaQuery(child: child,data:MediaQuery.of(context).copyWith(textScaleFactor: 1.0),); }, )
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @override Widget build(BuildContext context) { //1 ScreenUtil.init ScreenUtil.init(context, width: 750, height: 1334, allowFontScaling: true); return Scaffold( appBar: _buildAppBar(), backgroundColor: Pigment.fromString(AppColor.colorFFFFFF), // 2 MediaQuery(data: , child: ) body: MediaQuery( data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), child: Container( child: new Column( children: <Widget>[ _buildBodyAppBar(), _buildHeader(), Container( height: 10, color: Colors.white, ), // List Expanded(flex: 1, child: _buildListView()), ], ), ), ),// MediaQuery ); }
1 MediaQuery _PointerListener
但是我当时使用了很多Text 为了以后迭代方便 管理方便我是用了下边的方法
2、
适配Text:修改textScaleFactor为1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import 'package:flutter/material.dart'; import 'package:flutter_app2/View/FixedSizeText.dart'; class FixedSizeText extends Text { const FixedSizeText(String data, { Key key, TextStyle style, StrutStyle strutStyle, TextAlign textAlign, TextDirection textDirection, Locale locale, bool softWrap, TextOverflow overflow, double textScaleFactor = 1, int maxLines, String semanticsLabel, }) : super(data, key:key, style:style, strutStyle:strutStyle, textAlign:textAlign, textDirection:textDirection, locale:locale, softWrap:softWrap, overflow:overflow, textScaleFactor:textScaleFactor, maxLines:maxLines, semanticsLabel:semanticsLabel); }
重点是这一行代码
1 double textScaleFactor = 1,
然后在布局Widget的时候使用FixedSizeText代替Text
就可以达到禁止字体大小跟随系统字体改变大小目的了
3、适配TabBar()修改textScaleFactor为1
进入flutter/packages/flutter/lib/src/material/tabs.dart文件,修改_buildLabelText方法如下
1 2 3 Widget _buildLabelText() { return child ?? Text(text, softWrap: false, overflow: TextOverflow.fade, textScaleFactor: 1); }
7、限制TextFormField输入类型和长度 1 2 3 4 5 6 7 8 /// 10、TextField设置高度后hintText居中 /// TextField设置高度小于默认高度后会出现hintText不居中的情况,经过一番摸索后发现InputDecoration中contentPadding设置padding即可 TextField( decoration: InputDecoration( hintText: "用户名或邮箱", border: InputBorder.none, // 去掉下滑线 contentPadding: EdgeInsets.all(0) ),
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 TextFormField( style: TextStyle(fontSize: 14), controller: widget.textEditingController, inputFormatters: listTextInputFormatter, keyboardType: TextInputType.numberWithOptions(decimal: true), textAlign: TextAlign.right, decoration: InputDecoration( isDense: true, contentPadding: EdgeInsets.all(1), border: InputBorder.none, hintStyle: TextStyle( fontSize: 15, color: Pigment.fromString(AppColor.colorC1C1C1)), hintText: widget.hintTip ?? "", ), )
print(‘系统手势边距 -> ${MediaQuery.of(context).systemGestureInsets}’);
iOS CupertinoAlertDialog报错:’alertDialogLabel’ was called on null. 在 main.dart 的 MaterialApp 加入这个属性:
1 2 3 4 5 6 localizationsDelegates: [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, YabandLocalizationsDelegate.delegate, const FallbackCupertinoLocalisationsDelegate(), //加入这个, 上面三个是我用来国际化的 ],
然后创建对应的 class :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class FallbackCupertinoLocalisationsDelegate extends LocalizationsDelegate<CupertinoLocalizations> { const FallbackCupertinoLocalisationsDelegate(); @override bool isSupported(Locale locale) => true; @override Future<CupertinoLocalizations> load(Locale locale) => DefaultCupertinoLocalizations.load(locale); @override bool shouldReload(FallbackCupertinoLocalisationsDelegate old) => false; }
缺少buildBodyAppBar
AddedBusinessListFromDistrict 增值业务收入增长率:从地区级增值业务跳转过来
AddedValueBusinessIndexRanking
: 增值业务收入增长率
BusinessChargeFeeRate 收费率
BusinessPersonCreateRate 利润增长率 组件
BusinessProfitRate 利润增长率 组件
BusinessServiceSatisfy 外拓
RevenueAchieve 内容:利润增长率 组件
解决header手势冲突问题
解决ListView高度不能确定问题
解决Android首页卡顿问题