Android 开发者 Flutter 指南:视图、布局、Intents、Listviews 和 adapters

2019-06-1915:10:03APP与小程序开发Comments2,652 views字数 14824阅读模式

1.视图(上)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

2.如何在布局中添加或删除一个组件?(上)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

3.Intents(上)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

4.异步 UI(上)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

5.工程结构和资源文件(上)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

6.Activity 和 Fragment(上)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

7.布局(下)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

8.手势**和触摸事件处理(下)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

9.Listviews 和 adapters(下)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

10.文字处理(下)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

11.表单输入(下)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

12.Flutter 插件(下)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

13.主题(下)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

14.数据库和本地存储(下)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

15.通知(下)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html


七、布局文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

7.1 LinearLayout 的对应概念是什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Android 中,LinearLayout 用于线性布局你的控件—水平或者垂直。在 Flutter 中,使用 Row 或者 Column Widget 来实现相同的效果。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

如果你注意看的话,会发现下面的两段代码除了 Row 和 Column Widget 以外是一模一样的。它们的孩子是一样的,而这个特性可以被充分利用来开发包含有相同的孩子但是会随时间改变的复杂布局。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

@override
Widget build(BuildContext context) {
  return Row(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
      Text('Row One'),
      Text('Row Two'),
      Text('Row Three'),
      Text('Row Four'),
    ],
  );
}
@override
Widget build(BuildContext context) {
  return Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: [
      Text('Column One'),
      Text('Column Two'),
      Text('Column Three'),
      Text('Column Four'),
    ],
  );
}

如果想学习更多的构建线性布局的内容,请阅读社区贡献的 Medium 文章给 Android 开发者的 Flutter 指南:如何在 Flutter 中设计线性布局?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

7.2 RelativeLayout 的对应概念是什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

RelativeLayout 通过 Widget 的相互位置对它们进行布局。在 Flutter 中,有几种实现相同效果的方法。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

你可以通过组合使用 Column、Row 和 Stack Widget 实现 RelativeLayout 的效果。你还可以在 Widget 构造器内声明孩子相对父亲的布局规则。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

Collin 在 StackOverflow 上的回答是一个在 Flutter 中构建相对布局的好例子。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

7.3 ScrollView 的对应概念是什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Android 中,使用 ScrollView 布局控件—如果用户的设备屏幕比应用的内容区域小,用户可以滑动内容。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Flutter 中,实现这个功能的最简单的方法是使用 ListView Widget。从 Android 的角度看,这样做可能是杀鸡用牛刀了,但是 Flutter 中 ListView Widget 既是一个 ScrollView,也是一个 Android 中的 ListView。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

@override
Widget build(BuildContext context) {
  return ListView(
    children: [
      Text('Row One'),
      Text('Row Two'),
      Text('Row Three'),
      Text('Row Four'),
    ],
  );
}

7.4 在 Flutter 中如何处理屏幕旋转?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

FlutterView 会处理配置的变化,前提条件是在 AndroidManifest.xml 文件中声明了:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

android:configChanges="orientation|screenSize"

八、手势**和触摸事件处理文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

8.1 Flutter 中如何为一个 Widget 添加点击**器?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Android 中,你可以通过调用 setOnClickListener 方法在按钮这样的 View 上添加点击**器。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Flutter 中有两种添加触摸**器的方法:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

1.如果 Widget 支持事件**,那么向它传入一个方法并在方法中处理事件。例如,RaisedButton 有一个 onPressed 参数:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

@override
Widget build(BuildContext context) {
  return RaisedButton(
      onPressed: () {
        print("click");
      },
      child: Text("Button"));
}

2.如果 Widget 不支持事件**,将 Widget 包装进一个 GestureDetector 中并向 onTap 参数传入一个方法。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
      child: GestureDetector(
        child: FlutterLogo(
          size: 200.0,
        ),
        onTap: () {
          print("tap");
        },
      ),
    ));
  }
}

8.2 如何处理 Widget 上的其它手势?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

