简体   繁体   English

自动布局和UIViewAnimation-两个连接的视图之间的间隙

[英]Auto layout and UIViewAnimation - Gap between two connected views

I created a "tooltip" view that has a UILabel and an UIView with a CAShapeLayer for a triangle shape. 我创建了一个“工具提示”视图,该视图具有一个UILabel和一个带有CAShapeLayer的三角形的UIView。 I have setup the "tooltip" so that the label is on top, with the triangle attached to the bottom and centered on the UILabel. 我已经设置了“工具提示”,以便标签在顶部,三角形连接在底部,并在UILabel上居中。

When I show the "tooltip", I use the UIViewAnimation with Spring Damping and Spring Velocity to give it a "pop" animation. 当显示“工具提示”时,我将UIViewAnimation与Spring Damping和Spring Velocity一起使用,以使其具有“ pop”动画。 This works great with one exception, a small gap can be noticed between the triangle and the UILabel during the beginning of the animation (which is then fixed when the animation ends. 这很好用,但有一个例外,在动画开始时可以注意到三角形和UILabel之间的间隙很小(然后在动画结束时固定该间隙。

Any suggestions on how to fix this? 对于如何解决这个问题,有任何的建议吗?

Here is the 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

Here is the animation script: 这是动画脚本:

    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: 视频: 在此处输入图片说明

One way to approach it would be to have a custom UILabel 一种解决方法是拥有自定义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)
    }
}

and then perform layout and animation like so: 然后像这样执行布局和动画:

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



    }

}

which creates the follow effect: 产生以下效果: 弹出工具提示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM