我正在开发一些基本的iPhone应用程序/实用工具/游戏,以更好地掌握它。
目前,我已经设置了一个CGRect
,可以随着手指移动而移动。然而,我不希望CGRect
超出view
的边界。
原始方法
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
startLocation = [touch locationInView:self];
if (startLocation.x < 33){
touchLocation.x = 33;
//NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
[self setNeedsDisplay];
}
if (startLocation.x > 288){
touchLocation.x = 288;
//NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
[self setNeedsDisplay];
}
if (startLocation.y < 84){
touchLocation.y = 84;
//NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
[self setNeedsDisplay];
}
if (startLocation.y > 460){
touchLocation.y = 460;
//NSLog(@"Touch At:%f, %f", touchLocation.x, touchLocation.y);
[self setNeedsDisplay];
}
else {
touchLocation = startLocation;
[self setNeedsDisplay];
}
}
问题
我已经尝试了几种不同的方法,包括使用&&
并将其作为一个语句。显然,boundaries
是硬编码的,我不确定手动设置touchLocation
是否是保持在bounds
中的最佳方式。
当我可以轻松地使用self.view.bounds
并获取边界CGRect
时,所有这些看起来都很荒谬。如何利用bounds
来做到这一点?除了手动设置touchLocation
之外,有没有更好的方法来防止它发生?我能否在其上放置硬限制?
那么switch
语句呢?它是否比尝试的if
更有效?
尝试
我现在正在尝试利用@Brad Goss下面发布的方法,但它不起作用?
Touch Started: (319.000000,350.000000)
Touch Result: (319.000000,350.000000)
Boundaries calculated: X:(0.000000,288.000000) Y(0.000000,328.000000)
Touch Started是实际的开始触摸。
Touch Result应该是改变后的结果。
上面的日志显示在定义的bounds
之外,也就是没有起作用。我不会重新发布他编写的代码,因为它完全相同。
尝试问题
我已经发现了问题。这是与上述情况相同的类型,但记录了设置每个值时的单独值。
Touch Started: (293.000000,341.000000)
min x:288.000000
max x:293.000000
min y:328.000000
max y:341.000000
Touch Result: (293.000000,341.000000)
Boundaries calculated: X:(0.000000,288.000000) Y(0.000000,328.000000)
我还没想明白,一发现问题就在这里发布了。否则我会完全忘记更新,ADD 呵呵。
我将回去查看每种可能情况下的具体情况。
错误
发现另一个问题,计算boundaries
的代码减去
了maximums
,但没有加上
minimums
。这很重要,因为这是boundary
的作用,用于防止rect
离开屏幕。
maxX = b.origin.x + b.size.width/* - [box bounds].size.width */;
minX = b.origin.x/* + [box bounds].size.width */;
maxY = b.origin.y + b.size.height/* - [box bounds].size.height */;
minY = b.origin.y?/* + [box bounds].size.height */;
问题已经解决,我现在可以继续处理原来的问题。
错误2
好了,我又解决了一个问题。之前在显示时我对 y
值进行了累加,但是我忘记在这个新代码中添加/提及了它。现在代码看起来像这样:
maxX = b.origin.x + b.size.width/* - [box bounds].size.width */;
minX = b.origin.x/* + [box bounds].size.width */;
maxY = b.origin.y + b.size.height/* - [box bounds].size.height + 20*/;
minY = b.origin.y/* + [box bounds].size.height + 20*/;
显示的圆圈大小在一个64px CGRect
内,因此20px
足以将圆圈显示在拇指上方。虽然这是固定的,但仍未解决我们最初的问题。
左上角:
Touch Started: (14.000000,20.000000)
min x:14.000000
max x:32.000000
min y:20.000000
max y:84.000000
Touch Result: (32.000000,84.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)
它按照预期工作,但我不明白为什么正确的值来自于MAX
而不是MIN
。这里有些混淆。
右上角:
Touch Started: (303.000000,21.000000)
min x:288.000000
max x:303.000000
min y:21.000000
max y:84.000000
Touch Result: (303.000000,84.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)
这阻止了我从屏幕顶部飞出,而是使用MAX
而不是MIN
。如上图所示,我仍然能够飞到右边。
右下角:
Touch Started: (317.000000,358.000000)
min x:288.000000
max x:317.000000
min y:276.000000
max y:358.000000
Touch Result: (317.000000,358.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)
它在两个方向上都失败了。现在实际值来自MAX
,最大值来自MIN
。真是令人困惑?
左下角:
Touch Started: (8.000000,354.000000)
min x:8.000000
max x:32.000000
min y:276.000000
max y:354.000000
Touch Result: (32.000000,354.000000)
Boundaries calculated: X:(32.000000,288.000000) Y(84.000000,276.000000)
可预见的是,它只适用于最小值。我仍然非常困惑这些函数应该做什么。希望能得到更多的见解!
已解决!
我们漫长的道路即将结束,谢天谢地。所以,因为我一点也不知道,这就是MIN
和MAX
的作用。由于发生的混乱,初始时对我来说并不明显。
MAX(x,y) will output the larger of the two numbers
// MAX(13,37) = 37
MIN(x,y) will output the smallest of the two numbers
// MIN(13,37) = 13
如果您想在这种情况下正确使用这些功能,需要执行以下操作:
1. 计算X和Y的最大值和最小值。
每个值的最低值计算如下:
view.origin + keepOnScreenRect.width
每个值的最高值计算如下:
view.origin + view.size.height/width - keepOnScreenRect.height/width
不要忘记手指的偏移量!
如果您正在执行我所做的操作,并且将keepOnScreenRect位置略微放在用户手指上方,则应仅将额外偏移添加到Y的最大值中,因为Y的最小值是屏幕/视图的底部,您无法物理上低于0。
如果您想知道为什么要这样做,那是因为用户无法透过自己的手指看到屏幕。
2. 在touchesBegan:
中获取触摸位置
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
startTouchLocation = [touch locationInView:self];
NSLog(@"Touch Started: (%f,%f)", startTouchLocation.x, startTouchLocation.y);
3. 应用数学约束:
首先,我们获取根据限制条件得到的最小可能值 minX
和 X
的触摸起始位置 startTouchLocation
中的最高值(即MAX
),用于计算屏幕左边界的限制。将此结果设置为 currentTouchLocation
。
currentTouchLocation.x = MAX(minX, startTouchLocation.x);
其次,我们获取
X
的最低值,即根据限制条件的最大可能值 maxX
和当前触摸位置 currentTouchLocation
中的最小值 MIN
。请注意,我们不是使用原始触摸位置,而是使用刚刚使用的 MAX
函数的结果位置。该值已经检查过屏幕左侧,因此我们要检查右侧。currentTouchLocation.x = MIN(maxX, currentTouchLocation.x);
这给我们一个保证在限制范围内的 X
位置。然后我们对 Y
执行相同的操作。
currentTouchLocation.y = MAX(minY, startTouchLocation.y);
currentTouchLocation.y = MIN(maxY, currentTouchLocation.y);
完成以上所有步骤后,我们现在可以告诉视图重新绘制自己,并不再担心我们可爱的小矩形被任何方式裁剪。
[self setNeedsDisplay];
成品
/* Generates the limits based on the view's size, taking into account
the width/height of the rect being displayed in it. This should only
be run once, unless the size of the view changes, in which case limits
would have to be recalculated. The same goes for if you were to change
the size of the displaying rect after calculation */
- (void)boundsCalculation {
CGRect viewBounds = [self bounds];
// calculate constraints
maxX = viewBounds.origin.x + viewBounds.size.width - 32;
minX = viewBounds.origin.x + 32;
maxY = viewBounds.origin.y + viewBounds.size.height - 32;
minY = viewBounds.origin.y + 84;
NSLog(@"Boundaries calculated: X:(%f,%f) Y(%f,%f)", minX, maxX, minY, maxY);
}
/* Magic goodness that happens when the user touches the screen.
Note that we don't calculate the bounds every time the user touches
the screen, that would be silly. */
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
startTouchLocation = [touch locationInView:self];
NSLog(@"Touch Started: (%f,%f)", startTouchLocation.x, startTouchLocation.y);
// apply constraints
// highest x value between the lowest allotted x value and touch
currentTouchLocation.x = MAX(minX, startTouchLocation.x);
// lowest x value between the highest allotted x value and touch
currentTouchLocation.x = MIN(maxX, currentTouchLocation.x);
// highest y value between the lowest allotted y value and touch
currentTouchLocation.y = MAX(minY, startTouchLocation.y);
// lowest y value between the highest allotted y value and touch
currentTouchLocation.y = MIN(maxY, currentTouchLocation.y);
// NSLog(@"Touch Result: (%f,%f)", currentTouchLocation.x, currentTouchLocation.y);
// If you don't do this you won't see anything
[self setNeedsDisplay];
}
今天是一个很好的学习日。