使用 GestureDetector 可以**非常多的手势,例如:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

  • Tap
  • onTapDown - 一个可能产生点击事件的指针触摸到屏幕的特定位置。
  • onTapUp - 一个产生了点击事件的指针停止触摸屏幕的特定位置。
  • onTap - A tap has occurred.
  • onTap - 一个点击事件已经发生。
  • onTapCancel - 之前触发了 onTapDown 事件的指针不会产生点击事件。
  • Double tap
  • onDoubleTap - 用户在屏幕同一位置连续快速地点击两次。
  • Long press
  • onLongPress - 指针在屏幕的同一位置保持了一段较长时间的触摸状态。
  • Vertical drag
  • onVerticalDragStart - 指针已经触摸屏幕并可能开始垂直移动。
  • onVerticalDragUpdate - 触摸屏幕的指针在垂直方向移动了更多的距离。
  • onVerticalDragEnd - 之前和屏幕接触并垂直移动的指针不再继续和屏幕接触,并且在和屏幕停止接触的时候以一定的速度移动。
  • Horizontal drag
  • onHorizontalDragStart - 指针已经触摸屏幕并可能开始水平移动。
  • onHorizontalDragUpdate - 触摸屏幕的指针在水平方向移动了更多的距离。
  • onHorizontalDragEnd - 之前和屏幕接触并水平移动的指针不再继续和屏幕接触,并且在和屏幕停止接触的时候以一定的速度移动。

下面的例子展示了一个实现了双击旋转 Flutter 标志的 GestureDetector:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

AnimationController controller;
CurvedAnimation curve;

@override
void initState() {
  controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
  curve = CurvedAnimation(parent: controller, curve: Curves.easeIn);
}

class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
          child: GestureDetector(
            child: RotationTransition(
                turns: curve,
                child: FlutterLogo(
                  size: 200.0,
                )),
            onDoubleTap: () {
              if (controller.isCompleted) {
                controller.reverse();
              } else {
                controller.forward();
              }
            },
        ),
    ));
  }
}

九、Listviews 和 adapters文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

9.1 ListView 在 Flutter 中的对应概念是什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

Flutter 中 ListView 的对应概念仍然是…ListView!文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

使用 Android 的 ListView 时,创建一个 adapter 并将其传给 ListView,ListView 渲染 adapter 返回的每一行内容。然后,你需要确保回收了每一行视图,否则,你会遇到各种奇怪的 界面和内存问题。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

因为 Flutter Widget 不可变的特点,你需要向 ListView 传入一组 Widget, Flutter 会保证滑动的快速顺畅。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

import 'package:flutter/material.dart';

void main() {
  runApp(SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Sample App"),
      ),
      body: ListView(children: _getListData()),
    );
  }

  _getListData() {
    List widgets = [];
    for (int i = 0; i < 100; i++) {
      widgets.add(Padding(padding: EdgeInsets.all(10.0), child: Text("Row $i")));
    }
    return widgets;
  }
}

9.2 如何知道点击了哪个列表项?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Android 中,ListView 有一个可以帮助你定位哪个列表项被点击了的方法 onItemClickListener。在 Flutter 中,则使用传入 Widget 的触摸**。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

import 'package:flutter/material.dart';

void main() {
  runApp(SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Sample App"),
      ),
      body: ListView(children: _getListData()),
    );
  }

  _getListData() {
    List widgets = [];
    for (int i = 0; i < 100; i++) {
      widgets.add(GestureDetector(
        child: Padding(
            padding: EdgeInsets.all(10.0),
            child: Text("Row $i")),
        onTap: () {
          print('row tapped');
        },
      ));
    }
    return widgets;
  }
}

9.3 如何动态更新 ListView?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Android 中,你需要更新 adapter 并调用 notifyDataSetChanged。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Flutter 中,如果你准备在 setState() 里更新一组 Widget,你很快会发现你的数据并没有 更新到界面上。这是因为当 setState() 被调用的时候,Flutter 渲染引擎会查看 Widget 树是否有任何更改。当引擎检查到 ListView,他会执行 == 检查,并判断两个 ListView 是一样的。没有任何更改,所以也就不需要更新。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

更新 ListView 的一个简单方法是,在 setState() 里创建一个新的 List,并将数据从旧列表拷贝到新列表。虽然这个方法很简单,就如下面例子所示,但是并不推荐在大数据集的时候使用。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

import 'package:flutter/material.dart';

void main() {
  runApp(SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  List widgets = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < 100; i++) {
      widgets.add(getRow(i));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Sample App"),
      ),
      body: ListView(children: widgets),
    );
  }

  Widget getRow(int i) {
    return GestureDetector(
      child: Padding(
          padding: EdgeInsets.all(10.0),
          child: Text("Row $i")),
      onTap: () {
        setState(() {
          widgets = List.from(widgets);
          widgets.add(getRow(widgets.length + 1));
          print('row $i');
        });
      },
    );
  }
}

