Fiiremonkey 的跨平台能力,大家有目共睹(一码同介面跨四平台),唯独移动平台在几何绘图方面,质量始终不尽人意,我也曾试着去修正(如:修正曲线平滑问题),也曾找过第三方案(如:AggPas),但都不完美,我一直在想,移动平台有这么强的绘图能力及质量(Android & iOS),如果能直接拿来用,不是很好?为什么 Firemonkey 要自己重写?
目前网上许多针对此问题的改善方案,但多以控件形式,且需依各平台的绘图函数来绘图,或仅提供固定的几何图形控件,如果能延用现有的 TCanvas.Draw????? 绘图代码,只要加入几行代码(或编译开关),就能达到原生绘图的效果,岂不是很理想,于是开是构想这种方案的可行性,最后证实是可行的。
要先说明的是,这里提供的只是一种改善方案,而不是修正,最终还是希望能受到 EMB 官方的关注,由官方来改进这个问题。
FMX 的绘图方法:
procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var Rect, DesRect: TRectF;
begin
Rect := PaintBox1.LocalRect;
Canvas.Stroke.Thickness := ;
Canvas.Stroke.Kind := TBrushKind.Solid;
Canvas.Stroke.Dash := TStrokeDash.DashDotDot;
DesRect := Rect;
InflateRect(DesRect, -(Canvas.Stroke.Thickness / ), -(Canvas.Stroke.Thickness / )); // 线在区内
Canvas.FillRect(DesRect, , , AllCorners, );
Canvas.DrawRect(DesRect, , , AllCorners, );
end;
说明
Android
iOS
Windows
macOS
上面的代码,使用 FMX 绘图方法
(移动平台是有问题的)
下面的代码,使用原生绘图方法
(四个平台全部相同了)
下面改成原生绘图方案,只要在原有絵图代码前後加入二行代码(原绘图代码不用更动):
{$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 方法
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
DrawLine
画线
FillRect
圆距区
DrawRect
圆距框线
FillPath
路径区
DrawPath
路径框线
FillEllipse
椭圆区
DrawEllipse
椭圆框线
FillArc
孤线区
DrawArc
孤框线
FillPolygon
多边形区
DrawPolygon
多边形框线
IntersectClipRect
相交剪裁区
ExcludeClipRect
其它剪裁区
支持所有涂刷特性,除了 Bitmap 涂色尚未支持(若有此需求,可自行修改源码,加入此特性)
FMX 在移动平台是不支持画线加渐层涂色,使用原生绘图,已经可以轻松实现(支持 Linear 线渐层及 Radial 圆渐层效果):
原生
FMX
procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var Rect, DesRect: TRectF;
begin
Rect := PaintBox1.LocalRect;
Canvas.Stroke.Thickness := ;
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 / ), -(Canvas.Stroke.Thickness / )); // 线在区内
Canvas.FillRect(DesRect, , , AllCorners, );
Canvas.DrawRect(DesRect, , , AllCorners, );
{$IFDEF UseNativeDraw}end);{$ENDIF} // 原生绘图 by Aone
end;
文件下载:
2017.06.22 新增 TestArc Demo(已更新到 GitHub):
手机扫一扫
移动阅读更方便
你可能感兴趣的文章