【问题标题】:UIView bringSubviewToFront: does *not* bring view to frontUIView bringSubviewToFront: *不*将视图带到前面
【发布时间】:2012-04-04 20:57:53
【问题描述】:

我正在实现一个简单的 iOS 纸牌游戏,它允许用户以通常的方式拖动卡片。卡片用UIView 子类CardView 表示。所有卡片视图都是兄弟姐妹,它们是SolitaireView 的子视图。以下 sn-p 尝试“将卡片放在前面”,以便在拖动时它高于所有其他视图:

-(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 顺序在拖动过程中保持不变。在下面的图片中,我正在拖动国王。注意它是如何正确地位于左图中的九之上,但不正确地位于右图中的二之下(实际上是在整个堆栈之下):

我也尝试更改 layer.zPosition 属性也无济于事。 如何在拖动过程中将卡片视图置于前面?我很困惑。

【问题讨论】:

  • 我发现bringSubviewToFront: 触发了要设置视图的“needsLayout”标志。我的 layoutSubviews 方法也调用了 bringSubviewToFront: 从而将所有视图 z 顺序恢复到初始状态!
  • 那有什么解决办法呢?我也有同样的要求,从卡片列表中,如果我选择任何中间顺序卡片,它应该出现,然后来到前面。但我的动画由于bringSubviewToFront: 方法而无法正常工作
  • 如果您坚持使用 UIView 子类,那么您需要标记正在拖动的卡片,以便 layoutSubviews 可以将其放在顶部。我实际上改用了下面提到的 CALayers。
  • 感谢您的回复。你能把代码放上去吗?
  • 下面列出了一个代码sn-p。

标签: ios uiview uitouch


【解决方案1】:

已确认。 bringSubviewToFront: 导致调用 layoutSubview。由于我的layoutSubviews 版本在所有视图上都设置了z 顺序,这将撤消我在上面的touchesBegan:withEvent 代码中设置的z 顺序。 Apple 应在 bringSubviewToFront 文档中提及此副作用。

我没有使用UIView 子类,而是创建了一个名为CardLayerCALayer 子类。我在KlondikeView 子类中处理触摸,如下所示。 topZPosition 是一个实例变量,它跟踪所有卡片的最高 zPosition。请注意,修改zPosition 通常是动画的——我在下面的代码中将其关闭:

-(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 用于扑克牌可能是一个糟糕的设计选择——我不认为它们真的是为此而设计的。我想我会退后一步,改用CALayer
猜你喜欢
  • 1970-01-01
  • 2014-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-08
相关资源
最近更新 更多