gpt4 book ai didi

ios - 向具有 mask View 的 View 添加 subview 会从中移除 mask

转载 作者:行者123 更新时间:2023-11-28 08:11:09 30 4
gpt4 key购买 nike

正如标题所说,我有 self.view,我将其添加到它的 mask 中(link) 属性另一个 View ,但是当我使用 addSubview 添加更多 View 到 self.view 时,掩码被删除。这是为什么?谢谢

我原来有this问题并意识到正在释放 mask View 。

在我的示例中,我添加了可动画的 UIImageView,当我在 addView 中点击屏幕时,它会在 UIBezierPath 上设置动画。

代码如下:

protocol UICircleMaskDelegate {

func circleMaskCompletion()

}

class UICircleMask: UIView {

var delegate: UICircleMaskDelegate?
var gestureDelegate: UIGestureRecognizerDelegate?

init(gestureDelegate: UIGestureRecognizerDelegate? = nil) {
super.init(frame: .zero)
self.gestureDelegate = gestureDelegate
self.clipsToBounds = true
self.backgroundColor = .yellow
self.isUserInteractionEnabled = false
}

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

var diameterConstraint: NSLayoutConstraint?
var animating = false

func updateSize(_ delta: CGFloat, animated: Bool = false) {

if animating { return }
if animated {
animating = true
diameterConstraint?.constant = UIScreen.main.bounds.height * 2.1

let duration: TimeInterval = Double((UIScreen.main.bounds.height - self.frame.height / 2.1) / 600)// duration = way / speed
let animation = CABasicAnimation(keyPath: "cornerRadius")
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
animation.fromValue = self.layer.cornerRadius
animation.toValue = UIScreen.main.bounds.height * 2.1 / 2
animation.duration = duration
self.layer.add(animation, forKey: nil)

UIView.animate(withDuration: duration, delay: 0, options: [.curveEaseOut], animations: {
self.superview?.layoutIfNeeded()
}, completion: { (success) in
if success {
self.animating = false
self.delegate?.circleMaskCompletion()
}
})
} else {
let newSize = diameterConstraint!.constant + (delta * 2.85)
if newSize > 60 && newSize < UIScreen.main.bounds.height * 2.1 {
diameterConstraint?.constant = newSize
}
}

}

var panStarted = false

func handlePan(_ pan: UIPanGestureRecognizer) {
guard let superv = superview else { return }
let delta = pan.translation(in: superv).y
if pan.state == .began {
if delta > 0 {
panStarted = true
updateSize(-delta)
}
} else if pan.state == .changed {
if panStarted {
updateSize(-delta)
}
} else if pan.state == .ended || pan.state == .cancelled {
if panStarted {
updateSize(superv.frame.height * 2.1, animated: true)
panStarted = false
}
}
pan.setTranslation(.zero, in: superv)
}

override func didMoveToSuperview() {
super.didMoveToSuperview()
if let superv = superview {
//
self.makeSquare()
self.centerHorizontallyTo(superv)
let c = NSLayoutConstraint.init(item: self, attribute: .centerY, relatedBy: .equal, toItem: superv, attribute: .bottom, multiplier: 1, constant: -40)
c.isActive = true
diameterConstraint = self.constrainHeight(superv.frame.height * 2.1)
//
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
panGesture.delegate = gestureDelegate
self.superview?.addGestureRecognizer(panGesture)
}
}

override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = self.frame.width / 2
}

}


class ViewController: UIViewController, UIGestureRecognizerDelegate, UICircleMaskDelegate {

override var prefersStatusBarHidden: Bool {
get {
return true
}
}

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}

func circleMaskCompletion() {
// print("nana")
}

override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.init(red: 48/255, green: 242/255, blue: 194/255, alpha: 1)
self.view.clipsToBounds = true

let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
tap.delegate = self
self.view.addGestureRecognizer(tap)

let circleMask = UICircleMask(gestureDelegate: self)
circleMask.delegate = self
self.view.mask = circleMask

}

func handleTap() {
let num = Int(5 + drand48() * 10)
(1 ... num).forEach { (_) in
addView()
}
}

