这是我第一次尝试 xamarin 应用程序。我目前只针对android。
该应用程序是一个以圆圈绘制的隐喻日历。我正在使用skiasharp 来完成我所有的绘图。我的问题是我一直在尝试根据文档实现滚动和捏缩放。如果我使用刹车点运行,那么代码(至少用于滚动)似乎可以工作。但如果没有刹车点,图像只会不断重新设置回屏幕的中心。我不能为我的生活找出原因。
这是绘制日历的 OnCanvasViewPaintSurface 方法
void OnCanvasViewPaintSurface(object sender, SkiaSharp.Views.Android.SKPaintSurfaceEventArgs args)
{
_info = args.Info;
_surface = args.Surface;
_canvas = _surface.Canvas;
_canvas.Clear();
if (Xtranslation == 0 && Ytranslation == 0)
System.Diagnostics.Debug.WriteLine("back to 0 again? WTF?");
_canvas.Translate(Xtranslation, Ytranslation);
_canvas.Scale(Scale);
string resourceID = "DruidCraftCalendar.Assets.calendar2.png";
Assembly assembly = GetType().GetTypeInfo().Assembly;
var cx = (_info.Width - Utility.GetWidthValueFromPercentage(_info, 99)) / 2;
var cy = (_info.Height - Utility.GetWidthValueFromPercentage(_info, 99)) / 2;
using (var stream = assembly.GetManifestResourceStream(resourceID))
using (var bitmap = SKBitmap.Decode(stream))
using (var paint = new SKPaint())
{
_canvas.DrawBitmap(bitmap, SKRect.Create(cx, cy, Utility.GetWidthValueFromPercentage(_info, 99), Utility.GetWidthValueFromPercentage(_info, 99)), paint);
}
CalendarRenderer.DrawCalendar(_info, _canvas, _calendar);
}
没有很多事情发生。绘制日历的最终调用在它下面有一组方法来绘制日历这里是一些代表该类中的东西的方法
private static void BuildDayRings(SKImageInfo info, SKCanvas canvas, IDayModel day, IMonthModel month)
{
float outerRingPercentageWidth = 31;
float innerRingPercentageWidth = 26;
var arcPainter = new SKPaint
{
Color = SKColors.Black,
Style = SKPaintStyle.Stroke,
StrokeWidth = 2
};
var dayLabelPainter = new SKPaint
{
Color = Color.FromRgb(0, 0, 0).ToSKColor(),
Style = SKPaintStyle.StrokeAndFill,
StrokeWidth = 2,
TextSize = Utility.GetWidthValueFromPercentage(info, 2.5f)
};
info = BuildOuterDayRing(info, canvas, outerRingPercentageWidth, arcPainter);
info = BuildInnerDayRing(info, canvas, innerRingPercentageWidth, arcPainter);
CircleShape[] outerRingPegPoints = GetOuterPegPoints(info, canvas, outerRingPercentageWidth);
CircleShape[] innerRingPegPoints = GetInnerPegPoints(info, canvas, innerRingPercentageWidth);
ConnectDayRingCrossover(canvas, arcPainter, outerRingPegPoints, innerRingPegPoints);
CreateDayLabels(info, canvas, arcPainter, dayLabelPainter, outerRingPegPoints, innerRingPegPoints);
SetActiveDayPeg(info, canvas, day, month, outerRingPegPoints, innerRingPegPoints);
}
private static void SetActiveDayPeg(SKImageInfo info, SKCanvas canvas, IDayModel day, IMonthModel month, CircleShape[] outerRingPegPoints, CircleShape[] innerRingPegPoints)
{
ColourActiveDayPeg(day, month, outerRingPegPoints, innerRingPegPoints);
DrawDayPegPoints(info, canvas, outerRingPegPoints, innerRingPegPoints);
}
private static void DrawDayPegPoints(SKImageInfo info, SKCanvas canvas, CircleShape[] outerRingPegPoints, CircleShape[] innerRingPegPoints)
{
DrawOutterRingPegPoints(canvas, outerRingPegPoints);
DrawInnerRingPegPoints(info, canvas, innerRingPegPoints);
}
private static void DrawInnerRingPegPoints(SKImageInfo info, SKCanvas canvas, CircleShape[] innerRingPegPoints)
{
for (int i = 0; i <= innerRingPegPoints.Length - 1; i++)
{
DrawPegPointsWithOutOfPlaceFirstPoint(info, canvas, innerRingPegPoints, i);
}
}
........
private static void DrawMonthRing(SKImageInfo info, SKCanvas canvas, IMonthModel month)
{
var monthRing = ElementDrawer.CreateRing(info, canvas, Utility.GetWidthValueFromPercentage(info, (float)21), new Color(255, 255, 255), false);
monthRing.FillColor = new Color(255, 255, 0, 0);
var monthPegPoints = ElementDrawer.CreatePegPoints(info, canvas, monthRing, 13, ((Math.PI * 2) / 13) / 2);
var monthLabelRing = ElementDrawer.CreateRing(info, canvas, Utility.GetWidthValueFromPercentage(info, (float)19.5), new Color(255, 255, 255), false);
var monthLabelPoints = ElementDrawer.CreatePegPoints(info, canvas, monthLabelRing, 13, ((Math.PI * 2) / 13) / 2);
float rotation = 74;
monthPegPoints[month.Get() - 1].FillColor = new Color(255, 0, 0);
for (int i = 0; i <= monthPegPoints.Length - 1; i++)
{
SKPaint txtPaint1 = new SKPaint()
{
Color = Color.FromRgb(255, 255, 255).ToSKColor(),
Style = SKPaintStyle.Fill,
StrokeWidth = 1,
TextSize = Utility.GetWidthValueFromPercentage(info, 2.2f)
};
SKPaint txtPaint2 = new SKPaint()
{
Color = Color.FromRgb(0, 0, 0).ToSKColor(),
Style = SKPaintStyle.Stroke,
StrokeWidth = 2,
TextSize = Utility.GetWidthValueFromPercentage(info, 2.2f)
};
canvas.DrawCircle(monthPegPoints[i].x, monthPegPoints[i].y, monthPegPoints[i].Radius, GetPointPainter(monthPegPoints[i]));
SKRect textbounds = new SKRect();
var labelText = month.GetMonthName(i + 1);
txtPaint1.MeasureText(labelText, ref textbounds);
canvas.Save();
canvas.RotateDegrees(rotation, monthLabelPoints[i].x, monthLabelPoints[i].y);
canvas.DrawText(labelText, monthLabelPoints[i].x, monthLabelPoints[i].y + (textbounds.Height / 2), txtPaint1);
canvas.DrawText(labelText, monthLabelPoints[i].x, monthLabelPoints[i].y + (textbounds.Height / 2), txtPaint2);
canvas.Restore();
rotation = rotation - 27.69f;
}
}
和元素抽屉
public class ElementDrawer
{
public static CircleShape GetPegPointTemplate(SKImageInfo info)
{
var pegPoint = new CircleShape();
pegPoint.Radius = (info.Width / 100) * (float)0.7;
pegPoint.FillColor = Color.FromRgb(90,90,90);
return pegPoint;
}
public static CircleShape[] CreatePegPoints(SKImageInfo info, SKCanvas canvas, CircleShape ring, int points, double offset = 0)
{
CircleShape[] pegPoints = new CircleShape[points];
for (var i = 0; i < points; i++)
{
float x = Convert.ToSingle(((info.Width) / 2) + ring.Radius * Math.Sin(Math.PI + offset + (2 * Math.PI * i / points)));
float y = Convert.ToSingle(((info.Height) / 2) + ring.Radius * Math.Cos(Math.PI + offset + (2 * Math.PI * i / points)));
var point = GetPegPointTemplate(info);
point.x = x;
point.y = y;
pegPoints[i] = point;
}
return pegPoints;
}
public static CircleShape CreateRing(SKImageInfo info, SKCanvas canvas, float radius, Color color, bool draw, bool fill = false)
{
var ring = new CircleShape();
ring.Radius = radius;
ring.OutlineColor = color;
SKPaint paint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = ring.OutlineColor.ToSKColor(),
StrokeWidth = 2
};
if (fill == true)
paint.Style = SKPaintStyle.Fill;
if (draw)
canvas.DrawCircle(info.Width / 2, info.Height / 2, ring.Radius, paint);
return ring;
}
}
回到活动中,这是我处理滚动的方式
private void ProcessTouchEvent(long id, MotionEventActions type, SKPoint location)
{
switch (type)
{
case MotionEventActions.Down:
case MotionEventActions.Pointer2Down:
case MotionEventActions.Pointer1Down:
touchDictionary.Add(id, new TouchManipulationInfo
{
PreviousPoint = location,
NewPoint = location
});
break;
case MotionEventActions.Move:
TouchManipulationInfo info = touchDictionary[id];
info.NewPoint = location;
Manipulate();
info.PreviousPoint = info.NewPoint;
break;
case MotionEventActions.Up:
case MotionEventActions.Pointer2Up:
case MotionEventActions.Pointer1Up:
touchDictionary[id].NewPoint = location;
//Manipulate();
touchDictionary.Remove(id);
break;
case MotionEventActions.Cancel:
touchDictionary.Remove(id);
break;
}
}
public SKMatrix Matrix = SKMatrix.MakeIdentity();
private void Manipulate()
{
TouchManipulationInfo[] infos = new TouchManipulationInfo[touchDictionary.Count];
touchDictionary.Values.CopyTo(infos, 0);
SKMatrix touchMatrix = SKMatrix.MakeIdentity();
if (infos.Length == 1)
{
SKPoint prevPoint = infos[0].PreviousPoint;
SKPoint newPoint = infos[0].NewPoint;
SKPoint pivotPoint = Matrix.MapPoint(_info.Width / 2, _info.Height /2);
OneFingerManipulate(prevPoint, newPoint, pivotPoint);
}
else if (infos.Length >= 2)
{
int pivotIndex = infos[0].NewPoint == infos[0].PreviousPoint ? 0 : 1;
SKPoint pivotPoint = Matrix.MapPoint(_info.Width / 2, _info.Height / 2);
SKPoint newPoint = infos[1 - pivotIndex].NewPoint;
SKPoint prevPoint = infos[1 - pivotIndex].PreviousPoint;
TwoFingerManipulate(prevPoint, newPoint, pivotPoint);
}
}
private void OneFingerManipulate(SKPoint prevPoint, SKPoint newPoint, SKPoint pivotPoint)
{
Xtranslation = newPoint.X - prevPoint.X;
Ytranslation = newPoint.Y - prevPoint.Y;
}
我也将所有代码都放在了 github 上,因为我知道这不是最容易帮助我解决的问题。我一直在寻找基类上的其他方法是否正在重置东西,但我找不到任何东西。有人知道吗?
https://github.com/radicalgeek/DruidcraftCalendar/tree/master/DruidCraftCalendar