推荐的高效且有效的创建一个列表的方法是使用 ListView.Builder。这个方法非常适用于动态列表或者拥有大量数据的列表。这基本上就是 Android 里的 RecyclerView,会为你自动回收列表项:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

import 'package:flutter/material.dart';

void main() {
  runApp(SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  List widgets = [];

  @override
  void initState() {
    super.initState();
    for (int i = 0; i < 100; i++) {
      widgets.add(getRow(i));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Sample App"),
        ),
        body: ListView.builder(
            itemCount: widgets.length,
            itemBuilder: (BuildContext context, int position) {
              return getRow(position);
            }));
  }

  Widget getRow(int i) {
    return GestureDetector(
      child: Padding(
          padding: EdgeInsets.all(10.0),
          child: Text("Row $i")),
      onTap: () {
        setState(() {
          widgets.add(getRow(widgets.length + 1));
          print('row $i');
        });
      },
    );
  }
}

不用创建一个“ListView”,而是创建接收两个参数的 ListView.Builder,两个参数分别是列表的初始长度和一个 ItemBuilder 方法。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

ItemBuilder 方法和 Android adapter 里的 getView 方法类似;它通过位置返回你期望在这个位置渲染的列表项。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

最后也是最重要的一条,需要注意 onTap() 方法不再重建列表项,但是会执行 .add 操作。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

十、文字处理文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

10.1 如何为 Text Widget 设置自定义字体?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Android SDK 中(从 Android O 开始),你可以创建一个字体资源文件并将其传给 TextView 的 FontFamily 参数。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Flutter 中,将字体文件放入一个文件夹,并在 pubspec.yaml 文件中引用它,就和导入图片一样。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

fonts:
   - family: MyCustomFont
     fonts:
       - asset: fonts/MyCustomFont.ttf
       - style: italic

然后将字体赋值给你的 Text Widget:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text("Sample App"),
    ),
    body: Center(
      child: Text(
        'This is a custom font text',
        style: TextStyle(fontFamily: 'MyCustomFont'),
      ),
    ),
  );
}

10.2 如何更改 Text Widget 的样式?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

除了字体,你还可以自定义 Text Widget 的其它样式元素。Text Widget 的样式参数接收一个 TextStyle 对象,你可以在这个对象里自定义很多参数,例如:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

  • color
  • decoration
  • decorationColor
  • decorationStyle
  • fontFamily
  • fontSize
  • fontStyle
  • fontWeight
  • hashCode
  • height
  • inherit
  • letterSpacing
  • textBaseline
  • wordSpacing

十一、表单输入文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

如果需要更多使用表单的信息,请查看 Flutter Cookbook 中的检索一个文本字段的值。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

11.1 Input 的“提示”(“hint”)的对应概念是什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Flutter 中,你可以简单地通过向 Text Widget 构造器的 decoration 参数传入一个 InputDecoration 对象来为输入框展示一个“提示”或占位文本。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

body: Center(
  child: TextField(
    decoration: InputDecoration(hintText: "This is a hint"),
  )
)

11.2 如何显示验证错误的信息?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

就像上面实现“提示”功能一样,像 Text Widget 构造方法的 decoration 参数传入一个 InputDecoration 对象。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

然而,你并不想一开始就显示错误信息。相反,当用户输入了无效的信息后,更新状态并传入一个新的 InputDecoration 对象。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

import 'package:flutter/material.dart';

void main() {
  runApp(SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  String _errorText;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Sample App"),
      ),
      body: Center(
        child: TextField(
          onSubmitted: (String text) {
            setState(() {
              if (!isEmail(text)) {
                _errorText = 'Error: This is not an email';
              } else {
                _errorText = null;
              }
            });
          },
          decoration: InputDecoration(hintText: "This is a hint", errorText: _getErrorText()),
        ),
      ),
    );
  }

  _getErrorText() {
    return _errorText;
  }

  bool isEmail(String em) {
    String emailRegexp =
        r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';

    RegExp regExp = RegExp(emailRegexp);

    return regExp.hasMatch(em);
  }
}

十二、Flutter 插件文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

12.1 如何使用 GPS 传感器?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

使用 geolocator 社区插件。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

12.2 如何使用相机?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

image_picker 插件被常用于相机功能的使用。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

12.3 如何使用 Facebook 登录?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

