Flutter MVC架构插件flutter_mvc的使用
Flutter MVC架构插件flutter_mvc的使用
在本教程中,我们将介绍如何使用flutter_mvc
插件来实现Flutter应用中的MVC(Model-View-Controller)架构。通过以下步骤,您可以快速上手并掌握flutter_mvc
的基本用法。
快速开始
使用MVC
首先,我们需要创建model
、view
和controller
类。
// 定义Model类
class HomeModel {
const HomeModel(this.title);
final String title;
}
// 定义Controller类
class HomeController extends MvcController<HomeModel> {
[@override](/user/override)
MvcView<HomeController> view() => HomeView();
}
// 定义View类
class HomeView extends MvcView<HomeController> {
[@override](/user/override)
Widget buildView() {
return Center(
child: Text(controller.model.title),
);
}
}
然后,我们可以在Flutter应用中使用Mvc
组件来实例化和展示这些类。
// 在Flutter应用中使用Mvc
Mvc(
create: () => HomeController(),
model: const HomeModel('Flutter Mvc Demo'),
)
这将显示文本Flutter Mvc Demo
。
更新MVC
如果您需要更新Model
,可以这样操作:
class _MyHomePageState extends State<MyHomePage> {
String title = 'Flutter Mvc Demo';
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
body: Mvc(
create: () => HomeController(),
model: HomeModel(title),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
title = 'Flutter Mvc Demo Updated';
});
},
tooltip: 'Update Title',
child: const Icon(Icons.add),
),
);
}
}
点击按钮后,HomeModel
的title
将被更新,并且HomeView
也会随之更新。
控制器生命周期
Controller
的生命周期与StatefulWidget
中的State
生命周期一致。您可以通过重写一些方法来处理这些生命周期事件:
class HomeController extends MvcController<HomeModel> {
[@override](/user/override)
void init() {
super.init();
}
[@override](/user/override)
void didUpdateModel(HomeModel oldModel) {
super.didUpdateModel(oldModel);
}
[@override](/user/override)
void activate() {
super.activate();
}
[@override](/user/override)
void deactivate() {
super.deactivate();
}
[@override](/user/override)
void dispose() {
super.dispose();
}
[@override](/user/override)
MvcView<MvcController> view() => HomeView();
}
更新Widget
更新MvcView
通过调用update()
方法,您可以更新整个MvcView
。
class HomeController extends MvcController {
String title = "Default Title";
void tapUpdate() {
title = "Title Updated";
update();
}
[@override](/user/override)
MvcView<MvcController> view() => HomeView();
}
class HomeView extends MvcView<HomeController> {
[@override](/user/override)
Widget buildView() {
return Scaffold(
body: Center(
child: Text(controller.title),
),
floatingActionButton: FloatingActionButton(
onPressed: controller.tapUpdate,
tooltip: 'Update Title',
child: const Icon(Icons.add),
),
);
}
}
使用Widget类型更新特定Widget
class HomeController extends MvcController {
String title = "Default Title";
String body = "Default Body";
void tapUpdate() {
title = "Title Updated";
body = "Body Updated";
querySelectorAll<MvcHeader>().update(); // 更新所有MvcHeader,或者使用querySelectorAll("MvcHeader").update();
querySelectorAll("MvcBody,MvcHeader").update(); // 更新所有MvcBody和MvcHeader
}
[@override](/user/override)
MvcView<MvcController> view() => HomeView();
}
class HomeView extends MvcView<HomeController> {
[@override](/user/override)
Widget buildView() {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MvcHeader(
builder: (_) => Text(controller.title),
),
MvcBody(
builder: (_) => Text(controller.body),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: controller.tapUpdate,
tooltip: 'Update',
child: const Icon(Icons.add),
),
);
}
}
只有继承自MvcStatelessWidget
或MvcStatefulWidget
的Widget才能使用这种方式更新。
使用id、类、属性更新特定Widget
class HomeController extends MvcController {
String title = "Default Title";
void tapUpdateById() {
querySelectorAll('#title_id').update(() => title = "Title Updated By Id");
}
void tapUpdateByClass() {
querySelectorAll('.title_class').update(() => title = "Title Updated By Class");
}
void tapUpdateByAttribute() {
querySelectorAll('[data-title]').update(() => title = "Title Updated By Attribute");
}
[@override](/user/override)
MvcView<MvcController> view() => HomeView();
}
class HomeView extends MvcView<HomeController> {
[@override](/user/override)
Widget buildView() {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MvcBuilder(
id: "title_id",
classes: const ["title_class"],
attributes: const {"data-title": "title"},
builder: (_) {
return Text(controller.title);
},
),
TextButton(
onPressed: controller.tapUpdateById,
child: const Text("Update By Id"),
),
TextButton(
onPressed: controller.tapUpdateByClass,
child: const Text("Update By Class"),
),
TextButton(
onPressed: controller.tapUpdateByAttribute,
child: const Text("Update By Attribute"),
),
],
),
);
}
}
querySelectorAll
遵循W3C选择器规则。它可用于同时更新符合规则的多个Widget,但不支持兄弟选择器。
依赖注入
依赖注入是flutter_mvc
的核心功能之一。您只需提供对象类型及其创建方法,框架会在需要时自动创建并提供该对象。它提供了三种不同的生命周期模式:单例模式、瞬态模式和范围模式。
概述
- 单例模式:对象仅创建一次,后续获取时返回相同的对象。
- 瞬态模式:每次获取时都会创建一个新对象。
- 范围模式:每次获取时都会创建一个新对象,但在同一范围内获取的对象是相同的。
在flutter_mvc
中,每个从MvcStatefulWidget
和MvcStatelessWidget
扩展的Widget都是一个新的范围,包括Mvc
、MvcBuilder
、MvcHeader
、MvcBody
等。
MvcDependencyProvider(
provider: (collection) {
collection.addSingleton<TestService1>((_) => TestService1());
collection.add<TestService2>((_) => TestService2());
collection.addScopedSingleton<TestService3>((serviceProvider) => TestService3());
},
child: Mvc(create: () => HomeController()),
)
获取对象
当获取对象时,您可以获取当前范围及其所有父范围中注入的对象。
class HomeController extends MvcController {
[@override](/user/override)
void init() {
super.init();
final TestService1 service1 = getService<TestService1>();
final TestService2 service2 = getService<TestService2>();
final TestService3 service3 = getService<TestService3>();
}
[@override](/user/override)
MvcView<MvcController> view() => HomeView();
}
class HomeView extends MvcView<HomeController> {
[@override](/user/override)
Widget buildView() {
final TestService1 service1 = getService<TestService1>();
final TestService2 service2 = getService<TestService2>();
final TestService3 service3 = getService<TestService3>();
return Scaffold(
body: Center(
child: MvcBuilder(
builder: (context) {
final TestService1 service1 = context.getService<TestService1>();
final TestService2 service2 = context.getService<TestService2>();
final TestService3 service3 = context.getService<TestService3>();
return const Text("Hello, World!");
},
),
),
);
}
}
使用依赖注入对象更新Widget
如果注入的对象实现了MvcService
接口,您可以使用一些方法来更新Widget。
class TestService with DependencyInjectionService, MvcService {
String title = "title";
void test() {
update(() => title = "new title");
}
}
MvcDependencyProvider(
provider: (collection) {
collection.addSingleton<TestService>((_) => TestService());
},
child: Scaffold(
body: MvcServiceScope<TestService>(
builder: (MvcContext context, TestService service) {
return Text(service.title);
},
),
floatingActionButton: Builder(
builder: (context) {
return FloatingActionButton(
onPressed: () {
context.getMvcService<TestService>().test();
},
child: const Icon(Icons.add),
);
},
),
),
)
点击按钮将更新Text
的内容。
完整示例Demo
import 'dart:async';
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mvc/flutter_mvc.dart';
void main() {
runApp(
MvcDependencyProvider(
provider: (collection) {
collection.addSingleton<TestService>((_) => TestService());
},
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: Mvc(
create: () => TestMvcController(),
model: const TestModel("Flutter Mvc Demo"),
),
);
}
}
/// The dependency injection service
class TestService with DependencyInjectionService, MvcService {
String title = "Default Title";
void changeTitle() {
title = "Service Changed Title";
update();
}
}
/// The Model
class TestModel {
const TestModel(this.title);
final String title;
}
/// The Controller
class TestMvcController extends MvcController<TestModel> {
int count = 0;
int timerCount = 0;
late Timer timer;
[@override](/user/override)
void init() {
super.init();
timer = Timer.periodic(const Duration(seconds: 1), timerCallback);
}
[@override](/user/override)
MvcView view() => TestMvcView();
[@override](/user/override)
void dispose() {
super.dispose();
timer.cancel();
}
/// timer callback
void timerCallback(Timer timer) {
// update the widget with classes "timerCount"
querySelectorAll(".timerCount").update(() => timerCount++);
}
/// click the FloatingActionButton
void tapAdd() {
count++;
// update the widget with id "count"
querySelectorAll("#count").update();
}
/// click the "update title by controller"
void changeTestServiceTitle() {
// get TestService and set title
getService<TestService>().title = "Controller Changed Title";
// update The TestService, will be update all MvcServiceScope<TestService>
getService<TestService>().update();
}
}
/// The View
class TestMvcView extends MvcView<TestMvcController> {
[@override](/user/override)
Widget buildView() {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(controller.model.title),
),
body: Column(
children: [
MvcHeader(
builder: (context) {
return Container(
height: 44,
color: Color(
Random().nextInt(0xffffffff),
),
);
},
),
Expanded(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MvcServiceScope<TestService>(
builder: (context, service) {
return Text(service.title);
},
),
MvcBuilder(
classes: const ["timerCount"],
builder: (context) {
return Text(
'${controller.timerCount}',
style: Theme.of(context).textTheme.headlineMedium,
);
},
),
MvcBuilder(
id: "count",
builder: (context) {
return Text(
'${controller.count}',
style: Theme.of(context).textTheme.headlineMedium,
);
},
),
CupertinoButton(
onPressed: controller.changeTestServiceTitle,
child: const Text("update title by controller"),
),
CupertinoButton(
onPressed: () => getService<TestService>().changeTitle(),
child: const Text("update title by self service"),
),
CupertinoButton(
onPressed: () => controller.querySelectorAll<MvcHeader>().update(),
child: const Text("update header"),
),
CupertinoButton(
onPressed: () => controller.querySelectorAll<MvcFooter>().update(),
child: const Text("update footer"),
),
],
),
),
),
MvcFooter(
builder: (context) {
return Container(
height: 44,
color: Color(
Random().nextInt(0xffffffff),
),
);
},
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: controller.tapAdd,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
更多关于Flutter MVC架构插件flutter_mvc的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter MVC架构插件flutter_mvc的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
flutter_mvc
是一个基于 Flutter 的 MVC(Model-View-Controller)架构插件,它帮助开发者更好地组织和管理 Flutter 应用中的代码。通过将应用程序的逻辑、数据和界面分离,flutter_mvc
使得代码更加模块化、易于维护和扩展。
安装 flutter_mvc
插件
首先,你需要在 pubspec.yaml
文件中添加 flutter_mvc
依赖:
dependencies:
flutter:
sdk: flutter
flutter_mvc: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
使用 flutter_mvc
插件
1. 创建 Model
Model 负责管理应用程序的数据和业务逻辑。你可以创建一个继承自 MvcModel
的类。
import 'package:flutter_mvc/flutter_mvc.dart';
class CounterModel extends MvcModel {
int count = 0;
void increment() {
count++;
notifyListeners(); // 通知 View 更新
}
}
2. 创建 Controller
Controller 负责处理用户交互和业务逻辑。你可以创建一个继承自 MvcController
的类,并在其中引用 Model。
import 'package:flutter_mvc/flutter_mvc.dart';
class CounterController extends MvcController<CounterModel> {
CounterController() : super(CounterModel());
void incrementCounter() {
model.increment();
}
}
3. 创建 View
View 负责展示数据和处理用户交互。你可以使用 MvcView
来绑定 Controller 和 Model。
import 'package:flutter/material.dart';
import 'package:flutter_mvc/flutter_mvc.dart';
class CounterView extends MvcView<CounterController, CounterModel> {
CounterView() : super(CounterController());
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Counter App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Count:',
),
Text(
'${model.count}',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: controller.incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
4. 运行应用
最后,在你的 main.dart
文件中运行应用:
import 'package:flutter/material.dart';
import 'counter_view.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter MVC Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: CounterView(),
);
}
}