Swift - UIStackView 中的 UIPanRecognizer

Posted

技术标签:

【中文标题】Swift - UIStackView 中的 UIPanRecognizer【英文标题】:Swift - UIPanRecognizer in a UIStackView 【发布时间】:2018-08-19 21:21:13 【问题描述】:

我想在 UIStackView 中创建一个 UIPanRecognizer。 The UI looks like this.

有一个大方块,它是一个包含 9 个标签的 StackView。 我的目标是当我开始在 StackView 中拖动手指时,如果标签包含该接触点,那么它的颜色应该是蓝色的,并且一直亮着。如果我抬起手指,所有标签的背景颜色都会变回白色。 标签位于 OutletCollection 中。 这是我的代码:

@IBOutlet var testLabels: [UILabel]!
@IBAction func handlePan(recognizer:UIPanGestureRecognizer) 
    var touchedPoint: CGPoint!
    if let view = recognizer.view
        if recognizer.state == .began || recognizer.state == .changed 
            touchedPoint = recognizer.location(in: view)
            for index in testLabels.indices 

                if testLabels[index].frame.contains(touchedPoint) 

                    testLabels[index].backgroundColor = UIColor.blue

                
            
        
        if recognizer.state == .ended 
            for index in testLabels.indices 

                testLabels[index].backgroundColor = UIColor.white

            
        
    

现在,例如,当我触摸左上角的正方形并开始向右拖动手指时,整个第一列会变成蓝色,然后是第二列,然后是第三列。当我触摸第一行的任何标签时会发生这种情况,但当我触摸其他方块时什么也不会发生。 第一次,我尝试通过将正方形作为 OutletCollection(没有 StackView)处理来解决我的问题,并且识别器工作得很好!我尝试使用 StackView 的原因是它更容易制作布局(只需要一些约束,没有 StackView 是一场噩梦)。 我会很感激任何帮助。谢谢。编辑:这可能有帮助吗?

Access nested stack views

【问题讨论】:

【参考方案1】:

每个标签都是其包含的堆栈视图的子视图(也可能是堆栈视图的子视图),每个标签都有自己的坐标空间。

假设您的UIPanGestureRecognizer 分配给视图控制器的视图,您需要转换坐标/帧。

这应该适合你:

@IBAction func handlePan(recognizer:UIPanGestureRecognizer) 
    var touchedPoint: CGPoint!

    if let view = recognizer.view

        if recognizer.state == .began || recognizer.state == .changed 

            touchedPoint = recognizer.location(in: view)

            for index in testLabels.indices 

                // translate / convert the label's bounds from its frame to the view's coordinate space
                let testFrame = view.convert(testLabels[index].bounds, from:testLabels[index] )

                // check the resulting testFrame for the point                  
                if testFrame.contains(touchedPoint) 

                    testLabels[index].backgroundColor = UIColor.blue

                
            
        
        else if recognizer.state == .ended 
            for index in testLabels.indices 

                testLabels[index].backgroundColor = UIColor.white

            
        
    

您还可以使用for object in collection 代替索引来稍微简化您的代码。这在功能上与上面相同,但可能更简单一些:

@IBAction func handlePan(recognizer:UIPanGestureRecognizer) 
    var touchedPoint: CGPoint!

    if let view = recognizer.view

        if recognizer.state == .began || recognizer.state == .changed 

            touchedPoint = recognizer.location(in: view)

            for lbl in testLabels 

                // translate / convert the label's bounds from its frame to the view's coordinate space
                let testFrame = view.convert(lbl.bounds, from:lbl )

                // check the resulting testFrame for the point
                if testFrame.contains(touchedPoint) 

                    lbl.backgroundColor = .blue

                
            
        
        else if recognizer.state == .ended 
            for lbl in testLabels 

                lbl.backgroundColor = .white

            
        
    

【讨论】:

以上是关于Swift - UIStackView 中的 UIPanRecognizer的主要内容,如果未能解决你的问题,请参考以下文章

UIStackView中的圆形按钮(iOS Swift)

Swift:在 UIWebview Scroll 上隐藏 UIStackView

查找由 UIStackView swift 调整的视图的大小

Swift UIStackView 利用 UIStackView 的全宽

强制视图在 UIStackView 中占用尽可能多的空间

如何在 UIStackView 中切换排列子视图的可见性,这在 tableViewCell swift3 中