Flutter布局约束插件cassowary的使用
Flutter布局约束插件cassowary的使用
Cassowary in Dart
Cassowary是Dart中实现的Cassowary约束求解算法。最初的实现基于用C++编写的Kiwi toolkit。它实现了Cassowary论文中描述的功能子集,并为Flutter的需求做出了特定的调整。
The Solver
求解器(Solver)是接受约束并尝试更新成员变量以满足这些约束的对象。
Parameters
为了创建约束,用户需要从视图层次结构中的元素获取特定的参数对象,并从中创建表达式。然后可以从这些表达式中获得约束。如果求解器需要更新这些参数以满足约束,它将调用这些参数上的回调函数。
Constructing Constraints
约束是以ax + by + cz + ... + k == 0
形式的线性方程。约束不必是等式关系,也可以指定小于或大于等于(<=
或 >=
)的关系。此外,每个约束都指定了一个优先级以帮助解决约束歧义。系统也可能被过度约束。
约束作为一个整体由Constraint
对象的实例表示。这反过来又引用了一个Expression
(ax + by + cz + ... k
)、关系和最终的优先级。
每个表达式由一个Term
列表和一个常数组成。项ax
具有系数a
和变量x
。提供给用户的Param
只是这个变量的包装器,负责检测其变化并更新层次结构中的底层视图。
以下示例设置了一个约束,指定元素的宽度必须至少为100个单位。假设已经从相关视图中获取了left
和right
这两个Param
对象。
var widthAtLeast100 = right - left >= cm(100.0);
让我们一步一步地解释:表达式right - left
创建了一个Expression
对象的实例。该表达式由两个项组成。right
和left
参数包装变量。它们的系数分别为1.0和-1.0,常数为-100.0。常数需要用CM
装饰以辅助Dart的操作符重载机制。
所有变量都是不受限制的。因此,没有什么可以阻止求解器使左右边缘变为负值。我们可以通过指定另一个约束来表达我们对这种情况的偏好:
var edgesPositive = (left >= cm(0.0));
当我们构建这些约束时,默认情况下它们是在Priority.required
下创建的。这意味着求解器将抵制添加在两个必需约束之间存在歧义的约束。要指定较低的优先级,可以使用priority
设置器或在构造约束时使用|
符号与优先级一起使用。例如:
var edgesPositive = (left >= cm(0.0))..priority = Priority.weak;
一旦构建了一组约束,它们就被添加到求解器中,并刷新解决方案的结果。
solver
..addConstraints([widthAtLeast100, edgesPositive])
..flushUpdates();
Edit Constraints
当需要更新作为求解器一部分的参数时,可以使用编辑变量。通过以下示例说明这一点:在鼠标按下时,我们希望更新视图的中点,并让left
和right
参数自动更新(受已设置的约束影响)。
我们创建一个参数来表示鼠标坐标。
var mid = Variable(coordinate);
然后,我们添加一个约束,用我们已经拥有的参数表达中点。
solver.addConstraint((left + right).equals(Term(mid, 1.0) * cm(2.0)));
然后,我们指定我们打算编辑中点。随着更新的发生,我们告诉求解器满足所有其他约束(尽管我们的示例非常简单)。
solver.addEditVariable(mid, Priority.strong);
最后
solver.flushUpdates();
示例代码
以下是一个完整的示例代码,展示了如何使用Cassowary插件进行布局约束:
import 'package:cassowary/cassowary.dart';
void main() {
final solver = Solver();
final left = Param(10);
final right = Param(20);
final widthAtLeast100 = right - left >= cm(100);
final edgesPositive = (left >= cm(0))..priority = Priority.weak;
solver
..addConstraints([widthAtLeast100, edgesPositive])
..flushUpdates();
print('left: ${left.value}, right: ${right.value}');
final mid = Variable(15);
// It appears that == isn't defined
solver
..addConstraint((left + right).equals(Term(mid, 1) * cm(2)))
..addEditVariable(mid, Priority.strong)
..flushUpdates();
print('left: ${left.value}, mid: ${mid.value}, right: ${right.value}');
}
通过以上内容,您可以了解如何在Flutter项目中使用Cassowary插件来进行布局约束管理。根据实际需求,您可以进一步扩展和调整约束条件,以实现更复杂和灵活的布局效果。
更多关于Flutter布局约束插件cassowary的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter布局约束插件cassowary的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,cassowary
是一个用于处理布局约束的库,它允许开发者以类似于 Auto Layout(在 iOS 开发中使用)的方式来定义复杂的布局。虽然 Flutter 原生已经提供了强大的布局系统(如 Column
、Row
、Stack
等),但 cassowary
可以为需要更高级约束控制的场景提供额外的灵活性。
以下是一个使用 cassowary
插件的基本示例。请注意,由于 cassowary
在 Flutter 社区中可能不是一个广为人知的库(相对于 Flutter 自带的布局系统),并且库的 API 和可用性可能会随时间变化,因此以下代码可能需要根据实际的 cassowary
版本进行调整。
首先,确保你已经在 pubspec.yaml
文件中添加了 cassowary
依赖:
dependencies:
flutter:
sdk: flutter
cassowary: ^x.y.z # 替换为最新版本号
然后,运行 flutter pub get
来安装依赖。
下面是一个使用 cassowary
插件的示例代码:
import 'package:flutter/material.dart';
import 'package:cassowary/cassowary.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Cassowary Layout Example'),
),
body: CustomLayoutWidget(),
),
);
}
}
class CustomLayoutWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 创建约束求解器
final solver = Solver();
// 创建变量(代表每个子控件的宽度、高度和位置)
final topViewHeight = Variable();
final topViewWidth = Variable();
final topViewX = Variable();
final topViewY = Variable();
final bottomViewHeight = Variable();
final bottomViewWidth = Variable();
final bottomViewX = Variable();
final bottomViewY = Variable();
// 添加约束
solver.addConstraint(topViewHeight == 100);
solver.addConstraint(topViewWidth == 300);
solver.addConstraint(topViewX == 0);
solver.addConstraint(topViewY == 0);
solver.addConstraint(bottomViewHeight == 100);
solver.addConstraint(bottomViewWidth == 300);
solver.addConstraint(bottomViewX == 0);
solver.addConstraint(bottomViewY == topViewY + topViewHeight + 20); // 底部视图位于顶部视图下方20单位
// 更新变量值
solver.updateVariables();
// 获取最终的布局值
final topViewSize = Size(topViewWidth.value, topViewHeight.value);
final topViewPosition = Offset(topViewX.value, topViewY.value);
final bottomViewSize = Size(bottomViewWidth.value, bottomViewHeight.value);
final bottomViewPosition = Offset(bottomViewX.value, bottomViewY.value);
return Stack(
children: [
Positioned(
left: topViewPosition.dx,
top: topViewPosition.dy,
width: topViewSize.width,
height: topViewSize.height,
child: Container(
color: Colors.red,
child: Center(child: Text('Top View')),
),
),
Positioned(
left: bottomViewPosition.dx,
top: bottomViewPosition.dy,
width: bottomViewSize.width,
height: bottomViewSize.height,
child: Container(
color: Colors.blue,
child: Center(child: Text('Bottom View')),
),
),
],
);
}
}
在这个示例中,我们创建了两个视图(顶部视图和底部视图),并使用 cassowary
来定义它们的布局约束。这些约束包括视图的尺寸和位置。然后,我们通过 solver.updateVariables()
更新变量的值,并在 Flutter 的布局系统中使用这些值来定位视图。
请注意,这个示例假设 cassowary
插件提供了 Solver
、Variable
等类和方法。如果 cassowary
的 API 有所变化,或者如果你发现这个库不再维护或推荐使用,请查阅最新的文档或寻找替代方案。