我正在尝试使用 UIGestures 执行类似于 UIScrollView 的缩放和平移。
我的观点是从开/关单元矩阵中得出的,需要能够支持数千个单元。drawRect: 方法负责将矩阵坐标转换为屏幕坐标。该视图具有缩放量的属性和保存偏移量的 CGPoint。
我想如果我能弄清楚下面的缩放和平移,我应该很好。很抱歉下面的代码墙,但它代表了一个完整的实现,它反映了我更复杂的程序。
现在,缩放确实缩放了一切,但它需要一种方法来使自己居中,就像 UIScrollView 缩放一样。
平移根本无法正常工作。
缩放视图.h
ZoomView 负责绘制布尔矩阵。
#import <Foundation/Foundation.h>
#import "ZoomModel.h"
@interface ZoomView : UIView
{
ZoomModel *m;
}
@property (nonatomic) float zoomScale;
@property (nonatomic) CGPoint offset;
- (id)initWithFrame:(CGRect)frame
andModel:(ZoomModel *)model;
- (BOOL)checkCellAt:(float)x
andY:(float)y;
- (CGSize)resize;
@end
缩放视图.m
drawRect: 方法进行计算以确定哪个矩阵元素应该位于屏幕的可见部分。屏幕的可见部分由 zoomScale 和偏移量决定。
#import "ZoomView.h"
#import <QuartzCore/QuartzCore.h>
@implementation ZoomView
@synthesize zoomScale, offset, holdZoom;
- (id)initWithFrame:(CGRect)frame
andModel:(ZoomModel *)model
{
self = [super initWithFrame:frame];
if (self) {
m = model;
zoomScale = 1.0;
offset = CGPointMake(0, 0);
}
return self;
}
- (void)setZoomScale:(float)s
{
zoomScale *= s;
if (zoomScale < 1.0) {
zoomScale = 1.0;
}
}
- (void)setOffset:(CGPoint)o
{
//This function is to make sure we don't pan outside the content range
//it needs some work, I'm having trouble getting the panning to work
float size = m.cellSize * zoomScale;
offset = o;
if ((offset.x - self.frame.size.width/size) <= 0) {
//offset.x = self.frame.size.width;
NSLog(@"X MIN");
}
if ((offset.x + self.frame.size.width/size) >= (m.gridLength*size)) {
// offset.x = (m.gridLength*size) - self.frame.size.width;
NSLog(@"X MAX");
}
if ((offset.y - self.frame.size.height/size) <= 0) {
//offset.y = self.frame.size.height;
NSLog(@"Y MIN");
}
if ((offset.y + self.frame.size.height/size) >= (m.gridLength*size)) {
// offset.y = (m.gridHeight*size) - self.frame.size.height;
NSLog(@"Y MAX");
}
}
- (BOOL)checkCellAt:(float)x
andY:(float)y
{
int X = (int)(x/m.cellSize * zoomScale);
int Y = (int)(y/m.cellSize * zoomScale);
return [m cellAtX:X andY:Y];
}
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
[[UIColor blackColor] setFill];
CGContextFillRect(ctx, rect);
float size = m.cellSize * zoomScale;
[[UIColor whiteColor] setFill];
float a = offset.x;
float b = offset.y;
//the -5 is there to give a little buffer so that half cells can be seen
// -a is taken because the offset is negative
int startX = (int)(-a/size) - 5;
int startY = (int)(-b/size) - 5;
int endX = (int)(startX) + (int)(rect.size.width/size) + 10;
int endY = (int)(startY) + (int)(rect.size.height/size) + 10;
if (startX < 0)
startX = 0;
if (startY < 0)
startY = 0;
if (endX > m.gridLength)
endX = m.gridLength;
if (endY > m.gridHeight)
endY = m.gridHeight;
[[UIColor whiteColor] setFill];
for (float i=startX; i<endX; ++i) {
for (float j=startX; j<endY; ++j) {
if ([m cellAtX:(int)i andY:(int)j]) {
//ii and jj are there to make the drawing start on the top left corner of the view
float ii = i - startX;
float jj = j - startY;
CGRect cell = CGRectMake(size*ii, size*jj, size, size);
CGContextFillRect(ctx, cell);
}
}
}
}
@end
缩放视图控制器.h
此视图控制器包含手势识别器和处理程序
#import <Foundation/Foundation.h>
#import "ZoomModel.h"
#import "ZoomView.h"
@interface ZoomViewController : UIViewController <UIGestureRecognizerDelegate>
{
ZoomModel *m;
ZoomView *v;
}
- (void)handleZoom:(UIPinchGestureRecognizer *)recognizer;
- (void)handlePan:(UIPanGestureRecognizer *)recognizer;
@end
缩放视图控制器.m
zoomView 设置在 UIView 内,该 UIView 将屏幕框架作为其框架。zoomView 本身比屏幕大一点,以允许绘制半个单元格。
#import "ZoomViewController.h"
#import <QuartzCore/QuartzCore.h>
@implementation ZoomViewController
- (void)loadView
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
UIView *mainView = [[UIView alloc] initWithFrame:screenRect];
float cellSize = 1;
int ni = (int)(screenRect.size.width/cellSize);
int nj = (int)(screenRect.size.height/cellSize);
CGRect zoomRect = CGRectMake(0, 0, 1.2*screenRect.size.width, 1.2*screenRect.size.height);
m = [[ZoomModel alloc] initWithLength:ni andHeight:nj andCellSize:cellSize];
v = [[ZoomView alloc] initWithFrame:zoomRect andModel:m];
v.center = CGPointMake(v.frame.size.width/2.0, v.frame.size.height/2.0);
UIPinchGestureRecognizer *zRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self
action:@selector(handleZoom:)];
zRecognizer.delegate = self;
[v addGestureRecognizer:zRecognizer];
UIPanGestureRecognizer *pRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(handlePan:)];
[pRecognizer setMaximumNumberOfTouches:1];
[pRecognizer setMinimumNumberOfTouches:1];
pRecognizer.delegate = self;
[v addGestureRecognizer:pRecognizer];
[mainView addSubview:v];
[self setView:mainView];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
- (void)handleZoom:(UIPinchGestureRecognizer *)recognizer
{
[v setZoomScale:recognizer.scale];
//need code to zoom around the center instead of the top left corner
recognizer.scale = 1;
[v setNeedsDisplay];
}
- (void)handlePan:(UIPanGestureRecognizer *)recognizer
{
//Adjusts the offset of the view, which is used in its drawRect:
CGPoint translation = [recognizer translationInView:self.view];
CGPoint newOffset = CGPointMake(v.offset.x - translation.x, v.offset.y - translation.y);
[v setOffset:newOffset];
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
[v setNeedsDisplay];
}
@end
缩放模型.h
这个类只是用随机的开/关值填充一个布尔矩阵,这样我们就可以在屏幕上看到一些东西它在它的访问器方法中模拟了我更复杂的应用程序模型。
#import <Foundation/Foundation.h>
@interface ZoomModel : NSObject
{
bool *grid;
}
@property (nonatomic) int gridLength;
@property (nonatomic) int gridHeight;
@property (nonatomic) float cellSize;
- (id)initWithLength:(int)l
andHeight:(int)h
andCellSize:(float)s;
- (BOOL)cellAtX:(int)x
andY:(int)y;
@end
缩放模型.m
#import "ZoomModel.h"
@implementation ZoomModel
@synthesize gridHeight, gridLength, cellSize;
- (id)initWithLength:(int)l
andHeight:(int)h
andCellSize:(float)s
{
self = [super init];
if (self) {
grid = malloc(l*h*sizeof(bool));
gridHeight = h;
gridLength = l;
cellSize = s;
for (int i=0; i<h*l; i++) {
if (arc4random()%6 >= 4)
grid[i] = true;
else
grid[i] = false;
}
}
return self;
}
- (BOOL)cellAtX:(int)x andY:(int)y
{
return (BOOL)grid[x*gridLength + y];
}
@end