UIView 건너뛰기

14587 단어 SwiftiOS
UIViewuserInteractionEnabled = true시 응답기 체인이 정지되어 공사가 아래 보기로 전달되지 않습니다.따라서 UIView의 일부 헤더를 비활성화하고 다음 뷰에 헤더를 전달하려고 합니다.어떻게 하면 좋을까요?

잘못된 헤더 영역 만들기


UIViewhitTest:withEvent:를 만드는 방법으로 헤드셋 반응 구역을self로 되돌려줍니다.잘못된 헤더 영역이 nil로 돌아가므로 UIView를 간단히 건너뛸 수 있습니다.참고로 이번 헤드셋 무효 구역은 UIBezier Path로 제작되었습니다.UIBezierPath에는 containsPoint: 방법이 있는데, 지역판정에서 이 방법을 사용하면 상당히 편리하다.
HollowView.swift
import UIKit

class HollowView: UIView {

    override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
        let radius = 100.0 as CGFloat
        let path = UIBezierPath(ovalInRect: self.bounds)
        if path.containsPoint(point) {
            return nil
        }
        return self
    }
}
시도해보면 한가운데 원 부분만 헤드셋이 반응하지만, 사각 헤드셋이 UIView에 멈춰 있는 것을 확인할 수 있다.다만, 이것을 본 목적은 이해하기 어렵다.차근차근 인상을 주는 것도 좋지만 처음부터 자신의 인상을 하나하나 표현하고 싶었다.

외관상으로도 뛰어나다


외관상으로 말하자면, 소뿔을 파고드는 것은 쉽지 않다.예를 들어 UITTableView에 HollowView라고 명명된 사각시도를 놓고 중심 부분을 원만하게 추출한다.
HollowView.swift
import UIKit

class HollowView: UIView {

    var hollowRadius = 60.0 as CGFloat
    lazy var hollowPoint: CGPoint = {
        return CGPoint(
            x: CGRectGetWidth(self.bounds) / 2.0,
            y: CGRectGetHeight(self.bounds) / 2.0
        )
        }()

    lazy var hollowLayer: CALayer = {
        // 繰り抜きたいレイヤーを作成する(今回は例として半透明にした)
        let hollowTargetLayer = CALayer()
        hollowTargetLayer.bounds = self.bounds
        hollowTargetLayer.position = CGPoint(
            x: CGRectGetWidth(self.bounds) / 2.0,
            y: CGRectGetHeight(self.bounds) / 2.0
        )
        hollowTargetLayer.backgroundColor = UIColor.blackColor().CGColor
        hollowTargetLayer.opacity = 0.5

        // 四角いマスクレイヤーを作る
        let maskLayer = CAShapeLayer()
        maskLayer.bounds = hollowTargetLayer.bounds

        // 塗りを反転させるために、pathに四角いマスクレイヤーを重ねる
        let ovalRect =  CGRect(
            x: self.hollowPoint.x - self.hollowRadius,
            y: self.hollowPoint.y - self.hollowRadius,
            width: self.hollowRadius * 2.0,
            height: self.hollowRadius * 2.0
        )
        let path =  UIBezierPath(ovalInRect: ovalRect)
        path.appendPath(UIBezierPath(rect: maskLayer.bounds))

        maskLayer.fillColor = UIColor.blackColor().CGColor
        maskLayer.path = path.CGPath
        maskLayer.position = CGPoint(
            x: CGRectGetWidth(hollowTargetLayer.bounds) / 2.0,
            y: CGRectGetHeight(hollowTargetLayer.bounds) / 2.0
        )
        // マスクのルールをeven/oddに設定する
        maskLayer.fillRule = kCAFillRuleEvenOdd
        hollowTargetLayer.mask = maskLayer
        return hollowTargetLayer
    }()

    override func awakeFromNib() {
        super.awakeFromNib()
        self.backgroundColor = UIColor.clearColor()
    }

    override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
        let rect = CGRect(
            x: self.hollowPoint.x - self.hollowRadius,
            y: self.hollowPoint.y - self.hollowRadius,
            width: self.hollowRadius * 2.0,
            height: self.hollowRadius * 2.0
        )
        let hollowPath = UIBezierPath(roundedRect: rect, cornerRadius: self.hollowRadius)
        if !CGRectContainsPoint(self.bounds, point) || hollowPath.containsPoint(point) {
            return nil
        }
        return self
    }

    override func layoutSublayersOfLayer(layer: CALayer!) {
        layer.addSublayer(self.hollowLayer)
    }
}
이런 게 나왔어요.
hitTest:withEvent에서 원형과 HollowView 바깥쪽의 터치가 효과적이다.내 생각에 중요한 것은 maskLayer의 kCAFiller EvenOdd이다.이벤트/od 규칙이기 때문에 UIBezierPath의 중첩으로 칠하고 칠한 부분이 아닌 것으로 판정됩니다.

샘플 코드

  • morizotter/HollowUIViewSample
  • 참고 자료

  • ios - Cut Out Shape with Animation - Stack Overflow
  • 좋은 웹페이지 즐겨찾기