2017-05-01 2 views
1

というタイトルで「self.view」と表示され、mask(リンク)プロパティに別のビューが追加されます。self.viewを使用すると、addSubviewマスクは除去される。何故ですか?ありがとうマスクビューを持つビューにサブビューを追加すると、

私はもともとthis問題を抱えており、maskビューがリリースされていることに気付きました。

私の例では、addViewの画面をタップするとUIBezierPathにアニメーション化できるアニメーション化可能なUIImageViewが追加されています。ここ

コードがある:あなたのマスクがある

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倍の大きさであることだけですので、あなたはすべてのものを見ることができるので、それは常に全体の事をカバーしています。そこに翻訳されることはありませんので、このコードは、あなたのハンドラ内で他に何も処理されていないことを意味する、ヒットを取得されることはありません.began

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

:あなたはあなたのコードにバグがあります。このコードは、panStartedフラグを設定するだけです。

マスクを有効にするにはかなりの時間をかけなければなりません。リリースすると、ビューのサイズの2.1倍に戻ります。

マスクの代わりに円をサブビューとして追加すると、これを簡単に確認できます。 0.5ですべて2.1の値を交換することはあなたにこの効果を与える:

enter image description here

だから要約すると、そこにあなたのマスクには何の問題もないのですが、周囲のコードで。

+0

あなたは[ここ](https://youtu.be/UtNuc8nicgs) 'self.view'にビューを追加する前の希望の動作?私は上記の私の前のポストでこれをリンクしました。私はその中心が 'self.view'の底にあるサークルを持っているので2.1を使用しています。もし私がビュー全体をカバーしたいのであれば、半径はビューの高さにする必要があります。 'UIImageView'sをスクリーンに追加する前後に私のビュー階層を見ると、マスクはその前に、そして後にあります。 – user1974368

+0

あなたが2.1で残っていても、私が言及したバグを十分にパンして修正すると、マスクが有効になりますが、パンが終了すると常に元に戻ります。問題は、消えていくマスクではありません。サブビューを追加するとマスクが消えません。 – jrturton

+0

'.begin'には翻訳があります。だから私はバグがあると言う理由を理解していない。パンが完成したらフルサイズに戻すようにプログラムしました。ビューを画面に追加する前後に 'View UI Hierarchy'デバッグモードを見ると、マスクはその前に、そして後にあります。私は論理的な理由はないと理解していますが、それは私のために起こります。 – user1974368

関連する問題