UIView BringSubviewToFront:*不* 将视图带到前面 [英] UIView bringSubviewToFront: does *not* bring view to front
问题描述
我正在实现一个简单的 iOS 纸牌游戏,它允许用户以通常的方式拖动卡片.卡片由 UIView
子类 CardView
表示.所有卡片视图都是兄弟视图,它们是 SolitaireView
的子视图.下面的代码片段试图将卡片放在前面",以便它在被拖动时位于所有其他视图之上:
I am implementing a simple iOS solitaire game that allows the user to drag the cards around in the usual way. The cards are represented with the UIView
subclass CardView
. All the card view's are siblings which are subviews of SolitaireView
. The following snippet tries to "bring a card to the front" so that it is above all the other views as it is being dragged:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if (touch.view.tag == CARD_TAG) {
CardView *cardView = (CardView*) touch.view;
...
[self bringSubviewToFront:cardView];
...
}
}
不幸的是,在拖动过程中卡片的 z-order 保持不变.在下面的图片中,我正在拖动国王.请注意它是如何正确地位于左图中的九个顶部,但在右侧图像中错误地位于两个下方(实际上是整个堆栈下方):
Unfortunately, the card's z-order remains unchanged during the drag. In the images below, I am dragging the King. Notice how it is correctly on top the Nine in the left image, but is incorrectly under the Two (under the entire stack actually) in the right image:
我也尝试更改 layer.zPosition
属性,但无济于事.如何在拖动过程中将卡片视图带到前面?我很困惑.
I also tried alter the layer.zPosition
property as well to no avail.
How can I bring the card view to the front during the drag? I am mystified.
推荐答案
已确认.bringSubviewToFront:
导致 layoutSubview
被调用.由于我的 layoutSubviews
版本在所有视图上设置了 z-orders,这会撤销我在上面的 touchesBegan:withEvent
代码中设置的 z-order.Apple 应该在 bringSubviewToFront
文档中提及这种副作用.
Confirmed. bringSubviewToFront:
causes layoutSubview
to be invoked. Since my version of layoutSubviews
sets the z-orders on all the views, this was undoing the z-order I was setting in the touchesBegan:withEvent
code above. Apple should mention this side effect in the bringSubviewToFront
documentation.
我没有使用 UIView
子类,而是创建了一个名为 CardLayer
的 CALayer
子类.我在我的 KlondikeView
子类中处理触摸,如下所示.topZPosition 是一个实例变量,用于跟踪所有卡片的最高 zPosition.请注意,修改 zPosition
通常是动画的——我在下面的代码中将其关闭:
Instead of using a UIView
subclass, I created a CALayer
subclass named CardLayer
. I handle the touch in my KlondikeView
subclass as listed below. topZPosition is an instance var that tracks the highest zPosition of all cards. Note that modifying the zPosition
is usually animated -- I turn this off in the code below:
-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
CGPoint hitTestPoint = [self.layer convertPoint:touchPoint
toLayer:self.layer.superlayer];
CALayer *layer = [self.layer hitTest:hitTestPoint];
if (layer == nil) return;
if ([layer.name isEqual:@"card"]) {
CardLayer *cardLayer = (CardLayer*) layer;
Card *card = cardLayer.card;
if ([self.solitaire isCardFaceUp:card]) {
//...
[CATransaction begin]; // disable animation of z change
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
cardLayer.zPosition = topZPosition++; // bring to highest z
// ... if card fan, bring whole fan to top
[CATransaction commit];
//...
}
// ...
}
}
这篇关于UIView BringSubviewToFront:*不* 将视图带到前面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!