[原創] 改善 Firemonkey Canvas 幾何繪圖質量問題(移動平臺)

說明:

  Fiiremonkey 的跨平臺能力,你們有目共睹(一碼同介面跨四平臺),惟獨移動平臺在幾何繪圖方面,質量始終不盡人意,我也曾試着去修正(如:修正曲線平滑問題),也曾找過第三方案(如:AggPas),但都不完美,我一直在想,移動平臺有這麼強的繪圖能力及質量(Android & iOS),若是能直接拿來用,不是很好?爲何 Firemonkey 要本身重寫?html

  目前網上許多針對此問題的改善方案,但多以控件形式,且需依各平臺的繪圖函數來繪圖,或僅提供固定的幾何圖形控件,若是能延用現有的 TCanvas.Draw????? 繪圖代碼,只要加入幾行代碼(或編譯開關),就能達到原生繪圖的效果,豈不是很理想,因而開是構想這種方案的可行性,最後證明是可行的。android

  要先說明的是,這裏提供的只是一種改善方案,而不是修正,最終仍是但願能受到 EMB 官方的關注,由官方來改進這個問題。ios

 

用法及效果:

FMX 的繪圖方法:git

procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var Rect, DesRect: TRectF;
begin
  Rect := PaintBox1.LocalRect;
  Canvas.Stroke.Thickness := 10;
  Canvas.Stroke.Kind := TBrushKind.Solid;
  Canvas.Stroke.Dash := TStrokeDash.DashDotDot;

  DesRect := Rect;
  InflateRect(DesRect, -(Canvas.Stroke.Thickness / 2), -(Canvas.Stroke.Thickness / 2)); // 線在區內
  Canvas.FillRect(DesRect, 30, 30, AllCorners, 1);
  Canvas.DrawRect(DesRect, 30, 30, AllCorners, 1);
end;
說明 Android iOS Windows macOS

上面的代碼,使用 FMX 繪圖方法github

(移動平臺是有問題的)app

下面的代碼,使用原生繪圖方法函數

(四個平臺所有相同了)spa

下面改爲原生繪圖方案,只要在原有絵圖代碼前後加入二行代碼(原繪圖代碼不用更動).net

{$i NativeDraw.inc}
uses FMX.Graphics.Native;

procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var Rect, DesRect: TRectF;
begin
  Rect := PaintBox1.LocalRect;
  Canvas.Stroke.Thickness := 10;
  Canvas.Stroke.Kind := TBrushKind.Solid;
  Canvas.Stroke.Dash := TStrokeDash.DashDotDot;

  {$IFDEF UseNativeDraw}Canvas.NativeDraw(Rect, procedure begin {$ENDIF} // 原生繪圖 by Aone

  DesRect := Rect;
  InflateRect(DesRect, -(Canvas.Stroke.Thickness / 2), -(Canvas.Stroke.Thickness / 2)); // 線在區內
  Canvas.FillRect(DesRect, 30, 30, AllCorners, 1);
  Canvas.DrawRect(DesRect, 30, 30, AllCorners, 1);

  {$IFDEF UseNativeDraw}end);{$ENDIF} // 原生繪圖 by Aone
end;

 

運做原理:

  • 它的運做原理很簡單,就是先配置一個原生的繪圖區域 Bitmap,再將幾何圖形畫在這個區域裏,最後將這個區域裏的內容,轉回 TBitmap,再顯示到 Canvas 裏
  • 利用 Delphi Pascal Helper 語言特性,針對 TCanvas 來作擴展,如此才能達到不改動原有的繪圖代碼
  • 目前這個做法,相同的繪圖代碼,能夠跨四個平臺:
    • Android, iOS:使用原生繪圖 TCanvasHelper 方法3d

    • Windows, masOS:使用原來 TCanvas 方法(這二個平臺原本就沒有質量問題,因此不用重寫)
  • 咱們沒法觸及 FMX 的最核心,只能利用這種 Bitmap 方式來變通,要知道這種方式可能帶來的問題(記憶體及效能),纔不致錯用

  • 注意:若是引用了 FMX.Graphics.Native 就必需使用下面的方式來寫繪圖代碼,不然請不要引用:
    {$i NativeDraw.inc}
    uses FMX.Graphics.Native;
    
    {$IFDEF UseNativeDraw}Canvas.NativeDraw(Rect, procedure begin {$ENDIF} // 原生繪圖 by Aone
    
    // 繪圖代碼
    
    {$IFDEF UseNativeDraw}end);{$ENDIF} // 原生繪圖 by Aone

 

調用原生繪圖的 TCanvas 函數:(僅有下面函數有質量問題)

DrawLine 畫線 
FillRect 圓距區 
DrawRect 圓距框線 
FillPath 路徑區 
DrawPath 路徑框線 
FillEllipse 橢圓區 
DrawEllipse 橢圓框線
FillArc 孤線區
DrawArc 孤框線 
FillPolygon 多邊形區 
DrawPolygon 多邊形框線 
IntersectClipRect 相交剪裁區
ExcludeClipRect 其它剪裁區

 

TBrush 塗刷 & TStrokeBrush 線刷:

  • 支持全部塗刷特性,除了 Bitmap 塗色還沒有支持(如有此需求,可自行修改源碼,加入此特性)
  • FMX 在移動平臺是不支持畫線加漸層塗色,使用原生繪圖,已經能夠輕鬆實現(支持 Linear 線漸層及 Radial 圓漸層效果):
    原生 FMX
  • procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
    var Rect, DesRect: TRectF;
    begin
      Rect := PaintBox1.LocalRect;
      Canvas.Stroke.Thickness := 10;
      Canvas.Stroke.Kind := TBrushKind.Gradient;
      Canvas.Stroke.Dash := TStrokeDash.DashDotDot;
      Canvas.Stroke.Gradient.Color := TAlphaColorRec.Blue;
      Canvas.Stroke.Gradient.Color1 := TAlphaColorRec.Gold;
    
      {$IFDEF UseNativeDraw}Canvas.NativeDraw(Rect, procedure begin {$ENDIF} // 原生繪圖 by Aone
    
      DesRect := Rect;
      InflateRect(DesRect, -(Canvas.Stroke.Thickness / 2), -(Canvas.Stroke.Thickness / 2)); // 線在區內
      Canvas.FillRect(DesRect, 30, 30, AllCorners, 1);
      Canvas.DrawRect(DesRect, 30, 30, AllCorners, 1);
    
      {$IFDEF UseNativeDraw}end);{$ENDIF} // 原生繪圖 by Aone
    end;

 

已知問題:

  • 真機 iOS 64bit 沒法顯示虛線(虛擬機沒問題)
  • 未完成的函數功能及特性,歡迎你們一塊兒完善

 

文件下載:

 

 2017.06.22 新增 TestArc Demo(已更新到 GitHub):

參考資料:

相關文章
相關標籤/搜索