使用 flutter_facebook_login 社区插件实现 Facebook 登录功能。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

12.4 如何使用 Firebase 的功能?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

官方插件提供了 Firebase 的大多数功能。这些插件都是由 Flutter 团队维护的官方集成插件:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

  • firebase_admob 提供 Firebase AdMob 功能
  • firebase_analytics 提供 Firebase Analytics 功能
  • firebase_auth 提供 Firebase Auth 功能
  • firebase_database 提供 Firebase RTDB 功能
  • firebase_storage 提供 Firebase Cloud Storage 功能
  • firebase_messaging 提供 Firebase Messaging (FCM) 功能
  • flutter_firebase_ui 提供快速的 Firebase Auth 集成功能 (Facebook, Google, Twitter 和 email)
  • cloud_firestore 提供 Firebase Cloud Firestore 功能

你可以在 Pub(https://pub.dev/flutter) 网站上查找一些官方插件没有直接支持的功能的第三方 Firebase 插件。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

12.5 如何创建自己的自定义原生集成插件?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

如果有 Flutter 官方或社区第三方插件没有涵盖的平台特定的功能,你可以根据开发包和插件页面创建自己的插件。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

Flutter 的插件架构,简而言之,和 Android 中的事件总线的使用非常相似:你发送一个消息,并让接受者处理并返回一个结果给你。在这种情况下,接受者是运行在 Android 或 iOS 原生端的代码。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

12.6 如何在 Flutter 应用中使用 NDK?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

如果你在现有的 Android 应用中使用 NDK,并且希望你的 Flutter 应用可以利用你的 native 库,这可以通过创建一个自定义插件实现。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

你的自定义插件首先和你的 Android 应用通信,Android 应用会通过 JNI 调用 native 方法。一旦有返回值,就可以向 Flutter 发送回一个消息并渲染结果。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

暂时还不支持从 Flutter 中直接调用 native 代码。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

十三、主题文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

13.1 如何对应用使用主题?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

Flutter 提供开箱即用的优美的 Material Design 实现,可以满足你通常需要的各种样式和主题的需求。不同于 Android 中你在 XML 文件中定义主题并在 AndroidManifest.xml 中将其赋值给你的应用, Flutter 中是在顶层 Widget 上声明主题。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

为了在应用中利用好 Material 组件,你可以在应用中声明一个顶层 Widget MeterialApp 作为入口。 MaterialApp 是一个包装了一系列 Widget 的为你给予便利的 Widget,而这些 Widget 通常是实现 Material Design 的应用所必须的。它基于 WidgetsApp 并添加了 Material 相关的功能。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

你也可以使用 WidgetApp 作为应用的 Widget,它会提供一些相同的功能,但是不如 MaterialApp 提供的功能丰富。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

如果要自定义任意子组件的颜色或者样式,给 MaterialApp Widget 传入一个 ThemeData 对象即可。例如,在下面的代码中,主色调设置为蓝色,文本选中颜色设置为红色。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Sample App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        textSelectionColor: Colors.red
      ),
      home: SampleAppPage(),
    );
  }
}

十四、数据库和本地存储文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

14.1 如何使用 Shared Preferences?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Android 中,你可以使用 SharedPreferences API 来存储少量的键值对。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Flutter 中,使用 Shared_Preferences 插件实现此功能。这个插件同时包装了 Shared Preferences 和 NSUserDefaults(iOS 平台对应 API)的功能。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        body: Center(
          child: RaisedButton(
            onPressed: _incrementCounter,
            child: Text('Increment Counter'),
          ),
        ),
      ),
    ),
  );
}

_incrementCounter() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  int counter = (prefs.getInt('counter') ?? 0) + 1;
  print('Pressed $counter times.');
  prefs.setInt('counter', counter);
}

14.2 在 Flutter 中如何使用 SQLite?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Android 中,你会使用 SQLite 来存储可以通过 SQL 进行查询的结构化数据。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Flutter 中,使用 SQFlite 插件实现此功能。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

十五、通知文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

15.1 如何设置推送通知?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Android 中,你会使用 Firebase Cloud Messaging 来为应用设置推送通知。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

在 Flutter 中,则使用 Firebase_Messaging 插件实现此功能。想要获得更多关于使用 Firebase Cloud Messaging API 的信息,请查阅 firebase_messaging 插件文档。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/xcx/13682.html

  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/xcx/13682.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定