我正在使用Xamarin Forms创建一个跨平台应用程序,并尝试使用以下代码绘制从10到-10的行。但问题是线条仅从10到0。为什么会发生这种情况我没有任何想法。
int margin = 20;
int steps = 20;
float start = margin;
float end = width - margin;
float dHeigth = heigth - (margin * 4);
float hStep = dHeigth / Convert.ToSingle(steps);
float textMargin = 30;
// draw the line
for (int i = 10; i >= -10; i--)
{
float xpoint = i * hStep + margin;
if (i.IsOdd())
{
canvas.DrawLine(start + textMargin, xpoint, end, xpoint, LineWhitePaint);
}
else
{
decimal dText = 0;
canvas.DrawLine(start + textMargin, xpoint, end, xpoint, LineGreyPaint);
if (i < 0)
dText = i;
else
dText = (10 - i);
string txt = dText.ToString();
canvas.DrawText(txt, start + margin, xpoint + 15, TextStyleFillPaintX);
}
}
我附上了那张
的截屏答案 0 :(得分:1)
对于正线,您正在绘制10 - i
,第一次迭代产生0
,第三次产生2
,依此类推。对此,您可以看到,您开始从画布中间绘制线条。第十次迭代将绘制最顶部的线(具有10的那一行)。 的其他行被绘制,但不在屏幕上。
当您将xPoint
写入调试输出时,也可以看到这一点。当i
变为否定时,xPoint
也会变为负数。要解决此问题,您必须将xPoint
偏移以始终在屏幕上绘图
float xpoint = i * hStep + margin + steps / 2 * hStep;
或者,您可以从20循环到0并更改文本的生成方式。
for (int i = 20; i >= 0; i--)
{
var xPoint = i * hStep + margin;
// ...
var displayedText = GetDisplayedText(i, steps);
// ...
}
string GetDisplayedText(int i, int steps)
{
var displayedValue = i > steps / 2
? steps - i
: -i - steps / 2; // I think this should be the formula
return displayedValue.ToString();
}
备注:最好封装线条的概念,将它们的计算与纵向分开。您可以创建一个工厂,根据索引和步骤数生成正确的行,然后只迭代Line
个对象,并通过传递画布来绘制它们。这将使您的代码更清洁,更整洁。
<强>更新强>
由于我们已经能够澄清要求,我将再次拍摄。
首先,我定义了将图形坐标转换为画布坐标的方法
private SKPoint ToCanvasCoordinates(SKPoint graphCoordinates)
{
var x = Margin + TextMargin + (_canvas.Width - 2*Margin - TextMargin)*graphCoordinates.X;
var y = (MaxY - graphCoordinates.Y)*(_canvas.Height - 2 * Margin)/(MaxY - MinY) + Margin;
return new SKPoint(x,y);
}
private SKPoint GetLegendCoordinates(int i)
{
var x = Margin;
var y = (MaxY - graphCoordinates.Y)*(_canvas.Height - 2 * Margin)/(MaxY - MinY) + Margin + 15;
return new SKPoint(x,y);
}
在这种情况下, _canvas
是私有成员字段,Margin
,MaxY
和MinY
是属性。我假设x
的最小值为0,最大值为1。
现在你可以画出像
这样的线条for(int i = -1; i <= 10; i++)
{
var lineStart = ToCanvasCoordinates(new SKPoint(0, i));
var lineEnd = ToCanvasCoordinates(new SKPoint(1, i));
canvas.DrawLine(lineStart, lineEnd, LineGreyPaint);
var textPosition = GetLegendCoordinates(i);
canvas.DrawText(i.ToString(), textPosition, TextStyleFillPaintX);
}
此外,如果您想在两个网格线之间画一条线,可以使用以下方法
private void DrawDataLine(SKPoint start, SKPoint end, SKPaint paint)
{
var startTransformed = ToCanvasCoordinates(start);
var endTransformed = ToCanvasCoordinates(end);
_canvas.DrawLine(startTransformed, endTransformed, paint);
}
private void DrawData(SKPaint paint)
{
for(int i=1; i<_data.Length; i++)
{
DrawDataLine(new SKPoint(data[i-1].X, data[i-1].Y), new SKPoint(data[i].X, data[i].Y)); // given that the objects in _data have the properties X and Y
}
}