Flutter动态功能插件dynamic的使用
Flutter动态功能插件dynamic的使用
动态功能插件dynamic
dynamic
: 远程UI客户端插件,用于Flutter。
什么是远程UI?
什么是“远程UI”?为什么和什么时候使用它?
远程UI是一种跨平台的UI结构标准,因此你可以以更一致、更完整、更易于维护的方式进行开发。
远程UI的关键特性:
- 实时反映UI。
- 一次编写,跨所有平台运行(使用你最喜欢的框架)。
- 所有数据和逻辑都在服务器端。只发送UI数据。
- 逻辑集中化。代码更少,更容易维护。
- 原生性能。(不会影响性能)
远程UI的核心概念
几乎所有应用都会遵循以下步骤:
- 应用定义(业务设计)。我们要做什么?为谁做?
- 模型定义(数据模式设计)。我们需要获取哪些数据?我们应该向用户提供哪些数据?
- UI设计(实际界面设计)。我们如何在屏幕上显示数据?表单将是什么样子?
远程UI是否适合所有人?
不是。 你不需要使用远程UI来制作你的应用。
由于我们的社区很小,你在开发生产级应用时可能会得到较少的支持和更多的麻烦。
它是如何工作的?
让我们通过一个名为“foodle”的食物卡车应用来了解其内部工作原理。
该框架由三层组成:
- 数据层(存储裸数据的数据层。可以想象为数据库)
- 布局数据层(将裸数据映射到视图的布局数据)
- 视图层(绘制布局数据的UI)
数据
var truckData = TruckData(
name: "gony's burger",
image: "https://~.jpg",
shortDescription: "since 1999");
小部件与布局
注意:由于Flutter的小部件命名与远程UI的小部件命名相同,我们选择使用前缀标记“X”。例如,XText
是远程UI的文本实例。
var truckItemLayout = (TruckData data) => TruckItemLayout(
body: TruckItemBody(
title: RU.Text(data.name),
description: RU.Text(data.shortDescription),
image: RU.Image(data.image),
onTap: RU.Action(null)));
视图
var titleText = (BuildContext context, RU.Text text) => Text(
text.content,
style: Theme.of(context).textTheme.body2,
);
var descriptionText = (BuildContext context, RU.Text text) => Text(
text.content,
style: Theme.of(context).textTheme.overline,
);
var coverImage = (RU.Image image) => Image.network(
image.src,
height: 100.0,
width: 140.0,
fit: BoxFit.cover,
);
Function onTapAction = (RU.Action action) => {
action.handle();
}
var truckItemView =
(BuildContext context, TruckItemLayout layout) => GestureDetector(
onTap: onTapAction(layout.body.onTap),
child: Container(
padding: EdgeInsets.only(left: 8, right: 8, top: 16, bottom: 16),
width: 150,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
new ClipRRect(
borderRadius: new BorderRadius.circular(2.0),
child: coverImage(layout.body.image)
),
titleText(context, layout.body.title),
descriptionText(context, layout.body.description),
],
),
));
通过这种方式,你可以动态改变卡片中显示的内容,甚至可以在不更新应用的情况下更改卡片类型。你可以决定当卡片被点击时触发哪个动作。
理论上,如果所有场景都被预先定义好,你将永远不需要更新你的应用来进行应用更新。这将通过更改UI配置来神奇地实现。
如何贡献
该项目仍在开发中,尚未达到测试版状态。
如果你喜欢这个概念,并且喜欢我们正在尝试实现的目标,请随时联系我们进行贡献。
©2020 bridged XYZ. 开发自2019年9月
示例代码
以下是使用dynamic
插件的完整示例代码:
import 'package:flutter/material.dart';
import 'package:flutter_remote_ui_example/screen/demo/action/action_demo_screen.dart';
import 'package:flutter_remote_ui_example/screen/demo/foodle/foodle.dart';
import 'package:flutter_remote_ui_example/screen/demo/search_example/search_screen.dart';
import 'package:flutter_remote_ui_example/screen/demo/stile/stile_demo.dart';
import 'package:flutter_remote_ui_example/screen/demo/timeline/timeline_demo_screen.dart';
import 'package:flutter_remote_ui_example/screen/wallet_screen.dart';
import 'package:flutter_remote_ui_example/screen/demo/youtube/youtube.dart';
import 'package:flutter_remote_ui_example/utils/routes.dart';
import 'screen/icons_demo/icons_demo_screen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// 这个小部件是你的应用程序的根。
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'remote-ui',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: DemoHomePage.routeName,
routes: buildRoute(context),
);
}
}
const List<DemoData> demos = [
const DemoData(title: "remote icons", route: IconsDemoScreen.routeName),
const DemoData(
title: "Foodle",
route: Foodle.routeName,
cover: 'https://blog.luz.vc/wp-content/uploads/2019/01/food-truck-ou-food-container-2-696x356.jpg'),
const DemoData(
title: "Wallet",
route: WalletDemo.routeName,
cover: "https://www.loveworldplus.tv/wp-content/uploads/2019/04/bank.jpg"),
const DemoData(
title: "Youtube",
route: YoutubeDemo.routeName,
cover: "https://marketingland.com/wp-content/ml-loads/2017/08/youtube-logo-1920-800x450.jpg"),
const DemoData(title: "Stile", route: StileDemo.routeName),
const DemoData(title: "Timeline", route: TimelineDemoScreen.routeName),
const DemoData(title: "Search results", route: SearchScreen.routeName),
const DemoData(title: "Actions", route: ActionDemoScreen.routeName),
];
class DemoHomePage extends StatefulWidget {
static const routeName = "/home";
[@override](/user/override)
_DemoHomePageState createState() => _DemoHomePageState();
}
class _DemoHomePageState extends State<DemoHomePage> {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("select demo"),
),
body: SingleChildScrollView(
child: Column(
children: [demoListBuilder()],
),
));
}
Widget demoListBuilder() {
return ListView.builder(
itemBuilder: (c, i) {
var demo = demos[i];
return DemoRow(
title: Text(demo.title),
cover: demo.cover != null
? Image.network(
demo.cover,
width: double.maxFinite,
fit: BoxFit.fitWidth,
)
: null,
onTap: () {
Navigator.of(context).pushNamed(demo.route);
},
);
},
itemCount: demos.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
);
}
}
class DemoData {
final String cover;
final String title;
final String route;
const DemoData({this.cover, [@required](/user/required) this.title, [@required](/user/required) this.route});
}
class DemoRow extends StatelessWidget {
final Function onTap;
final Widget title;
final Widget cover;
const DemoRow({Key key, this.onTap, this.title, this.cover}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
width: double.maxFinite,
height: 200,
child: Stack(
children: [
this.cover != null
? this.cover
: Container(
color: Colors.blueAccent,
),
Positioned(left: 24, bottom: 24, child: _title(context))
],
),
));
}
Widget _title(BuildContext context) {
return DefaultTextStyle(
child: this.title,
style: Theme.of(context).textTheme.headline2.copyWith(color: Colors.white),
);
}
}
更多关于Flutter动态功能插件dynamic的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter动态功能插件dynamic的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,动态功能插件(dynamic features)通常涉及将应用拆分为多个模块(modules),以便按需加载这些模块,从而提高应用的性能和用户体验。虽然Flutter本身并没有直接提供名为“dynamic”的官方插件,但你可以通过Flutter的模块化和插件系统来实现动态加载功能。
以下是一个基本的示例,展示如何在Flutter应用中创建和使用动态模块。
步骤 1: 创建主应用
首先,创建一个新的Flutter项目作为主应用。
flutter create main_app
cd main_app
步骤 2: 创建动态模块
在main_app
项目目录中,使用以下命令创建一个新的Flutter模块,这将作为你的动态模块。
flutter create -t module dynamic_feature
这将在main_app
项目目录中创建一个名为dynamic_feature
的子目录,其中包含你的动态模块代码。
步骤 3: 配置动态模块
在dynamic_feature
模块的pubspec.yaml
中,你可以定义该模块所需的依赖项。例如:
name: dynamic_feature
description: A new Flutter module.
version: 1.0.0+1
environment:
sdk: ">=2.12.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
# Add any other dependencies your module needs
步骤 4: 实现动态模块功能
在dynamic_feature/lib/main.dart
中,你可以定义该模块提供的功能。例如,一个简单的屏幕:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Dynamic Feature Module'),
),
body: Center(
child: Text('Hello from the dynamic feature module!'),
),
),
);
}
}
步骤 5: 从主应用加载动态模块
在main_app
项目中,你需要使用flutter_engine
和platform_channels
等机制来加载和显示动态模块的内容。这通常涉及到一些平台特定的代码(如Android的Activity
和iOS的ViewController
),以及Flutter的插件系统。
由于直接展示完整的加载过程涉及较多代码和配置,这里提供一个简化的思路:
-
在Android/iOS平台上配置动态模块加载:你需要确保动态模块被正确打包到APK/IPA中,并且可以在运行时被加载。
-
使用Flutter的插件或通道与原生代码通信:从主应用发送命令到原生代码,要求加载动态模块,并在加载完成后显示其内容。
-
在Flutter中处理模块加载后的逻辑:使用
Navigator
或类似的机制将动态模块的内容嵌入到主应用的UI中。
示例代码(简化)
以下是一个简化的示例,展示如何在Flutter中通过平台通道请求加载动态模块(注意:这只是一个概念验证,实际实现会更复杂):
在main_app/lib/main.dart
中:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
static const platform = MethodChannel('com.example.dynamic_feature');
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Main App'),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
try {
await platform.invokeMethod('loadDynamicFeature');
// Handle success (e.g., navigate to the loaded feature)
} on PlatformException catch (e) {
// Handle error
print("Failed to load dynamic feature: '${e.message}'.");
}
},
child: Text('Load Dynamic Feature'),
),
),
),
);
}
}
在Android平台上(MainActivity.kt
或MainActivity.java
中),你需要实现loadDynamicFeature
方法,该方法负责加载并显示动态模块的内容。
由于篇幅限制,这里无法展示完整的Android和iOS实现代码,但你可以参考Flutter官方文档和社区资源来了解如何实现这些功能。
总结
虽然Flutter没有直接提供一个名为“dynamic”的插件来实现动态功能,但你可以通过模块化、平台通道和原生代码集成来实现类似的功能。上述示例提供了一个基本的框架,你可以在此基础上根据具体需求进行扩展和完善。