转换工程视图时,iOS图形出错
我有一个自定义的UIView和UIPangestureRecograiser,用于捕获点和速度。我将这些点和速度存储在NSMutableArray中,然后使用数据创建UIBezierPath,然后将其添加到撤消/重做历史记录中 当用户在屏幕上移动手指时,撤销历史记录会不断添加新的路径,每个新路径都会被绘制到屏幕外的图形上下文中,剪裁到路径的大小,然后在UIView上绘制 我的问题是:现在我正在创建一个“收缩到缩放”功能,并对工程视图应用缩放和平移变换,放大时所做的任何绘图最终都会出现在错误的位置,即手指在屏幕上的向上和左侧位置,错误的尺寸会变小。在撤消并重做之前,您实际上无法看到正在绘制的内容。我认为屏幕外上下文或屏幕的错误矩形正在更新,或者由于转换不知道如何称呼,存储在撤消历史记录中的路径点具有不同的原点/参考点 这是我的第一个iOS应用程序,可能会有一些愚蠢的错误,我已经使用了许多不同的教程来达到这一点,但我仍然停留在变换如何影响路径上。以及如何确保以正确的比例在屏幕外上下文的正确位置绘制路径。我试过变换路径,变换点,试着反转变换,但我就是不明白 下面是代码,对数量表示歉意。我包括什么处理捕获点,使路径和绘图到屏幕。。。夹点识别器将放大工程视图,并将其转换为将其放大到夹点的中心 在ViewController中,我以整个屏幕的大小创建了绘图视图VelocityDrawer,并添加了手势识别器:转换工程视图时,iOS图形出错,ios,uiview,drawrect,Ios,Uiview,Drawrect,我有一个自定义的UIView和UIPangestureRecograiser,用于捕获点和速度。我将这些点和速度存储在NSMutableArray中,然后使用数据创建UIBezierPath,然后将其添加到撤消/重做历史记录中 当用户在屏幕上移动手指时,撤销历史记录会不断添加新的路径,每个新路径都会被绘制到屏幕外的图形上下文中,剪裁到路径的大小,然后在UIView上绘制 我的问题是:现在我正在创建一个“收缩到缩放”功能,并对工程视图应用缩放和平移变换,放大时所做的任何绘图最终都会出现在错误的位置
VelocityDrawer *slv = [[VelocityDrawer alloc] initWithFrame:CGRectMake(0,0,768,1024)];
slv.tag = 100;
drawingView = slv;
drawingView.delegate = self;
drawingView.currentPen = finePen;
然后在VelocityDrawer中初始化WithFrame:CGRectframe:
self.undoHistory = [[NSMutableArray alloc] init];
self.redoHistory = [[NSMutableArray alloc] init];
// create offscreen context
drawingContext = [self createOffscreenContext:frame.size];
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
panGestureRecognizer.maximumNumberOfTouches = 1;
[self addGestureRecognizer:panGestureRecognizer];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
tapGestureRecognizer.numberOfTapsRequired = 1;
tapGestureRecognizer.numberOfTouchesRequired = 1;
[self addGestureRecognizer:tapGestureRecognizer];
[self clearHistoryBitmaps];
屏幕外上下文的创建方式如下:
- (CGContextRef) createOffscreenContext: (CGSize) size {
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
float scaleFactor = [[UIScreen mainScreen] scale];
// must use whole numbers so invalid context does not happen
NSInteger sw = (NSInteger)(size.width * scaleFactor);
NSInteger sh = (NSInteger)(size.height * scaleFactor);
CGContextRef context = CGBitmapContextCreate(NULL,
sw,
sh,
8,
sw * 4,
colorSpace,
(CGBitmapInfo)kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
CGContextScaleCTM(context, scaleFactor, scaleFactor);
return context;
}
在handlePanGesture。我捕获点,根据手指速度计算extractSize中线条的大小或宽度,然后将信息添加到数组中:
if (panGestureRecognizer.state == UIGestureRecognizerStateBegan)
{
CGPoint point = [panGestureRecognizer locationInView:panGestureRecognizer.view];
CGPoint prev = [[points firstObject] pos];
float size;
size = currentPen.minWidth/2;
// Add point to array
[self addPoint:point withSize:size];
// Add empty group to history
[undoHistory addObject:[[NSMutableArray alloc] init]];
}
if (panGestureRecognizer.state == UIGestureRecognizerStateChanged) {
CGPoint point = [panGestureRecognizer locationInView:panGestureRecognizer.view];
currentPoint = [(LinePoint *)[points lastObject] pos];
float size = clampf([self extractSize:panGestureRecognizer], currentPen.minWidth, currentPen.maxWidth);
[self addPoint:point withSize:size];
NSMutableArray *pArr = [[NSMutableArray alloc] init];
UIBezierPath *sizer = [[UIBezierPath alloc] init];
// interpolate points to make smooth variable width line
NSMutableArray *interPoints = [self calculateSmoothLinePoints];
// code continues
I循环插入识别器中最新点和以前点之间的插值点阵列,创建将在屏幕上绘制的路径:
// other code here
// loop starts
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, mid1.x, mid1.y);
CGPathAddQuadCurveToPoint(path, NULL, prevT1.x, prevT1.y, mid2.x, mid2.y);
CGPathAddLineToPoint(path, NULL, mid2b.x, mid2b.y);
CGPathAddQuadCurveToPoint(path, NULL, prevB1.x, prevB1.y, mid1b.x, mid1b.y);
CGPathAddLineToPoint(path, NULL, mid1.x, mid1.y);
UIBezierPath *aPath = [UIBezierPath bezierPath];
aPath.CGPath = path;
[sizer appendPath:aPath];
[pArr addObject:aPath];
// more code here
// loop ends
CGPathRelease(path);
将所有路径添加到pArr后,我将创建一个HistoryItem,并用路径、线条颜色、线条宽度等填充它
HistoryItem *action = [[HistoryItem alloc] initWithPaths:pArr
andLineColour:self.lineColor
andLineWidth:self.lineWidth
andDrawMode:self.currentDrawMode
andScale:self.scale];
[self addAction:action];
addAction将HistoryItem添加到撤消堆栈。请注意,我记录了self.scale,但不使用它做任何事情。然后,我得到一个边框,并调用setNeedsDisplayInRect
当手势完成后,我会在线条上添加一个圆形的端点。代码省略
最后,drawRect:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
// offScreen context
UIGraphicsPushContext(drawingContext);
HistoryItem *action = [[undoHistory lastObject] lastObject];
if(currentDrawMode == DRAW || currentDrawMode == ERASE) {
for (UIBezierPath *p in action.pathsToDraw) {
p.lineWidth = 1;
p.lineCapStyle = kCGLineCapRound;
[action.lineColor setFill];
[action.lineColor setStroke];
[p fill];
[p stroke];
}
}
if(currentDrawMode == UNDO) {
CGContextClearRect(drawingContext, self.bounds);
for (NSArray *actionGroup in undoHistory) {
for (HistoryItem *undoAction in actionGroup) {
for (UIBezierPath *p in undoAction.pathsToDraw) {
p.lineWidth = 1;
p.lineCapStyle = kCGLineCapRound;
[undoAction.lineColor setFill];
[undoAction.lineColor setStroke];
[p fill];
[p stroke];
}
}
}
}
// similar code for redo omitted
可能是框架/尺寸有问题
// Continuation of drawRect:
CGImageRef cgImage = CGBitmapContextCreateImage(drawingContext);
CGContextClipToRect(context, rect);
CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), cgImage);
CGImageRelease(cgImage);
[super drawRect:rect];
}
重新绘制直线时,需要对点应用相同的变换。存储在阵列中的点相对于在其上渲染的画布。我建议您存储原始帧,然后在下一行渲染时缩放原始帧和新大小之间的坐标 请你澄清一下你所说的画布是什么意思?我曾尝试将工程视图的变换应用于工程视图的drawRect中的路径,但没有纠正问题,虽然有所不同,但仍然是错误的。请举例说明你将如何实施你的建议?你有没有找到答案?我也有同样的问题,在任何地方都找不到合适的答案。。。。
// Continuation of drawRect:
CGImageRef cgImage = CGBitmapContextCreateImage(drawingContext);
CGContextClipToRect(context, rect);
CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), cgImage);
CGImageRelease(cgImage);
[super drawRect:rect];
}