自动布局和 UIViewAnimation - 两个连接视图之间的间隙 [英] Auto layout and UIViewAnimation - Gap between two connected views

查看:25
本文介绍了自动布局和 UIViewAnimation - 两个连接视图之间的间隙的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个工具提示"视图,它有一个 UILabel 和一个带有 CAShapeLayer 的 UIView 用于三角形.我已经设置了工具提示",以便标签位于顶部,三角形连接到底部并以 UILabel 为中心.

I created a "tooltip" view that has a UILabel and an UIView with a CAShapeLayer for a triangle shape. I have setup the "tooltip" so that the label is on top, with the triangle attached to the bottom and centered on the UILabel.

当我显示工具提示"时,我使用带有 Spring Damping 和 Spring Velocity 的 UIViewAnimation 给它一个pop"动画.这很好用,但有一个例外,在动画开始时三角形和 UILabel 之间有一个小间隙(然后在动画结束时修复.

When I show the "tooltip", I use the UIViewAnimation with Spring Damping and Spring Velocity to give it a "pop" animation. 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.

关于如何解决此问题的任何建议?

Any suggestions on how to fix this?

这是视图/约束设置:

    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)

视频:

推荐答案

实现它的一种方法是使用自定义 UILabel

One way to approach it would be to have a custom 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
            })        }



    }

}

创建以下效果:

这篇关于自动布局和 UIViewAnimation - 两个连接视图之间的间隙的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