Scenic的多方面分析

随着移动互联网的发展,越来越多的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就是用于绘制的画布,我们在画布上绘制了一个白色的矩形,这个矩形的大小是100×100。

三、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开发者提供了一个高度定制的解决方案。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/257691.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-15 12:46
下一篇 2024-12-15 12:46

相关推荐

  • Python取较大值的多方面

    Python是一款流行的编程语言,广泛应用于数据分析、科学计算、Web开发等领域。作为一名全能开发工程师,了解Python的取较大值方法非常必要。本文将从多个方面对Python取较…

    编程 2025-04-27
  • OWASP-ZAP:多方面阐述

    一、概述 OWASP-ZAP(Zed Attack Proxy)是一个功能丰富的开放源代码渗透测试工具,可帮助开发人员和安全专业人员查找应用程序中的安全漏洞。它是一个基于Java的…

    编程 2025-04-25
  • Java中字符串根据逗号截取的多方面分析

    一、String的split()方法的使用 Java中对于字符串的截取操作,最常使用的是split()方法,这个方法可以根据给定的正则表达式将字符串切分成多个子串。在对基础类型或简…

    编程 2025-04-25
  • 定距数据的多方面阐述

    一、什么是定距数据? 定距数据是指数据之间的差距是有真实的、可比较的含义的数据类型。例如长度、时间等都属于定距数据。 在程序开发中,处理定距数据时需要考虑数值的大小、单位、精度等问…

    编程 2025-04-25
  • Lua 协程的多方面详解

    一、什么是 Lua 协程? Lua 协程是一种轻量级的线程,可以在运行时暂停和恢复执行。不同于操作系统级别的线程,Lua 协程不需要进行上下文切换,也不会占用过多的系统资源,因此它…

    编程 2025-04-24
  • Midjourney Logo的多方面阐述

    一、设计过程 Midjourney Logo的设计过程是一个旅程。我们受到大自然的启发,从木质和地球色的调色板开始。我们想要营造一种旅途的感觉,所以我们添加了箭头和圆形元素,以表示…

    编程 2025-04-24
  • Idea隐藏.idea文件的多方面探究

    一、隐藏.idea文件的意义 在使用Idea进行开发时,经常会听说隐藏.idea文件这一操作。实际上,这是为了保障项目的安全性和整洁性,避免.idea文件的意外泄露或者被其他IDE…

    编程 2025-04-24
  • 如何卸载torch——多方面详细阐述

    一、卸载torch的必要性 随着人工智能领域的不断发展,越来越多的深度学习框架被广泛应用,torch也是其中之一。然而,在使用torch过程中,我们也不可避免会遇到需要卸载的情况。…

    编程 2025-04-23
  • Unity地形的多方面技术详解

    一、创建和编辑地形 Unity提供了可视化界面方便我们快速创建和编辑地形。在创建地形时,首先需要添加Terrain组件,然后可以通过左侧Inspector面板中的工具来进行细节的调…

    编程 2025-04-23
  • 跳出while的多方面探讨

    一、break语句跳出while循环 在while循环的过程中,如果需要跳出循环,可以使用break语句。break语句可以直接退出当前的循环体,继续执行后面的代码。 while …

    编程 2025-04-23

发表回复

登录后才能评论