2016-03-16 2 views
0

Я создал «подсказку», которая имеет UILabel и UIView с CAShapeLayer для формы треугольника. Я установил «подсказку», чтобы метка была сверху, а треугольник прикреплен к нижней и центрирован на UILabel.Автоматическая компоновка и UIViewAnimation - Разрыв между двумя связанными видами

Когда я показываю «подсказку», я использую UIViewAnimation с пружинным демпфированием и весной Velocity, чтобы придать ему «поп-анимацию». Это прекрасно работает с одним исключением, небольшой зазор можно заметить между треугольником и UILabel во время начала анимации (которая затем фиксируется, когда анимация заканчивается.

Любые предложения о том, как это исправить?

Вот установка вид/ограничение:

let containerView = UIView() 
    containerView.alpha = 1.0 
    containerView.layer.cornerRadius = 5.0 
    containerView.clipsToBounds = true 
    containerView.backgroundColor = UIColor.orangeColor() 
    self.addSubview(containerView) 
    self.containerView = containerView 

    let titleLabel = UILabel() 
    titleLabel.font = UIFont.systemFontOfSize(14.0) 
    titleLabel.textColor = UIColor.whiteColor() 
    titleLabel.numberOfLines = 0 
    titleLabel.adjustsFontSizeToFitWidth = true 
    containerView.addSubview(titleLabel) 
    self.titleLabel = titleLabel 

    let triangleView = UIView() 
    self.addSubview(triangleView) 
    self.triangleView = triangleView 

    let views: [String: UIView] = [ 
     "containerView" : containerView, 
     "titleLabel" : titleLabel, 
     "triangleView" : triangleView, 
    ] 
    let metrics = [String:AnyObject]() 
    for (_, view) in views { 
     view.translatesAutoresizingMaskIntoConstraints = false 
    } 

    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|-8-[titleLabel]-8-|", options: [], metrics: metrics, views: views)) 
    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-8-[titleLabel]-8-|", options: [], metrics: metrics, views: views)) 

    let widthConstraint = NSLayoutConstraint(item: self, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 0) 
    widthConstraint.active = true 
    self.widthConstraint = widthConstraint 

    let heightConstraint = NSLayoutConstraint(item: self, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 0) 
    heightConstraint.active = true 
    self.heightConstraint = heightConstraint 

    let trianglePath = UIBezierPath() 
    trianglePath.moveToPoint(CGPoint(x: 0, y: 0)) 
    trianglePath.addLineToPoint(CGPoint(x: 8.0, y: 10.0)) 
    trianglePath.addLineToPoint(CGPoint(x: 16.0, y: 0)) 
    trianglePath.closePath() 

    let mask = CAShapeLayer() 
    mask.frame = triangleView.bounds 
    mask.path = trianglePath.CGPath 
    triangleView.layer.mask = mask 

    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[containerView][triangleView]|", options: [], metrics: metrics, views: views)) 
    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|[containerView]|", options: [], metrics: metrics, views: views)) 
    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("|-(>=8)-[self]-(>=8)-|", options: [], metrics: metrics, views: views)) 
    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-(>=8)-[self][anchorView]", options: [], metrics: metrics, views: views)) 

    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("[triangleView(>=16)]", options: [], metrics: metrics, views: views)) 
    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[triangleView(>=10)]", options: [], metrics: metrics, views: views)) 

    NSLayoutConstraint(item: self.triangleView, attribute: .CenterX, relatedBy: .Equal, toItem: self.anchorView, attribute: .CenterX, multiplier: 1.0, constant: 1.0).active = true 

    let centerXConstraint = NSLayoutConstraint(item: triangleView, attribute: .CenterX, relatedBy: .Equal, toItem: containerView, attribute: .CenterX, multiplier: 1.0, constant: 0.0) 
    centerXConstraint.priority = UILayoutPriorityDefaultLow // Required to allow tooltip to grow beyond anchorView bounds without changing the anchorView constraints. 
    centerXConstraint.active = true 

Вот анимация сценарий:

self.layoutIfNeeded() // Set starting position for tooltip before animation 

    self.widthConstraint.active = false 
    self.heightConstraint.active = false 

    UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: .CurveEaseInOut, animations: {() -> Void in 
     self.alpha = 1.0 
     self.layoutIfNeeded() 
     }, completion: nil) 

Видео: enter image description here

+0

Можете ли вы PLS опубликовать скриншот или gif о том, с какой ошибкой вы столкнулись? –

+0

