斯威夫特 - UIPanRecognizer在UIStackView(Swift - UIPanR

2019-10-29 05:56发布

我想打一个UIPanRecognizer在UIStackView。 该UI看起来是这样的。

有一个大的广场,是包含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它是一场噩梦)。
我会很感激的任何帮助。 谢谢。
编辑:这可能是一个帮助?

访问嵌套的堆栈意见

Answer 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 - UIPanRecognizer in a UIStackView