如何检查多个 UIView 子视图相互重叠显示的贝塞尔路径内的触摸事件?

Posted

技术标签:

【中文标题】如何检查多个 UIView 子视图相互重叠显示的贝塞尔路径内的触摸事件?【英文标题】:How do I check multiple UIView subviews displayed on top of each other for a touch event inside a bezier path? 【发布时间】:2018-08-26 12:09:53 【问题描述】:

我编写了一些代码,在 UIViews 中生成一个***的楔形,将这些 UIViews 存储在一个数组中,并在一个容器 UIView 内将这些 UIViews 彼此叠加显示。这基本上绘制了一个分段的***。

我现在想要的是让每个 UIView 在其定义的贝塞尔路径中单独接收触摸事件,并返回一个唯一标识符。这实际上意味着滚轮的每个楔形都是一个单独的按钮。

我现在遇到的问题是,只有添加到数组中的最后一个 UIView 响应单个触摸事件(我现在将其设置为在贝塞尔路径中打印触摸位置),之后 UIView在响应单个触摸事件之前添加,直到我循环遍历所有楔形/UIView 并且不再响应触摸事件。

这是绘制楔子的类;我已经尝试实现一些方法,这些方法应该允许在代码末尾将触摸事件传输到其他 UIView,但我无法让它工作。

import UIKit

class WedgeDraw: UIView 

var wedgeNumber:CGFloat = 4
var wedgeLocation: CGFloat = 2

var wedgeIdentifier = 0
var wedgePath = UIBezierPath()
var touchPosition = CGPoint()


override func draw(_ rect: CGRect) 

    let startAngle = (360 / wedgeNumber - 360) * (wedgeLocation - 1) * CGFloat.pi / 180
    let endangle = (360 / wedgeNumber - 360) * wedgeLocation * CGFloat.pi / 180


    let center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)

    let outerRadius = self.bounds.midX - 3
    let innerRadius = self.bounds.width / 8

    //defines end points of simulated Bezier archs as a CGpoint
    let endPointInner = UIBezierPath(arcCenter: center, radius: innerRadius, startAngle: startAngle, endAngle: endangle, clockwise: false).currentPoint
    let endPointOuterCounterclockwise = UIBezierPath(arcCenter: center, radius: outerRadius, startAngle: endangle, endAngle: startAngle, clockwise: true).currentPoint

    //defines bezier arch curves
    let outerWedgeCurvePath = UIBezierPath(arcCenter: center, radius: outerRadius, startAngle: startAngle, endAngle: endangle, clockwise: true)
    let innerWedgeCurvePath = UIBezierPath(arcCenter: center, radius: innerRadius, startAngle: endangle, endAngle: startAngle, clockwise: false)

    //draw line path

    wedgePath.append(outerWedgeCurvePath)
    wedgePath.addLine(to: endPointInner)
    wedgePath.append(innerWedgeCurvePath)
    wedgePath.addLine(to: endPointOuterCounterclockwise)

    //sets stroke and color properties and draws the bezierpath.

    UIColor.black.setStroke()
    UIColor.white.setFill()
    wedgePath.lineWidth = 3
    wedgePath.stroke()
    wedgePath.fill()




override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? 
    let view = super.hitTest(point, with: event)
    if wedgePath.contains(touchPosition) 
        return nil
     else 
        return view
    


override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) 

    if let touch = touches.first 
        touchPosition = touch.location(in: self)

        if wedgePath.contains(touchPosition)
            print(touchPosition)
            print(isUserInteractionEnabled)
         else 

        
    


这是创建数组并绘制***的 Viewcontroller 代码:

import UIKit

class ViewController: UIViewController 

@IBOutlet weak var boardContainer: UIView!

@IBAction func checkButton(_ sender: UIButton) 



var wedgeViewConstructorArray = [WedgeDraw]()


override func viewDidLoad() 
    super.viewDidLoad()

    //creates array of UNIQUE wedgedraw objects
    for _ in 1...6 
        wedgeViewConstructorArray.append(WedgeDraw())
    
    drawBoard()


func drawBoard() 

    for i in 0..<wedgeViewConstructorArray.count 
        wedgeViewConstructorArray[i].wedgeIdentifier = i

        wedgeViewConstructorArray[i].frame = CGRect(x: 0, y: 0, width: boardContainer.frame.width, height: boardContainer.frame.height)

        wedgeViewConstructorArray[i].wedgeNumber = CGFloat(wedgeViewConstructorArray.count)
        wedgeViewConstructorArray[i].wedgeLocation = CGFloat(i + wedgeViewConstructorArray.count + 1)
        wedgeViewConstructorArray[i].backgroundColor = UIColor.clear

        boardContainer.addSubview(wedgeViewConstructorArray[i])
    
  

这是***的渲染图,以及视图层次结构:

Wheelimage

总的来说,我对 swift 和编码还是很陌生,我很高兴能到达现在的位置,但我现在真的被困住了,不知道如何继续。我希望我已经设法弄清楚我的问题是什么! 提前致谢!

【问题讨论】:

不同命中检测方法的相关问题:***.com/q/50697037/1630618 【参考方案1】:

好的,我花了一段时间才找到答案,但实际上非常简单。 这就是我现在得到的,它完美地满足了我的需要。

    // checks if point inside touch event is inside bezier path and passes on to next subview if false.
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool 
            let location = point
            if wedgePath.contains(location) == true 
                print("\(wedgeColor)")
                return true


    
    return false


【讨论】:

以上是关于如何检查多个 UIView 子视图相互重叠显示的贝塞尔路径内的触摸事件?的主要内容,如果未能解决你的问题,请参考以下文章

+[UIView transitionFromView:toView:...] 有多个视图

重叠的 UIView - 如何接收触摸?

子视图重叠的问题

重叠的透明 UIView

多个 UIView 的重叠

UIView transitionWithView 带有多个xib文件的子视图