通过在它们上方移动另一个 UIView 来获取所有 UIViews
Posted
技术标签:
【中文标题】通过在它们上方移动另一个 UIView 来获取所有 UIViews【英文标题】:Get all UIViews affected by moving another UIView above them 【发布时间】:2017-05-06 22:04:39 【问题描述】:我有一个UIScrollView
,其中包含许多大小不同的可拖动UIViews
,大部分是正方形。这些UIViews
捕捉到屏幕上的 6 列网格。
当一个UIView
(假设它的大小是132x132)卡入到位并且另一个UIView's
框架与第一个UIView
框架相交时,第二个框架应该移动到第一个框架之下,要么是全部要么是一半第一个UIView
的高度(取决于UIViews
相交的位置)。我通过使用CGRectIntersectsRect
以及CGRectGetMaXY
和CGRectGetMinY
来计算所需的移动距离。
但是,也有可能在已经受影响的 UIView 下方存在第三个甚至更多 UIViews
,它也可能需要被移动。我的问题是我不能
a) 以正确的顺序(按其 Y 原点排序)将所有受影响的 UIViews
移动到移动的 UIView
(而不是快照的 UIView
)下方。
b) 仅基于它们上方的UIView
移动UIViews
,而不受卡入到位的UIView
的影响(即使移动距离可能相同)。
我目前的尝试是在捕捉后获得一个与移动的UIView
相交的UIView
,将UIView
和所需的移动距离作为字典添加到数组中,然后在其下方添加其他UIViews
使用递归。然而,有时,UIViews
会因为它们在视图层次结构中的顺序而被错误地移动,或者它们甚至根本没有移动。
这是一个例子:
带有框架的 UIView A =0 0; 269 132
带有框架的 UIView B = 0 205.5; 63.5 63.5
UIView C 与 frame = 137 137; 132 132
对齐到 0 0; 132 132
边框间距为 5 像素
当UIView
C 卡入到位时,UIView A 应该移动到0 137; 269 132
,因为所需的移动距离是 UIView C 的全高 + 边框间距。但是将UIView
A 移动到新位置也会影响UIView
B,然后将0 274; 63.5 63.5
移动到UIView
A 的一半高度+边框间距,删除UIView
A 和B 之间的空间。
这是另一个例子:
带有框架的 UIView A =0 0; 269 132
带有框架的 UIView B = 0 205.5; 63.5 63.5
UIView C 与 frame = 0 274; 269 269
对齐到 0 68.5; 269 269
当UIView
C 移动到位时,UIView A 移动到 0 274; 269 132
,然后影响 UIView
B 并将其移动到 0 411; 63.5 63.5
,删除之前 UIView
A 和 B 之间的空间。
【问题讨论】:
在您的第一个示例中,您的意思是说您的 UIView A 的帧大小从 269,132 变为 132,132?那是对的吗?我假设这些是框架的宽度/高度。 在你的第二个例子中,在 UIView C 移动到位,UIView A 移动后,C 和 A 重叠? UIView 大小没有改变。那是个错误,我已经改正了。在第二个例子中,当 UIView C 移动到位时,它与 A 和 B 都重叠,因此需要向下移动。 【参考方案1】:这是我正在使用的 Objective-C 实现,基于 Daniel T. 的回答和他的伪代码。我接受了他的回答,因为他提供了实际的解决方案。仅供参考。
- (void)moveAffectedViewsForView:(UIView*)movedView
NSMutableArray* stack = [NSMutableArray new];
[stack addObject:movedView];
while ([stack count] > 0)
UIView* current = [stack objectAtIndex:0];
[stack removeObject:current];
for (UIView* view in [self subviews])
if (view != current && CGRectIntersectsRect(current.frame, view.frame))
[stack addObject:view];
CGFloat moveDistance = (CGRectGetMaxY(current.frame) - CGRectGetMinY(view.frame)) + 5;
[view setFrame:CGRectOffset(view.frame, 0, moveDistance)];
【讨论】:
【参考方案2】:您可能需要设置一个先进先出的堆栈。算法看起来像这样(不是有效的 Obj-C 代码!):
move viewC
[stack addObject: viewC]
while stack.isEmpty == false
current = stack[0]
remove current from stack
for view in allViews
if view != current and view needs to move because of current's position
[stack addObject: view]
move view to correct position
上面将首先将 viewC 移动到它的新位置,然后扫描除 viewC 之外的所有视图,并在必要时将它们从 viewC 下移出。每个被移动的视图都将被添加到堆栈中。
然后它会遍历所有由于 viewC 的新位置而移动的视图,并检查是否有任何尚未移动的视图因为 那个 视图的新位置而必须移动。等等……
-- 编辑--
经过反思,我认为您不需要跟踪访问过哪些视图。我更新了算法以删除该步骤。
【讨论】:
以上是 Dijkstra 寻路算法的一种变体,但重新用于视图移动。 这个算法运行得非常好。比我尝试过的任何东西都要好得多。非常感谢您的帮助!以上是关于通过在它们上方移动另一个 UIView 来获取所有 UIViews的主要内容,如果未能解决你的问题,请参考以下文章
在 `UIViewController` 上方添加 `UIView`
通过包含另一个 firstResponder(一个 UITextView)来创建一个 firstResponder UIView