ios tutorial Auto-Layout und UIViewAnimation-Abstand zwischen zwei verbundenen Ansichten



xcode constraints tutorial (1)

Ich habe eine "Tooltip" -Ansicht erstellt, die eine UILabel und eine UIView mit einem CAShapeLayer für eine Dreiecksform aufweist. Ich habe die "Tooltip" so eingestellt, dass das Etikett oben ist, mit dem Dreieck an der Unterseite und zentriert auf dem UILabel.

Wenn ich den "Tooltip" zeige, verwende ich die UIViewAnimation mit Spring Damping und Spring Velocity, um eine "Pop" -Animation zu erhalten. Dies funktioniert mit einer Ausnahme sehr gut, eine kleine Lücke kann zwischen dem Dreieck und dem UILabel während des Beginns der Animation bemerkt werden (die dann fixiert wird, wenn die Animation endet).

Irgendwelche Vorschläge, wie Sie das beheben können?

Hier ist das View / Constraint Setup:

    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

Hier ist das Animationsskript:

    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)

Video:


Eine Möglichkeit, sich dem zu nähern, wäre ein benutzerdefiniertes 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)
    }
}

und führe dann Layout und Animation wie folgt aus:

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
            })        }



    }

}

was den folgenden Effekt erzeugt:





uiviewanimation