Вместо того, чтобы удалять ограничение, попытались ли вы установить ограничение на требуемую высоту и ширину? например 'self.widthConstraint.constant = // label width' и' self.heightConstraint.constant = // label height', а затем анимация 'layoutIfNeeded()' – sketchyTech

+0

@ SohilR.Memon GIF добавлен. Качество плохое, но во время анимации вы можете увидеть промежуток между треугольником и куском всплывающей подсказки. – JimmyJammed

ответ

0

Один из способов приблизиться было бы иметь обычай UILabel

class ToolTip: UILabel { 
    var roundRect:CGRect! 
    override func drawTextInRect(rect: CGRect) { 
     super.drawTextInRect(roundRect) 
    } 
    override func drawRect(rect: CGRect) { 
     roundRect = CGRect(x: rect.minX, y: rect.minY, width: rect.width, height: rect.height * 4/5) 
     let roundRectBez = UIBezierPath(roundedRect: roundRect, cornerRadius: 10.0) 
     let triangleBez = UIBezierPath() 
     triangleBez.moveToPoint(CGPoint(x: roundRect.minX + roundRect.width/2.5, y:roundRect.maxY)) 
     triangleBez.addLineToPoint(CGPoint(x:rect.midX,y:rect.maxY)) 
     triangleBez.addLineToPoint(CGPoint(x: roundRect.maxX - roundRect.width/2.5, y:roundRect.maxY)) 
     triangleBez.closePath() 
     roundRectBez.appendPath(triangleBez) 
     let bez = roundRectBez 
     UIColor.lightGrayColor().setFill() 
     bez.fill() 
     super.drawRect(rect) 
    } 
} 

, а затем выполнить компоновку и анимации, как так:

import UIKit 

class ViewController: UIViewController { 

    var label:ToolTip! 
    var labelTransform:CGAffineTransform! 
    let buttonHeight:CGFloat = 100 
    let buttonWidth:CGFloat = 200 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     let button = UIButton() 
     button.setTitle("Push Me", forState: .Normal) 
     button.addTarget(self, action: Selector("buttonPushed"), forControlEvents: .TouchUpInside) 
     button.backgroundColor = UIColor.orangeColor() 
     view.addSubview(button) 
     button.translatesAutoresizingMaskIntoConstraints = false 
     button.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true 
     button.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor).active = true 
     button.heightAnchor.constraintEqualToConstant(buttonHeight).active = true 
     button.widthAnchor.constraintEqualToConstant(buttonWidth).active = true 

     label = ToolTip() 

     view.insertSubview(label, belowSubview: button) 
     label.translatesAutoresizingMaskIntoConstraints = false 
     label.heightAnchor.constraintEqualToConstant(buttonHeight).active = true 
     label.widthAnchor.constraintEqualToConstant(buttonWidth).active = true 


     label.bottomAnchor.constraintEqualToAnchor(button.topAnchor).active = true 
     label.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true 
     label.text = "This button is orange!" 
     label.textColor = UIColor.whiteColor() 
     label.textAlignment = .Center 
     let trans1 = CGAffineTransformMakeScale(0, 0) 
     let trans2 = CGAffineTransformMakeTranslation(0, buttonHeight) 
     labelTransform = CGAffineTransformConcat(trans1, trans2) 
     label.transform = labelTransform 

    } 

    func buttonPushed() { 

     if label.transform.ty > 0 { 
      UIView.animateWithDuration(0.75, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: .CurveEaseInOut, animations: {() -> Void in 

       self.label.transform = CGAffineTransformIdentity 

       }, completion: nil) 

     } 
     else { 
      UIView.animateWithDuration(0.5, delay: 0, options: .CurveEaseInOut, animations: {() -> Void in 
       self.label.alpha = 0 

       }, completion: {_ in 
        self.label.transform = self.labelTransform 
        self.label.alpha = 1 
      })  } 



    } 

} 

который создает последующую эффект: Popup tooltip

+0

Отличный ответ! Тем не менее, имеет один последний вопрос, который позволяет метке изменять размер предоставленного текста и не ограничиваться размером anchorView (UIButton в вашем примере). Предложения? – JimmyJammed

+0

, если вы уберете анкеры ширины и высоты кнопки или метки, они изменят размер текста. Однако то, что вы, вероятно, хотите, это некоторое дополнение к тексту, пропорциональному ему. Вот [gist] (https://gist.github.com/sketchytech/e5920de6c31651b44724), что происходит с использованием ** boundingRectWithSize: ** – sketchyTech

+0

Я попытался добавить эти ограничения, чтобы был минимум, но они никогда не растут являющийся экземпляром ToolTip): – JimmyJammed