老孟导读:一个月前分享的《超过百万的StackOverflow Flutter 问题-第一期》受到很多朋友的喜欢,非常感谢大家的支持,在文章末尾有第一期的链接,希望此文能对你有所帮助。

这个问题估计大部分都遇到过,解决方法如下:

  1. 执行flutter doctor

    1. Doctor summary (to see all details, run flutter doctor -v):
    2. [✓] Flutter (Channel stable, v1.12.13+hotfix.9, on Mac OS X 10.14.6 18G1012,
    3. locale zh-Hans-CN)
    4. [!] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
    5. ! Some Android licenses not accepted. To resolve this, run: flutter doctor
    6. --android-licenses
    7. [✓] Xcode - develop for iOS and macOS (Xcode 11.3.1)
    8. [✓] Android Studio (version 3.5)
    9. [✓] Connected device (1 available)
    10. ! Doctor found issues in 1 category.

    保证没有红色的叉。

  2. 启动手机或者模拟器(Android系统大于16),开启USB 调试模式,不同手机开启方法略有不同,以华为手机为例:进入设置->系统->关于手机,快速连续点击版本号5次,提示打开开发者模式,返回设置,此时会出现开发人员选项菜单,进入,打开开发人员选项USB 调试,弹出授权菜单,同意即可。

  3. 打开Android Studio,查看连接的手机:

    enter image description here

  4. 如果依然无法连接手机,打开Android Studio设置界面:

    enter image description here

    选择最近的API。

  5. 到此基本就可以解决了,如果还无法连接,那基本就是adb的问题,很可能是adb端口被占用,关于adb的解决方案可百度,引起adb问题有很多种情况。

Material Design设计规范中Snackbars就是Toast提示,Snackbar用法如下:

  1. Scaffold.of(context).showSnackBar(SnackBar(
  2. content: Text("Sending Message"),
  3. ));

enter image description here

这个效果在国内来不是很接受,所以一般使用第三方插件fluttertoast

  1. Fluttertoast.showToast(
  2. msg: "This is Toast messaget",
  3. toastLength: Toast.LENGTH_SHORT,
  4. gravity: ToastGravity.CENTER,
  5. timeInSecForIos: 1
  6. );

enter image description here

创建圆角Button的方式有很多种,下面介绍几种简单的:

  1. 使用 FlatButtonRaisedButton

    1. shape: RoundedRectangleBorder(
    2. borderRadius: BorderRadius.circular(18.0),
    3. side: BorderSide(color: Colors.red)
    4. ),

    enter image description here

  2. 使用ClipRRect

    1. ClipRRect(
    2. borderRadius: BorderRadius.circular(40),
    3. child: RaisedButton(
    4. onPressed: () {},
    5. child: Text("Button"),
    6. ),
    7. )
  3. 使用ButtonTheme

    1. ButtonTheme(
    2. shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
    3. child: RaisedButton(
    4. onPressed: () {},
    5. child: Text("Button"),
    6. ),
    7. )

Flutter应用程序启动时会出现一段时间的白屏,因为程序要启动引擎,所以App第一次启动比较慢,在原生端会显示一段时间的白色启动页,我们把这个白色启动页做为应用程序的启动页,替换为自己的图片,此方案的启动页只能是一张图片,无法交互,如果需要启动页有交互效果建议使用Flutter做。

Android端替换启动页图片,打开android/app/src/main/res/drawable/launch_background.xml文件,效果如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!-- Modify this file to customize your launch splash screen -->
  3. <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  4. <item android:drawable="@android:color/white" />
  5. <!-- You can insert your own image assets here -->
  6. <!-- <item>
  7. <bitmap
  8. android:gravity="center"
  9. android:src="@mipmap/launch_image" />
  10. </item> -->
  11. </layer-list>

修改为:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!-- Modify this file to customize your launch splash screen -->
  3. <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  4. <item>
  5. <bitmap
  6. android:gravity="center"
  7. android:src="@drawable/splash" />
  8. </item>
  9. </layer-list>

splash.png图片拷贝到drawable文件夹下。

iOS端,打开ios/Runner/Assets.xcassets/LaunchImage.imageset下面的3张LaunchImage.png图片替换,保持名称不变。

