自动布局和 UIViewAnimation - 两个连接视图之间的间隙 [英] Auto layout and UIViewAnimation - Gap between two connected views
问题描述
我创建了一个工具提示"视图,它有一个 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屋!