随着移动互联网的发展,越来越多的APP需要显示丰富的场景,这就需要我们有一种以高效、灵活为特点的界面框架,Scenic就是这样的一种框架。Scenic它是一种以OpenGL为基础的图形库,用于构建高效、灵活的用户接口。
一、Scenic的特点
1. 矢量渲染:Scenic使用OpenGL绘制2D图形,支持不同的变形和旋转,这使得图形很容易适应不同大小的屏幕。同时,Scenic支持基于路径的渲染技术,使开发者可以更轻松的绘制各种复杂的图形。
2. 丰富的图形元素:Scenic提供了各种常见的UI元素,如文本、图片、按钮、列表和滚动视图等,这些元素可供组合成丰富的用户界面。
3. 异步布局:Scenic支持异步布局,这意味着当界面使用布局时,布局的计算是在单独的线程中进行的,可以大大减少界面卡顿的情况。
4. 支持GPU加速:Scenic使用OpenGL,可以充分利用GPU的性能,提高性能,同时也可以减少CPU的工作量。
5. 高度可定制:Scenic允许开发者自定义UI元素以及界面样式,这使得开发者可以轻松构建适应各种需求的用户界面。
二、Scenic的基本用法
安装Scenic: Scenic可以使用Flutter的package manager进行安装,只需要输入以下命令即可:
flutter packages add scenic
创建Scenic Widget: Scenic的UI元素被封装为Widget,开发者可以轻松创建一个Scenic Widget:
class ScenicWidget extends StatelessWidget {
const ScenicWidget();
@override
Widget build(BuildContext context) {
return Scenic.custom(
sizeCallback: (size) {},
onPaint: (canvas) {},
);
}
}
在上面的代码中,我们创建了一个简单的Scenic Widget,并重写了build方法,返回一个Scenic.custom Widget。通过这个Widget,我们可以自定义画布大小以及视图绘制方法。
这个Widget现在什么也不显示,我们需要自定义视图的绘制方法,来让其显示出来:
return Scenic.custom(
sizeCallback: (size) {},
onPaint: (canvas) {
canvas.drawRect(
rect: Offset.zero & Size(100, 100),
style: Paint.Style.fill,
color: ScenicColor.fromHex('#FFFFFF'));
},
);
这里的canvas就是用于绘制的画布,我们在画布上绘制了一个白色的矩形,这个矩形的大小是100x100。
三、Scenic实现ListView
我们可以使用Scenic轻松地构建一个ListView,下面是一个简单的例子:
class CustomListViewItemWidget extends ScenicWidget {
const CustomListViewItemWidget(
this.index, {
this.color = 'FF0000',
});
final int index;
final String color;
@override
void onPaint(Canvas canvas) {
canvas.drawRect(
rect: Offset.zero & size,
style: Paint.Style.fill,
color: ScenicColor.fromHex('#$color'),
);
canvas.drawText(
text: 'Item $index',
position: Offset(16, size.height / 2 - 16),
textStyle: TextStyle(color: ScenicColor.fromHex('#FFFFFF')),
);
}
@override
get width => 320;
@override
get height => 64;
}
class CustomListViewWidget extends ScenicWidget {
const CustomListViewWidget();
@override
void sizeCallback(Size size) {
super.sizeCallback(size);
final width = size.width;
final height = size.height / CustomListViewItemWidget.height;
sizeCallback(Size(width, height));
}
@override
void onPaint(Canvas canvas) {
for (var i = 0; i < size.height / CustomListViewItemWidget.height; i++) {
canvas.drawRRect(
rect: Offset(0, i * CustomListViewItemWidget.height) &
Size(size.width, CustomListViewItemWidget.height),
radius: 4,
style: Paint.Style.fill,
color: ScenicColor.fromHex(
i.isEven ? '#F5F5F5' : '#FFFFFF',
),
);
canvas.save();
canvas.translate(0, i * CustomListViewItemWidget.height);
canvas.clipRRect(
rect: Offset.zero &
Size(size.width, CustomListViewItemWidget.height),
radius: 4);
CustomListViewItemWidget(i, color: i.isEven ? '0087FF' : 'FF0000')
..paint(canvas);
canvas.restore();
}
}
}
在上面的代码中,我们创建了两个Widget,CustomListViewItemWidget和CustomListViewWidget,分别用于显示ListView中每一个Item和整个ListView。CustomListViewItemWidget表示ListView的Item,我们在这里绘制了一个矩形和文本;CustomListViewWidget表示整个ListView,我们在这里使用onPaint方法绘制了多个CustomListViewItemWidget,然后每一个CustomListViewItemWidget都需要调用paint方法绘制到画布上。
四、Scenic实现表单
Scenic同样也非常适合用于实现表单,为开发者提供了很多便利和高度的灵活性。下面是一个简单的例子:
class ScenicFormWidget extends ScenicWidget {
const ScenicFormWidget();
@override
double get width => 240;
@override
double get height => 200;
final TextEditingController _nameController = TextEditingController();
void submit() {
print(_nameController.text);
}
@override
void onPaint(Canvas canvas) {
final inputWidth = width - 32;
final inputOffset = Offset(16, 32);
canvas.drawRect(
rect: Offset.zero & size,
style: Paint.Style.fill,
color: ScenicColor.fromHex('#FFFFFF'),
);
canvas.drawText(
text: 'Scenic Form',
position: Offset(width / 2 - 50, 16),
textStyle: TextStyle(
color: ScenicColor.fromHex('#000000'), fontSize: 18),
);
canvas.drawText(
text: 'Name',
position: inputOffset - Offset(0, 16),
textStyle: TextStyle(
color: ScenicColor.fromHex('#000000'),
fontSize: 14,
),
);
canvas.drawRect(
rect: Rect.fromLTWH(inputOffset.dx, inputOffset.dy, inputWidth, 32),
style: Paint.Style.stroke,
color: ScenicColor.fromHex('#000000'),
strokeWidth: 1,
);
canvas.drawText(
text: _nameController.text,
position: inputOffset,
textStyle: TextStyle(
color: ScenicColor.fromHex('#000000'),
fontSize: 14,
),
);
}
}
在上面的代码中,我们创建了一个ScenicFormWidget,这个Widget里面绘制了一个表单,包含一个输入框和一个提交按钮。在onPaint方法中,我们使用ScenicDraw来绘制各种UI元素,如文本、矩形、线条等。同时,我们为表单绑定了一个该Controller,使用submit方法来处理其提交事件。
五、Scenic实现动画
Scenic使用Flutter的Animation框架来支持动画,提供了ScenicAnimationBuilder Widget,可方便地创建动画并将其连接到UI元素:
class ScenicAnimationDemo extends StatefulWidget {
const ScenicAnimationDemo();
@override
State
createState() => _ScenicAnimationDemoState();
}
class _ScenicAnimationDemoState extends State
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation
_animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
);
_animation = Tween(begin: 0.0, end: 1.0).animate(_controller);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ScenicAnimationBuilder(
animation: _animation,
builder: (context, child, value) {
return Scenic.custom(
onPaint: (canvas) {
canvas.drawRect(
rect: Offset.zero & Size(100, 100),
style: Paint.Style.fill,
color: ScenicColor.fromHex('#000000').withOpacity(value),
);
},
);
},
);
}
}
在上面的代码中,我们使用ScenicAnimationBuilder Widget来创建动画,并使用ScenicDraw中的canvas.drawRect方法绘制一个黑色矩形。在动画执行过程中,我们修改矩形的透明度,将其从完全透明变为完全不透明。
总结
Scenic是一个轻量级的UI框架,其特点在于支持矢量渲染、异步布局、GPU加速、高度可定制等方面。Scenic可以轻易地创建各种丰富的用户界面,例如ListView、表单和动画等。同时,Scenic也与Flutter配合得非常好,为Flutter开发者提供了一个高度定制的解决方案。