ios - 当多个 UIView 相互重叠时,甚至在顶部 UIView 上拦截点击

标签 ios swift

我有一个填满整个屏幕的 UIView,然后我在该容器 View 中添加了多个小圆圈 UIView,我希望这些小圆圈的 UIView 可以拖动使用 UIPanGestureRecognizer。但有时它们恰好在彼此之上,使得顶部的 UIView 根本不可点击,它总是选择底部的。

在容器 UIView 中,我实现了 hitTest 以便能够仅选择那些 subview 。

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    for planet in self.myPlanets.values {
        if let presentation = planet.layer.presentation(), presentation.frame.contains(point) {
            return planet
        }
    }
    return nil
}

如何让顶部 View 接收点击而不是底部 View ?

最佳答案

我通过创建 UIView 子类、添加 UIPanGestureRecognizer 并根据其输入进行更新来处理可拖动 View 。

使用此方法,无论哪个 View 在顶部都会接收到触摸,并且您不必覆盖父 View 上的 hitTest

如果 View 受限于父 View ,我还添加了一个委托(delegate)来更新约束。通过设置委托(delegate),UIView 或 ViewController(以委托(delegate)为准)可以更新要移动的 View 的约束。

这是一个简单的实现:

// Delegate protocol for managing constraint updates if needed
protocol DraggableDelegate: class {

    // tells the delegate to move
    func moveByTranslation(_ change: CGPoint)
}


class DraggableView: UIView {

    var dragDelegate: DraggableDelegate?

    init() {
        // frame is set later if needed by creator
        super.init(frame: CGRect.zero)
        configureGestureRecognizers()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // setup UIPanGestureRecognizer
    internal func configureGestureRecognizers() {
        let panGR = UIPanGestureRecognizer.init(target: self, action: #selector(didPan(_:)))
        addGestureRecognizer(panGR)
    }

    @objc func didPan(_ panGR: UIPanGestureRecognizer) {

        // get the translation
        let translation = panGR.translation(in: self).applying(transform)

        if let delegate = dragDelegate {

            // tell delegate to move
            delegate.moveByTranslation(translation)

        } else {

            // move self
            self.center.x += translation.x
            self.center.y += translation.y
        }

        // reset translation
        panGR.setTranslation(CGPoint.zero, in: self)
    }
}

下面是我如何使用这个 View 在 View Controller 中实现委托(delegate)回调,因为我的 View 使用了约束:

/// Moves the tool tray when dragging is triggered via the pan gesture recognizer in the tool tray (an instance of DraggableView).
///
/// - Parameter change: The x/y change provided by the pan gesture recognizer.
func moveByTranslation(_ change: CGPoint) {

    // only interested in the y axis movements for this example
    // update the constraint that moves this view
    let newPos = constraint_tooltray_yAxis.constant + change.y

    // this function limited the movement of the view to keep it within bounds
    updateToolTrayPosition(newPos)
}

关于ios - 当多个 UIView 相互重叠时,甚至在顶部 UIView 上拦截点击,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51974299/

相关文章:

ios - 我尝试向我的应用程序添加 map ,但我看到的只是黑屏......为什么?

android - Flutter - 如何将数据从网站解析为 ListView

ios - SpriteKit,Swift - ScrollView 未显示

iphone - 在应用程序中保存图像

java - 为不同的设备生成服务器端图像?

ios - 无法在 UIAlertView 中使用键盘输入

ios - 使用 WKWebView 修改键盘工具栏/附件 View

ios - 类型 'Int' 没有下标成员

swift - Google API map 未显示在 TabBar 应用程序上

ios - 如何解决此错误 : "Undefined symbols for architecture arm64"