gpt4 book ai didi

ios - 从顶部而不是固有大小的中心开始动画

转载 作者:行者123 更新时间:2023-11-28 07:54:14 25 4
gpt4 key购买 nike

我正在尝试让我的 View 从上到下动画化。目前,当更改我的标签文本时,在 nil 和一些“错误消息”之间,标签从其固有大小的中心开始动画,但我希望常规“标签”为“静态”并且只为错误标签设置动画。基本上,错误标签应该位于常规标签的正下方,错误标签应该根据其(固有)高度展开。这本质上是一个复选框。我想在用户尚未选中该复选框但正在尝试进一步操作时显示错误消息。代码只是解释问题的基本实现。我已经尝试为 containerview 调整 anchorPoint 和 contentMode,但它们似乎并不像我想的那样工作。抱歉,如果缩进很奇怪

import UIKit
class ViewController: UIViewController {

let container = UIView()
let errorLabel = UILabel()


var bottomLabel: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()

view.addSubview(container)
container.contentMode = .top
container.translatesAutoresizingMaskIntoConstraints = false
container.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
container.bottomAnchor.constraint(lessThanOrEqualTo: view.bottomAnchor).isActive = true
container.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
container.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true

let label = UILabel()
label.text = "Very long text that i would like to show to full extent and eventually add an error message to. It'll work on multiple rows obviously"
label.numberOfLines = 0
container.contentMode = .top
container.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: container.topAnchor).isActive = true
label.bottomAnchor.constraint(lessThanOrEqualTo: container.bottomAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: container.trailingAnchor).isActive = true

container.addSubview(errorLabel)
errorLabel.setContentHuggingPriority(UILayoutPriority(300), for: .vertical)
errorLabel.translatesAutoresizingMaskIntoConstraints = false
errorLabel.topAnchor.constraint(equalTo: label.bottomAnchor).isActive = true
errorLabel.trailingAnchor.constraint(equalTo: container.trailingAnchor).isActive = true
errorLabel.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true

bottomLabel = errorLabel.bottomAnchor.constraint(lessThanOrEqualTo: container.bottomAnchor)
bottomLabel.isActive = false

errorLabel.numberOfLines = 0

container.backgroundColor = .green
let tapRecognizer = UITapGestureRecognizer()
tapRecognizer.addTarget(self, action: #selector(onTap))
container.addGestureRecognizer(tapRecognizer)
}

