2017-05-01 309 views
1

掩模作爲標題說,我有self.view我添加到其mask(鏈路)屬性另一視圖,但是當我添加更多的視圖來self.view使用addSubview面具被刪除。這是爲什麼?謝謝添加一個子視圖到具有掩模圖的圖中刪除從它

我原本有this問題,並意識到mask視圖正在釋放。

在我的示例中,我添加了動畫UIImageView s,當我點擊屏幕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 
    } 


} 
+0

請包括一些代碼,這將使人們重現在操場或類似 – jrturton

+0

@jrturton您的問題添加的代碼,感謝 – user1974368

回答

0

你的面具是存在的,只是它是你的視圖大小的2.1倍,所以它總是覆蓋了整個事情,所以你可以看到一切。你有一個錯誤在你的代碼:

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

.began永遠不會有一個翻譯,所以這個代碼是從來沒有擊中,這意味着沒有別的處理程序進行處理。此代碼應該只設置panStarted標誌。

你必須拖動很長一段時間才能使遮罩生效,當你釋放時,它會彈回到視圖大小的2.1倍。

您可以通過將圓圈添加爲子視圖而不是掩碼來輕鬆看到。與0.5更換所有2.1值給你這樣的效果:

enter image description here

因此,在總結,有什麼不對你的面具的,但與周圍的代碼。

+0

你見過[這裏](https://youtu.be/UtNuc8nicgs),我設法得到將視圖添加到'self.view'之前所需的行爲?我在我上面鏈接的上一篇文章中將其鏈接。我使用2.1是因爲我有一個圓圈,它的中心位於'self.view'的底部,如果我希望它覆蓋整個視圖,我需要半徑與視圖一樣高。當我在屏幕上添加'UIImageView'之前和之後,我看着我的視圖層次結構之前和之後的屏蔽。 – user1974368

+0

即使將2.1留在你身上,如果你平移足夠遠的距離並修復我提到的錯誤,仍然可以看到面具生效,但當平底鍋完成時它總是彈回。你的問題不是消失的面具。添加子視圖時,蒙版不會消失。 – jrturton

+0

在'.begin'中有翻譯。所以我不明白你爲什麼說有一個錯誤。並且我將它編程爲在鍋完成時反彈回全尺寸。當我在查看屏幕之前和之後查看'View UI Hierarchy'調試模式時,掩碼在之前和之後都會出現。我明白這不是合乎邏輯的原因,但它確實發生在我身上。 – user1974368

相關問題