func addView() {

var image: UIImageView!
let dd = drand48()
if dd < 0.5 {
image = UIImageView(image: #imageLiteral(resourceName: "heart1"))
} else {
image = UIImageView(image: #imageLiteral(resourceName: "heart2"))
}

image.isUserInteractionEnabled = false
image.contentMode = .scaleAspectFit
let dim: CGFloat = 20 + CGFloat(10 * drand48())
image.constrainHeight(dim)
image.constrainWidth(dim)

let animation = CAKeyframeAnimation(keyPath: "position")
let duration = Double(1.5 * self.view.frame.width / CGFloat((60 + drand48() * 40))) // duration = way / speed
animation.path = getPath().cgPath
animation.duration = duration
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = false
image.layer.add(animation, forKey: nil)

DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + duration + 1) {
DispatchQueue.main.async {
image.removeFromSuperview()
}
}

if drand48() < 0.3 {
UIView.animate(withDuration: 0.2 + 0.1 * drand48() , delay: TimeInterval(drand48() * 1), options: [.curveEaseOut, .repeat, .autoreverse], animations: {
image.transform = CGAffineTransform.init(scaleX: 1.5, y: 1.5)
}, completion: nil)
}

self.view.addSubview(image)
self.view.sendSubview(toBack: image)

}


func getPath() -> UIBezierPath {

let path = UIBezierPath()

let startPoint = CGPoint.init(x: -30, y: self.view.frame.height / 2)
path.move(to: startPoint)

let r = CGFloat(400 * drand48())
let cp1 = CGPoint.init(x: self.view.frame.width * 0.33, y: self.view.frame.height * 0.25 - r)
let cp2 = CGPoint.init(x: self.view.frame.width * 0.66, y: self.view.frame.height * 0.75 + r)
let endPoint = CGPoint.init(x: self.view.frame.width + 30, y: self.view.frame.height / 2)

path.addCurve(to: endPoint, controlPoint1: cp1, controlPoint2: cp2)

return path

}

}


extension UIView {

func turnOffMaskResizing() {
self.translatesAutoresizingMaskIntoConstraints = false
}


@discardableResult
func makeSquare() -> NSLayoutConstraint {
self.turnOffMaskResizing()
let constraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: self, attribute: NSLayoutAttribute.height, multiplier: 1.0, constant: 0)
NSLayoutConstraint.activate([constraint])
return constraint
}


@discardableResult
func centerHorizontallyTo(_ toItem: UIView, padding: CGFloat) -> NSLayoutConstraint {
self.turnOffMaskResizing()
let constraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: toItem, attribute: NSLayoutAttribute.centerX, multiplier: 1.0, constant: padding)
NSLayoutConstraint.activate([constraint])
return constraint
}


@discardableResult
func constrainHeight(_ height: CGFloat, priority: UILayoutPriority = 1000) -> NSLayoutConstraint {
self.turnOffMaskResizing()
let constraint = NSLayoutConstraint(item: self, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.height, multiplier: 0, constant: height)
constraint.priority = priority
NSLayoutConstraint.activate([constraint])
return constraint
}


}

最佳答案

你的面具就在那里,只是它是你 View 大小的 2.1 倍,所以它总是覆盖整个东西,所以你可以看到一切。您的代码中有错误:

if pan.state == .began {
if delta > 0 {
panStarted = true
circle.updateSize(-delta)
}

.began 处永远不会有翻译,所以这段代码永远不会被命中,这意味着您的处理程序中的任何其他内容都不会被处理。此代码应仅设置 panStarted 标志。

您必须拖动很长一段距离才能使 mask 生效,当您松开时,它会再次弹回到 View 大小的 2.1 倍。

通过将圆添加为 subview 而不是 mask ,您可以很容易地看到这一点。将所有 2.1 值替换为 0.5 会产生以下效果:

enter image description here

所以总而言之,您的掩码没有问题,但周围的代码有问题。

关于ios - 向具有 mask View 的 View 添加 subview 会从中移除 mask ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43716676/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com