@objc func onTap() {

self.container.layoutIfNeeded()
UIView.animate(withDuration: 0.3, animations: {
let active = !self.bottomLabel.isActive
self.bottomLabel.isActive = active
self.errorLabel.text = active ? "A veru very veru very veru very veru very veru very veru very veru very veru very long Error message" : nil


self.container.layoutIfNeeded()
})
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

最佳答案

我发现让动态多行标签以我想要的方式“动画化”有点困难 - 特别是当我想“隐藏”标签时。

一种方法:创建 2 个“错误”标签,一个叠加在另一个之上。使用“隐藏”标签来控制容器 View 上的约束。为变化设置动画时,容器 View 的边界将有效地“显示”和“隐藏”(显示/隐藏)“可见”标签。

这是一个示例,您可以直接在 Playground 页面中运行:

import UIKit
import PlaygroundSupport

class RevealViewController: UIViewController {

let container = UIView()
let staticLabel = UILabel()
let hiddenErrorLabel = UILabel()
let visibleErrorLabel = UILabel()

override func viewDidLoad() {
super.viewDidLoad()

// colors, just so we can see the bounds of the labels
view.backgroundColor = .lightGray
container.backgroundColor = .green
staticLabel.backgroundColor = .yellow
visibleErrorLabel.backgroundColor = .cyan

// we don't want to see this label, so set its alpha to zero
hiddenErrorLabel.alpha = 0.0

// we want the Error Label to be "revealed" - so when it is has text it is initially "covered"
container.clipsToBounds = true

// all labels may be multiple lines
staticLabel.numberOfLines = 0
hiddenErrorLabel.numberOfLines = 0
visibleErrorLabel.numberOfLines = 0

// initial text in the "static" label
staticLabel.text = "Very long text that i would like to show to full extent and eventually add an error message to. It'll work on multiple rows obviously"

// add the container view to the VC's view
// pin it to the sides, and 100-pts from the top
// NO bottom constraint
view.addSubview(container)
container.translatesAutoresizingMaskIntoConstraints = false
container.topAnchor.constraint(equalTo: view.topAnchor, constant: 100.0).isActive = true
container.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
container.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true

// add the static label to the container
// pin it to the top and sides
// NO bottom constraint
container.addSubview(staticLabel)
staticLabel.translatesAutoresizingMaskIntoConstraints = false
staticLabel.topAnchor.constraint(equalTo: container.topAnchor).isActive = true
staticLabel.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
staticLabel.trailingAnchor.constraint(equalTo: container.trailingAnchor).isActive = true

// add the "hidden" error label to the container
// pin it to the sides, and pin its top to the bottom of the static label
// NO bottom constraint
container.addSubview(hiddenErrorLabel)
hiddenErrorLabel.translatesAutoresizingMaskIntoConstraints = false
hiddenErrorLabel.topAnchor.constraint(equalTo: staticLabel.bottomAnchor).isActive = true
hiddenErrorLabel.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
hiddenErrorLabel.trailingAnchor.constraint(equalTo: container.trailingAnchor).isActive = true

// add the "visible" error label to the container
// pin its top, leading and trailing constraints to the hidden label
container.addSubview(visibleErrorLabel)
visibleErrorLabel.translatesAutoresizingMaskIntoConstraints = false
visibleErrorLabel.topAnchor.constraint(equalTo: hiddenErrorLabel.topAnchor).isActive = true
visibleErrorLabel.leadingAnchor.constraint(equalTo: hiddenErrorLabel.leadingAnchor).isActive = true
visibleErrorLabel.trailingAnchor.constraint(equalTo: hiddenErrorLabel.trailingAnchor).isActive = true

// pin the bottom of the hidden label ot the bottom of the container
// now, when we change the text of the hidden label, it will
// "push down / pull up" the bottom of the container view
hiddenErrorLabel.bottomAnchor.constraint(equalTo: container.bottomAnchor).isActive = true

// add a tap gesture
let tapRecognizer = UITapGestureRecognizer()
tapRecognizer.addTarget(self, action: #selector(onTap))
container.addGestureRecognizer(tapRecognizer)

}

var myActive = false

@objc func onTap() {

let errorText = "A veru very veru very veru very veru very veru very veru very veru very veru very long Error message"

self.myActive = !self.myActive

if self.myActive {

// we want to SHOW the error message

// set the error message in the VISIBLE error label
self.visibleErrorLabel.text = errorText

// "animate" it, with duration of 0.0 - so it is filled instantly
// it will extend below the bottom of the container view, but won't be
// visible yet because we set .clipsToBounds = true on the container
UIView.animate(withDuration: 0.0, animations: {

}, completion: {
_ in

// now, set the error message in the HIDDEN error label
self.hiddenErrorLabel.text = errorText

// the hidden label will now "push down" the bottom of the container view
// so we can animate the "reveal"
UIView.animate(withDuration: 0.3, animations: {
self.view.layoutIfNeeded()
})

})

} else {

// we want to HIDE the error message

// clear the text from the HIDDEN error label
self.hiddenErrorLabel.text = ""

// the hidden label will now "pull up" the bottom of the container view
// so we can animate the "conceal"
UIView.animate(withDuration: 0.3, animations: {
self.view.layoutIfNeeded()
}, completion: {
_ in

// after its hidden, clear the text of the VISIBLE error label
self.visibleErrorLabel.text = ""

})

}

}

}

let vc = RevealViewController()
PlaygroundPage.current.liveView = vc

关于ios - 从顶部而不是固有大小的中心开始动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48748435/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com