Android平台上打开android/app/build.gradle:

  1. defaultConfig {
  2. applicationId "com.example.fluttersample"
  3. minSdkVersion 16
  4. targetSdkVersion 28
  5. versionCode flutterVersionCode.toInteger()
  6. versionName flutterVersionName
  7. testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  8. }

修改applicationId属性即可。

iOS平台打开ios/Runner/Info.plist,修改CFBundleIdentifier的值:

  1. <key>CFBundleIdentifier</key>
  2. <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
  1. new Container(
  2. margin: const EdgeInsets.all(15.0),
  3. padding: const EdgeInsets.all(3.0),
  4. decoration: BoxDecoration(
  5. border: Border.all(color: Colors.blueAccent)
  6. ),
  7. child: Text("My Awesome Border"),
  8. )

enter image description here

  1. SizedBox.expand(
  2. child: RaisedButton(...),
  3. )

或者

  1. SizedBox(
  2. width: double.infinity,
  3. // height: double.infinity,
  4. child: RaisedButton(...),
  5. )

或者

  1. ConstrainedBox(
  2. constraints: const BoxConstraints(minWidth: double.infinity),
  3. child: RaisedButton(...),
  4. )

或者

  1. ButtonTheme(
  2. minWidth: double.infinity,
  3. child: MaterialButton(
  4. onPressed: () {},
  5. child: Text('Raised Button'),
  6. ),
  7. ),

给ListView指定高度:

  1. Column(
  2. children: <Widget>[
  3. Container(
  4. height: 50,
  5. child: ListView(),
  6. )
  7. ],
  8. )

或者铺满Column:

  1. Column(
  2. children: <Widget>[
  3. Expanded(
  4. child: horizontalList,
  5. )
  6. ],
  7. );
  1. ClipRRect(
  2. borderRadius: BorderRadius.circular(8.0),
  3. child: Image.network(
  4. '',
  5. ),
  6. )

或者

  1. CircleAvatar(
  2. radius: 20,
  3. backgroundImage: NetworkImage('https://via.placeholder.com/140x100')
  4. )

或者

  1. ClipOval(
  2. child: Image.network(
  3. "image_url",
  4. height: 100,
  5. width: 100,
  6. fit: BoxFit.cover,
  7. ),
  8. ),

或者

  1. Container(
  2. width: 100.0,
  3. height: 150.0,
  4. decoration: BoxDecoration(
  5. image: DecorationImage(
  6. fit: BoxFit.cover,
  7. image: NetworkImage('Path to your image')
  8. ),
  9. borderRadius: BorderRadius.all(Radius.circular(8.0)),
  10. color: Colors.redAccent,
  11. ),
  1. InputDecoration(
  2. border: InputBorder.none,
  3. hintText: 'Username',
  4. ),
  5. ),

设置支持的方向:

  1. class MyApp extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. SystemChrome.setPreferredOrientations([
  5. DeviceOrientation.portraitUp,
  6. DeviceOrientation.portraitDown,
  7. ]);
  8. return new MaterialApp(...);
  9. }
  10. }

打开ios/Runner/Info.plist,设置支持的方向:

  1. <array>
  2. <string>UIInterfaceOrientationPortrait</string>
  3. </array>

使用Opacity

  1. Opacity(
  2. opacity: .0,
  3. child: ,
  4. )

或者

  1. Visibility(
  2. visible: false,
  3. child: ,
  4. )

或者

  1. Offstage(
  2. offstage: true,
  3. child: ,
  4. )

使用WillPopScope

  1. @override
  2. Widget build(BuildContext context) {
  3. return new WillPopScope(
  4. onWillPop: () async => false,
  5. child: new Scaffold(
  6. appBar: new AppBar(
  7. title: new Text("data"),
  8. leading: new IconButton(
  9. icon: new Icon(Icons.ac_unit),
  10. onPressed: () => Navigator.of(context).pop(),
  11. ),
  12. ),
  13. ),
  14. );
  15. }
  1. ButtonTheme(
  2. minWidth: 200.0,
  3. height: 100.0,
  4. child: RaisedButton(
  5. onPressed: () {},
  6. child: Text("test"),
  7. ),
  8. );

