我需要创建一个如下所示的进度条。
我现在所做的是:
public void Draw(ICanvas canvas, RectF dirtyRect)
{
float effectiveSize = Size - Thickness;
float x = Thickness / 2;
float y = Thickness / 2;
if (Progress < 0)
{
Progress = 0;
}
else if (Progress > 100)
{
Progress = 100;
}
if (Progress < 100)
{
float angle = GetAngle(Progress);
canvas.StrokeColor = ProgressLeftColor;
canvas.StrokeSize = Thickness;
canvas.DrawEllipse(x, y, effectiveSize, effectiveSize);
// Draw arc
canvas.StrokeColor = ProgressColor;
canvas.StrokeSize = Thickness;
canvas.DrawArc(x, y, effectiveSize, effectiveSize, 90, angle, true, false);
}
else
{
// Draw circle
canvas.StrokeColor = ProgressColor;
canvas.StrokeSize = Thickness;
canvas.DrawEllipse(x, y, effectiveSize, effectiveSize);
}
float fontSize = effectiveSize / 2.86f;
canvas.FontSize = fontSize;
canvas.FontColor = TextColor;
float verticalPosition = ((Size / 2) - (fontSize / 2)) * 1.15f;
canvas.DrawString($"{Progress}%", x, verticalPosition, effectiveSize, effectiveSize / 4, HorizontalAlignment.Center, VerticalAlignment.Center);
}
这会画出一个带有弧线的漂亮圆圈。我正在努力解决内部馅饼部分(浅灰色部分)。我需要那个部分填充一些颜色。
我的想法之一是创建两条线,然后用弧线连接它们,并填充对象。 像这样的东西。
canvas.FillColor = Colors.Teal;
var center = new Point(effectiveSize / 2, effectiveSize / 2);
var startPoint = new Point(x, y);
var endPoint = new Point();
canvas.DrawLine(center, startPoint);
canvas.DrawLine(center, endPoint);
canvas.DrawArc((float)startPoint.X, (float)startPoint.Y,float)endPoint.X, (float)endPoint.Y, 0, angle, true, false);
如何计算终点。 或者有什么更好的解决办法吗
谢谢
您可以尝试使用SkiaSharp来绘制这个饼图。我在这里分享一个解决方案。有关更多信息,您可以参考SkiaSharp曲线和路径。它也适用于毛伊岛。
使用滑块控制角度:
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Slider Maximum="360" ValueChanged="Slider_ValueChanged" />
<skia:SKCanvasView x:Name="mycanvas" WidthRequest="400" HeightRequest="400" PaintSurface="SKCanvasView_PaintSurface"/>
</VerticalStackLayout>
在后面的代码中:
void Slider_ValueChanged(System.Object sender, Microsoft.Maui.Controls.ValueChangedEventArgs e)
{
if (e.NewValue >= 360)
{
// the value cannnot be equal to 360
SweepAngle = (float)359.99;
}
else
{
SweepAngle = (float)e.NewValue;
}
mycanvas.InvalidateSurface();
}
void SKCanvasView_PaintSurface(System.Object sender, SkiaSharp.Views.Maui.SKPaintSurfaceEventArgs e)
{
SKImageInfo info = e.Info;
SKSurface surface = e.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// draw the default background circle ring
SKPaint cPaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.LightGray,
StrokeWidth = 50
};
SKPoint center = new SKPoint(info.Width / 2, info.Height / 2);
canvas.DrawCircle(center, 200, cPaint);
cPaint.Color = SKColors.AliceBlue;
cPaint.Style = SKPaintStyle.Fill;
canvas.DrawCircle(center, 200, cPaint);
//draw the progress bar outer ring
SKRect rect = new SKRect(center.X-200, center.Y-200, center.X + 200, center.Y + 200);
SKPaint aPaint = new SKPaint()
{
StrokeWidth = 50,
Color = SKColors.Green,
IsStroke = true
};
canvas.DrawArc(rect, -90, SweepAngle, false,aPaint);
// draw the inner circle of the progress bar
using (SKPath path = new SKPath())
using (SKPaint fillPaint = new SKPaint())
using (SKPaint outlinePaint = new SKPaint())
{
SKRect rect1 = new SKRect(center.X - 200, center.Y - 200, center.X + 200, center.Y + 200);
path.MoveTo(e.Info.Width / 2, e.Info.Height / 2);
path.ArcTo(rect1, -90, SweepAngle, false);
fillPaint.Style = SKPaintStyle.Fill;
fillPaint.Color = SKColors.LightGreen;
canvas.DrawPath(path, fillPaint);
}
SKPaint textPaint = new SKPaint
{
Color = SKColors.LightSeaGreen,
StrokeWidth = 1,
};
// draw the text
string text = (Math.Round(SweepAngle/360*100,0)).ToString() + "%";
float textWidth = textPaint.MeasureText(text);
textPaint.TextSize = 0.2f * info.Width * textPaint.TextSize / textWidth;
SKRect textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);
float xText = info.Width / 2 - textBounds.MidX;
float yText = info.Height / 2 - textBounds.MidY;
canvas.DrawText(text, xText, yText, textPaint);
}
希望有帮助!
您已经使用 Skia 得到了一个很好的答案,但如果您想使用 Microsoft.Maui.Graphics,这里是一个替代方案。没有文本,因为即使可以将其添加到可绘制对象中,如果您正在执行控件,那么在封装所有这些内容的 ContentView 中也更好。从那里您可以添加 BindableProperty 和所有此类机制。
public class ProgressbarDrawable : IDrawable
{
public double Progress { get; set; } = 100;
public void Draw(ICanvas canvas, RectF dirtyRect)
{
canvas.SaveState();
var startAngle = 90;
var _progressAngle = Progress / 100;
var endAngle = startAngle - (int)Math.Round(_progressAngle * 360, MidpointRounding.AwayFromZero);
var isFullCircle = Progress == 100;
var centerX = dirtyRect.Width / 2;
var centerY = dirtyRect.Height / 2;
var radius = dirtyRect.Width / 2;
canvas.StrokeColor = new Color(243, 242, 238);
canvas.StrokeSize = 10;
canvas.DrawCircle(centerX, centerY, radius);
if (isFullCircle)
{
canvas.FillColor = new Color(235, 243, 231);
canvas.FillCircle(centerX, centerY, radius);
canvas.StrokeColor = new Color(132, 189, 137);
canvas.StrokeSize = 10;
canvas.DrawCircle(centerX, centerY, radius);
}
else
{
var path = new PathF();
path.MoveTo(centerX, centerY);
path.AddArc(centerX - radius, centerY - radius, radius * 2, radius * 2, startAngle, endAngle, true);
path.LineTo(centerX, centerY);
canvas.FillColor = new Color(235, 243, 231);
canvas.FillPath(path);
canvas.StrokeColor = new Color(132, 189, 137);
canvas.StrokeSize = 10;
canvas.DrawArc(centerX - radius, centerY - radius, radius * 2, radius * 2, startAngle, endAngle, true, false);
}
canvas.RestoreState();
}
}
实施
<ContentPage.Resources>
<drawables:ProgressbarDrawable x:Key="ProgressbarDrawable" />
</ContentPage.Resources>
<GraphicsView
x:Name="ProgressbarDrawable"
Drawable="{StaticResource ProgressbarDrawable}"
HeightRequest="200"
WidthRequest="200" />