这是我第一次尝试使用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