或者

  1. SizedBox(
  2. width: 100, // specific value
  3. child: RaisedButton(...)
  4. )

使用PreferredSize

  1. class MyApp extends StatelessWidget {
  2. @override
  3. Widget build(BuildContext context) {
  4. return MaterialApp(
  5. title: 'Example',
  6. home: Scaffold(
  7. appBar: PreferredSize(
  8. preferredSize: Size.fromHeight(50.0), // here the desired height
  9. child: AppBar(
  10. // ...
  11. )
  12. ),
  13. body: // ...
  14. )
  15. );
  16. }
  17. }

Dart API本身没有格式化时间的接口,使用intl

  1. import 'package:intl/intl.dart';
  2. DateTime now = DateTime.now();
  3. String formattedDate = DateFormat('yyyy-MM-dd – kk:mm').format(now);
  1. Widget getTextWidgets(List<String> strings)
  2. {
  3. List<Widget> list = new List<Widget>();
  4. for(var i = 0; i < strings.length; i++){
  5. list.add(new Text(strings[i]));
  6. }
  7. return new Row(children: list);
  8. }

或者

  1. Row(children: strings.map((item) => new Text(item)).toList())

或者

  1. var list = ["one", "two", "three", "four"];
  2. child: Column(
  3. mainAxisAlignment: MainAxisAlignment.center,
  4. children: <Widget>[
  5. for(var item in list ) Text(item)
  6. ],
  7. ),

使用childAspectRatio,设置如下:

  1. class MyHomePage extends StatefulWidget {
  2. MyHomePage({Key key, this.title}) : super(key: key);
  3. final String title;
  4. @override
  5. _MyHomePageState createState() => new _MyHomePageState();
  6. }
  7. class _MyHomePageState extends State<MyHomePage> {
  8. List<String> widgetList = ['A', 'B', 'C'];
  9. @override
  10. Widget build(BuildContext context) {
  11. var size = MediaQuery.of(context).size;
  12. /*24 is for notification bar on Android*/
  13. final double itemHeight = (size.height - kToolbarHeight - 24) / 2;
  14. final double itemWidth = size.width / 2;
  15. return new Scaffold(
  16. appBar: new AppBar(
  17. title: new Text(widget.title),
  18. ),
  19. body: new Container(
  20. child: new GridView.count(
  21. crossAxisCount: 2,
  22. childAspectRatio: (itemWidth / itemHeight),
  23. controller: new ScrollController(keepScrollOffset: false),
  24. shrinkWrap: true,
  25. scrollDirection: Axis.vertical,
  26. children: widgetList.map((String value) {
  27. return new Container(
  28. color: Colors.green,
  29. margin: new EdgeInsets.all(1.0),
  30. child: new Center(
  31. child: new Text(
  32. value,
  33. style: new TextStyle(
  34. fontSize: 50.0,
  35. color: Colors.white,
  36. ),
  37. ),
  38. ),
  39. );
  40. }).toList(),
  41. ),
  42. ),
  43. );
  44. }
  45. }

使用flutter_statusbarcolor

  1. import 'package:flutter_statusbarcolor/flutter_statusbarcolor.dart';
  2. void main() => runApp(new MyApp());
  3. class MyApp extends StatelessWidget {
  4. @override
  5. Widget build(BuildContext context) {
  6. FlutterStatusbarcolor.setStatusBarColor(Colors.white);
  7. return MaterialApp(
  8. title: app_title,
  9. theme: ThemeData(
  10. primarySwatch: Colors.blue,
  11. ),
  12. home: HomePage(title: home_title),
  13. );
  14. }
  15. }

或者

  1. SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
  2. statusBarColor: Colors.white
  3. ));
  1. return Column(
  2. crossAxisAlignment: CrossAxisAlignment.center,
  3. mainAxisSize: MainAxisSize.max,
  4. mainAxisAlignment: MainAxisAlignment.end,
  5. children: <Widget>[
  6. //your elements here
  7. ],
  8. );

老孟Flutter博客地址(近200个控件用法):http://laomengit.com

欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】:

版权声明:本文为mengqd原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/mengqd/p/12892707.html