Swift-UIStackView中的UIPanRecognizer [英] Swift - UIPanRecognizer in a UIStackView

查看:96
本文介绍了Swift-UIStackView中的UIPanRecognizer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在UIStackView中制作一个UIPanRecognizer. 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则是一场噩梦).
我将不胜感激.谢谢.
这可能有帮助吗?

访问嵌套堆栈视图

解决方案

每个标签都是其包含堆栈视图的子视图(也可能是堆栈视图的子视图),并且每个标签都有自己的坐标空间. /p>

假设您将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

            }
        }
    }
}

I want to make a UIPanRecognizer in a UIStackView. The UI looks like this.

There's a big square which is a StackView which contains 9 labels. My goal is when I start to drag my finger within the StackView and if a label contains that touchpoint then its color should be blue and on and on. If I lift my finger all of the labels background color turn back to white.
The labels are in a OutletCollection.
Here's my code:

@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

            }
        }
    }

Right now when I touch for example the top-left square and start to drag my finger to the right the whole first column turns blue then the second then the third. That happens when I touch any labels of the first row, but nothing happens when I touch the other squares.
First time, I tried to solve my problem by handle the squares just as an OutletCollection (without the StackView) and the recognizer just worked fine! The reason why I experiment with the StackView that it's so easier to make the layout(just a few constraints needed, without the StackView it is a nightmare).
I'd appreciate any help. Thank you.
Edit: probably this one helps?

Access nested stack views

解决方案

Each label is a subview of its containing stack view (which is also probably a subview of a stack view), and each label has its own coordinate space.

Assuming your UIPanGestureRecognizer is assigned to the view controller's view, you need to translate the coordinates / frames.

This should work for you:

@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

            }
        }
    }
}

You can also simplify your code a bit by using for object in collection instead of indices. This is functionally the same as above, but maybe a little simpler:

@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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