本文共 7677 字,大约阅读时间需要 25 分钟。
Flutter 命令行创建项目
可以指定语言: -i -> iOS
, -a -> android
flutter create -i objc -a java #项目名# flutter create -i swift -a kotlin #项目名#
创建完项目之后, cd到项目文件夹下
// 查看支持的设备flutter devices// 打开模拟器flutter emulators --launch apple_ios_simulator//运行项目flutter run//flutter 清理项目flutter clean
Column中嵌套Column或者Row中嵌套Row
Flutter 三种方式实现页面切换后保持原页面状态
flutter中,保存页面的状态issue
使用上面文章中的方法仅仅可以保存 “没有导航栏跳转的情况”,
如果在页面中放置一个按钮然后跳转到子页面,此时外部部分页面如果不做额外处理,则会销毁。
处理方法:
除了要在需要保存状态的widget中混入 AutomaticKeepAliveClientMixin,然后重写 方法:@override bool get wantKeepAlive => true;还要在页面的build方法中,调用 super.build(context); 方法
flutter截长图
json -> dart
父控件根据子控件高度自适应
① column中放不可滚动的组件,设置mainAxisSize: MainAxisSize.min即可 ② column中放ListView等可以滚动的组件,则除了要设置主轴Size为MainAxisSize.min之外,还要设置ListView的shrinkWrap: true,
这个属性是大部门可以滚动的组件(ListView,GridView)的父类ScrollView的属性,用来确定scrollview的内容高度是否由子组件决定 /// Whether the extent of the scroll view in the [scrollDirection] should be /// determined by the contents being viewed. /// Defaults to false. final bool shrinkWrap;
③ 在自定义iOS样式的AlertController的时候,我使用了AlertDialog -> Column -> ListView这样的布局方式,结果发现会报错
RenderShrinkWrappingViewport does not support returning intrinsic dimensions
flutter调用iOS中api修改:
import UIKitimport Flutter@UIApplicationMain@objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) let controller : FlutterViewController = window?.rootViewController as! FlutterViewController; let batteryChannel = FlutterMethodChannel.init(name: "com.flutter.io/wififx", binaryMessenger: controller.binaryMessenger); batteryChannel.setMethodCallHandler({ (call: FlutterMethodCall, result: FlutterResult) -> Void in // Handle battery messages. if ("getBatteryLevel" == call.method) { self.receiveBatteryLevel(result: result); } else { result(FlutterMethodNotImplemented); } }); return super.application(application, didFinishLaunchingWithOptions: launchOptions) } private func receiveBatteryLevel(result: FlutterResult) { let device = UIDevice.current; device.isBatteryMonitoringEnabled = true; if (device.batteryState == .unknown) { result(FlutterError.init(code: "UNAVAILABLE", message: "电池信息不可用", details: nil)); } else { result(Int(device.batteryLevel * 100)); } }}
Android Studio打开flutter项目的时候,设备列表那里一直是loading。
解决方法: 全凭运气。。。
查找带dart的进程,杀掉,然后重启as
此时命令行执行flutter doctor
, 偶然间好了。。
删除 flutter/bin/cache/路径下的lockfile、flutter.bat.lock文件
重启电脑
等着吧。。
Flutter i18n 国际化
Sliver效果的列表添加下拉刷新
Use Flutter in China
属性传值、InheritedWidget、Notification、EventBus区别
原生项目集成flutter之后,页面跳转管理
flutter切换字体
Android Studio Flutter Shortcut
Flex/Row/Column、 Flexible/Expanded
①. Row、Column 都是继承于 Flex的组件, 可以设置子widget的对齐方式 ②. Expanded是继承于Flexible的widget,可以看做 flex为1,fit为FlexFit.tight 的Flexible组件 Expanded可以放到①中的组件中:flutter 分享
Flutter项目编译报错
cd到你的项目文件夹下;在终端执行下面的代码:xattr -rc . // 别忘了后面是有一个点.的然后,执行 flutter run 就OK了。
相关命令
查看造成错误的文件
xattr -lr
删除造成错误的文件
xattr -cr
Future、 async、 await
结论:
async是标志方法需要一段时间才能得到返回值。 await字面上意思是 等待异步的方法执行完成之后再执行后续代码(会阻塞当前方法)Stack的宽高,根据子组件来变化
Stack/ IndexedStack
自定义bottomNavigationBar 使用Lottie动画组件
参考插件
FF-Navigation bar Bottom personalized bot bar Titled Bottom Navigation Bar Bubbled Navigation Bar Bottom NavyBarFlutter 类中创建私有变量
class FXTabbarItem extends StatefulWidget { /// tabbarItem 标题 String _title; /// json文件路径 String _jsonFile; Key _itemKey; /// 点击回调 VoidCallback _onTapCallBack; /// 文字常规样式 final TextStyle titleNormalStyle; /// 文字选中样式 final TextStyle titleSelectStyle; /// 是否是选中状态 final bool isSelected; FXTabbarItem({ @required String title, @required String jsonFile, @required Key itemKey, @required VoidCallback onTap, this.isSelected, this.titleNormalStyle, this.titleSelectStyle, }) : _title = title, _jsonFile = jsonFile, _itemKey = itemKey, _onTapCallBack = onTap; @override _FXTabbarItemState createState() => _FXTabbarItemState();}
如果还有super继承的
class FXDealerDetailHeader extends StatefulWidget { final FXTraderModel _traderModel; FXDealerDetailHeader({Key key, FXTraderModel traderModel}) : _traderModel = traderModel, super(key: key); @override _FXDealerDetailHeaderState createState() => _FXDealerDetailHeaderState();}
使用GlobalKey,在帧绘制回调的时候获取组件的frame
WidgetsBinding 提供了单次 Frame 绘制回调及实时 Frame 绘制回调两种机制
WidgetsBinding.instance.addPostFrameCallback((_){ print("addPostFrameCallback 绘制回调"); // 只回调一次});
WidgetsBinding.instance.addPersistentFrameCallback((_){ print("addPersistentFrameCallback 绘制回调"); // 每帧都回调});
使用Builder组件
Builder( builder: (context) { return IconButton( icon: Icon(Icons.flight), onPressed: () { /// 通过 Builder 组件获取 context即element, /// 再通过element获取renderObject, 即可拿到组件信息 RenderBox box = context.findRenderObject() as RenderBox; var offset = box.localToGlobal(Offset.zero); var size = box.currentContext.size; }, ); },)
Flutter 文字下面显示双黄线
原因: Text组件,默认使用的是Material节点中的TextStyle,所以我们可以在Text组件外面包裹Material组件
Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Sample Code'), ), body: Center( child: Text('You have pressed the button $_count times.') ), backgroundColor: Colors.blueGrey.shade200, floatingActionButton: FloatingActionButton( onPressed: () => setState(() => _count++), tooltip: 'Increment Counter', child: const Icon(Icons.add), ), );}
Widget build(BuildContext context) { return Material( type: MaterialType.transparency, child: Container() );}
Text("Text Content", style: TextStyle( decoration: TextDecoration.none, ));
Flutter Text TextOverflow.ellipsis 默认 按单词 切割
问题描述
考虑替代方案:
Flutter VS Code 编译器 有选中的代码块的时候无代码提示问题
在设置中搜索 prevent, 然后在 Editor > Suggest: Snippets Prevent Quick Suggestions
前面,把√去掉即可
30 Best Flutter App Templates in 2020
Flutter 绘制虚线
两种方法:
使用canvas绘图的时候绘制,此时要依赖第三方库来实现:
使用widget层的listView来构建Widget
一个类似iOS JXCategoryView LineView效果的tabbar
路径: /lib/smart_tabbar.dartFlutter BezierPath 实现类似iOS strokeEnd 动画效果
Path path = Path(); path.moveTo(0, size.height / 2); //直线测试 // path.lineTo(size.width / 2, size.height / 2); // path.lineTo(size.width, 0); //曲线测试, ⚠️⚠️ Flutter使用和 iOS一样的绘图坐标系 ⚠️⚠️ path.addArc( Rect.fromCenter( center: Offset(size.width / 2, size.height / 2), width: size.width, height: size.height), 0, -pi/2); var pathMetrics = path.computeMetrics(forceClosed: false); var list = pathMetrics.toList(); var length = progress * list.length.toInt(); Path newPath = new Path(); for (int i = 0; i < length; i++) { var extractPath = list[i] .extractPath(0, list[i].length * progress, startWithMoveTo: true); newPath.addPath(extractPath, Offset(0, 0)); } canvas.drawPath(newPath, paint);
参考:
作者:wwwwwwdi 链接:https://www.jianshu.com/p/8ce1840b69e9 来源:简书 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。