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/zh-hant/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

發表回復

登錄後才能評論