Swift - 用动画显示 header
Swift - Display header with animation
我对 Swift 编码有点陌生,我想通过寻找一些布局并尝试使用 AutoLayout 实现它们来训练自己。
这是我尝试实现的屏幕截图
https://i.imgur.com/9yzvnzp.png
这里需要的行为是在滚动时图片应该淡出并且标题应该这样设置
https://i.imgur.com/bLhyTGs.png
任何人都可以帮助我我应该怎么做吗?
我应该使用 ScrollView 吗?界面表视图? UICollectionView ?
我实际上正在开发一个执行类似操作的应用程序。
因此,您要做的第一件事是为背景创建一个 UIView
,即显示 Squirtle 的蓝色部分。这个视图可以占据整个视图控制器。通过 IBOutlet
将其连接到您的 UIViewController
并将其命名为 backgroundView
.
接下来,我们要在 backgroundView
上放置一个 UIScrollView
。这个滚动视图应该被限制在父视图的顶部、底部、前导和尾部边缘,以便它覆盖整个视图控制器的框架。通过 IBOutlet
将此 UIScrollView
连接到您的 UIViewController
并将其命名为 scrollView
。另外,确保 scrollView
的 backgroundColor
设置为 clear
。这样,我们就可以在 scrollView
.
下面看到 backgroundView
在您的 UIViewController
内,您需要将 scrollView
的委托设置为 viewDidLoad
内的 self
。您的 UIViewController
的代码现在应该如下所示:
class SquirtleViewController: UIViewController {
@IBOutlet var backgroundView: UIView!
@IBOutlet var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
}
extension SquirtleViewController: UIScrollViewDelegate {
}
稍后我们将为 scrollView
设置委托方法。这些将帮助我们知道滚动视图何时开始滚动到我们 SquirtleViewController
.
的顶部
现在,我们的 scrollView
有了清晰的背景,实际上不会向我们的用户显示任何内容。这就是我们现在想要的。我们希望 scrollView
的顶部清晰,以便我们可以看到它后面的 backgroundView
,而 scrollView
的底部有另一个视图,即 "content view"显示 STATS
、EVOLUTIONS
、MOVES
、HP
等
所以,让我们添加另一个 UIView
作为我们 scrollView
的子视图。通过 IBOutlet
将其连接到 SquirtleViewController
并将其命名为 contentView
。
现在,我们需要在 contentView
的上边缘和 scrollView
的上边缘之间创建一个约束。此约束的常量需要等于 backgroundView
内容的高度。这样,我们的 contentView
就不会掩盖我们想从 backgroundView
中看到的内容。我们还应该将这个高度保存为 backgroundViewContentHeight
以便我们以后可以引用它。
我们还需要 contentView
的 leading
、trailing
和 bottom
约束与其父视图的约束相同,即 scrollView
。这些不需要通过 IBOutlet
s.
连接
此外,给 contentView
一个 height
和 width
约束,并将它们分别作为 contentViewHeight
和 contentViewWidth
通过 IBOutlet
。这将帮助我们稍后设置 scrollView
的 contentSize
。
您的代码现在应该如下所示:
class SquirtleViewController: UIViewController {
@IBOutlet var backgroundView: UIView!
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var contentView: UIView!
//New lines of code
//Our constraints
@IBOutlet var contentViewTop: NSLayoutConstraint!
@IBOutlet var contentViewHeight: NSLayoutConstraint!
@IBOutlet var contentViewWidth: NSLayoutConstraint!
var backgroundViewContentHeight = 400
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
}
extension SquirtleViewController: UIScrollViewDelegate {
}
现在,当 SquirtleViewController
布置其子视图时,我们将要设置 contentViewHeight
和 contentViewWidth
的 constant
属性。这将为我们的 scrollView
设置一个 contentSize
。我们希望我们的 contentViewWidth
只是 SquirtleViewController
的 view
宽度的大小。我们的 contentViewHeight
的 constant
会有点不同,因为它取决于我们 contentView
的子视图的高度。对于这个例子,我们假设 contentViewHeight
的 constant
应该是 1200。代码现在应该是这样的:
class SquirtleViewController: UIViewController {
@IBOutlet var backgroundView: UIView!
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var contentView: UIView!
//Our constraints
@IBOutlet var contentViewTop: NSLayoutConstraint!
@IBOutlet var contentViewHeight: NSLayoutConstraint!
@IBOutlet var contentViewWidth: NSLayoutConstraint!
var backgroundViewContentHeight = 400
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
//New lines of code
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
contentViewWidth.constant = view.frame.width
contentViewHeight.constant = 1200
}
}
extension SquirtleViewController: UIScrollViewDelegate {
}
从这里,您可以根据需要向 backgroundView
和 contentView
添加子视图,以显示宠物小精灵 (backgroundView
) 以及宠物小精灵的统计信息 (contentView
).但是,您仍然需要知道如何根据我们滚动 scrollView
的程度来更改 backgroundView
的内容。这就是 UIScrollViewDelegate
帮助我们的地方。
UIScrollViewDelegate
中有一个方法,每次我们的 scrollView
的 contentOffset.y
发生变化时都会调用该方法。这基本上意味着每次我们更改 scrollView
滚动的数量时,都会调用此方法。
在这个方法中,我们可以交叉引用我们滚动的量和背景视图的高度。当我们的 scrollView
的 contentOffset.y
接近我们 backgroundView
内容的高度时,我们可以淡出 Squirtle 的图像并淡入 UILabel
,它简单地说 "Squirtle"(就像你的例子)。
因此,在您的情况下,我建议添加 Squirtle 的 UIImage
作为 contentView
的子视图,并通过 IBOutlet
作为 pokemonImageView
连接它。 pokemonImageView
的框架应该部分位于 contentView
之外(就像您的示例一样)。如果这样做,请确保 contentView
的 clipsToBounds
属性 设置为 false
.
我还会添加一个 UILabel
作为 backgroundView
的子视图,并通过 IBOutlet
作为 pokemonNameLabel
将其连接到 SquirtleViewController
。当我们的 SquirtleViewController
视图加载时,我们应该将 pokemonNameLabel.alpha
设置为零,以便它最初是隐藏的。
您的代码现在应该如下所示:
class SquirtleViewController: UIViewController {
@IBOutlet var backgroundView: UIView!
//New line of code
@IBOutlet var pokemonNameLabel: UILabel!
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var contentView: UIView!
//New line of code
@IBOutlet var pokemonImageView: UIImageView!
//Our constraints
@IBOutlet var contentViewTop: NSLayoutConstraint!
@IBOutlet var contentViewHeight: NSLayoutConstraint!
@IBOutlet var contentViewWidth: NSLayoutConstraint!
var backgroundViewContentHeight = 400
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
//New line of code
pokemonNameLabel.alpha = 0
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
contentViewWidth.constant = view.frame.width
contentViewHeight.constant = 1200
}
}
extension SquirtleViewController: UIScrollViewDelegate {
}
现在我们只需要在 class 扩展中添加 scrollViewDidScroll
方法。这是将告诉我们 scrollView
的 contentOffset.y
属性 的方法,以便我们知道我们滚动了多少。随着这个数字的增加,我们的 pokemonImageView
的 alpha 应该减少到零,我们的 pokemonNameLabel
的 alpha 应该增加到 1。
在这个方法中,我会将 scrollView.contentOffset.y
除以 backgroundView
的高度减去 pokemonNameLabel
的高度。然后我们可以使用这个小数来设置我们各自的 pokemonImageView
和 pokemonNameLabel
.
的 alpha
您的代码现在应该如下所示:
class SquirtleViewController: UIViewController {
@IBOutlet var backgroundView: UIView!
//New line of code
@IBOutlet var pokemonNameLabel: UILabel!
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var contentView: UIView!
//New line of code
@IBOutlet var pokemonImageView: UIImageView!
//Our constraints
@IBOutlet var contentViewTop: NSLayoutConstraint!
@IBOutlet var contentViewHeight: NSLayoutConstraint!
@IBOutlet var contentViewWidth: NSLayoutConstraint!
var backgroundViewContentHeight = 400
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
//New line of code
pokemonNameLabel.alpha = 0
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
contentViewWidth.constant = view.frame.width
contentViewHeight.constant = 1200
}
}
extension SquirtleViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//Subtracting contentView.frame.height from scrollView.frame.height
let alphaDecimal = scrollView.contentOffset.y / (backgroundViewContentHeight - pokemonNameLabel.frame.height)
pokemonNameLabel.alpha = alphaDecimal
pokemonImageView.alpha = 1 - alphaDecimal
}
}
现在,当我们向上滚动时,可以看到 backgroundView
缩小,我们的 pokemonImageView
会淡出,我们的 pokemonNameLabel
会淡入。会有一个点in-between 其中两者的 alpha 均为 0.5。你可以随意使用这个 scrollViewDidScroll
方法or 最适合你。
我对 Swift 编码有点陌生,我想通过寻找一些布局并尝试使用 AutoLayout 实现它们来训练自己。
这是我尝试实现的屏幕截图
https://i.imgur.com/9yzvnzp.png
这里需要的行为是在滚动时图片应该淡出并且标题应该这样设置
https://i.imgur.com/bLhyTGs.png
任何人都可以帮助我我应该怎么做吗? 我应该使用 ScrollView 吗?界面表视图? UICollectionView ?
我实际上正在开发一个执行类似操作的应用程序。
因此,您要做的第一件事是为背景创建一个 UIView
,即显示 Squirtle 的蓝色部分。这个视图可以占据整个视图控制器。通过 IBOutlet
将其连接到您的 UIViewController
并将其命名为 backgroundView
.
接下来,我们要在 backgroundView
上放置一个 UIScrollView
。这个滚动视图应该被限制在父视图的顶部、底部、前导和尾部边缘,以便它覆盖整个视图控制器的框架。通过 IBOutlet
将此 UIScrollView
连接到您的 UIViewController
并将其命名为 scrollView
。另外,确保 scrollView
的 backgroundColor
设置为 clear
。这样,我们就可以在 scrollView
.
backgroundView
在您的 UIViewController
内,您需要将 scrollView
的委托设置为 viewDidLoad
内的 self
。您的 UIViewController
的代码现在应该如下所示:
class SquirtleViewController: UIViewController {
@IBOutlet var backgroundView: UIView!
@IBOutlet var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
}
extension SquirtleViewController: UIScrollViewDelegate {
}
稍后我们将为 scrollView
设置委托方法。这些将帮助我们知道滚动视图何时开始滚动到我们 SquirtleViewController
.
现在,我们的 scrollView
有了清晰的背景,实际上不会向我们的用户显示任何内容。这就是我们现在想要的。我们希望 scrollView
的顶部清晰,以便我们可以看到它后面的 backgroundView
,而 scrollView
的底部有另一个视图,即 "content view"显示 STATS
、EVOLUTIONS
、MOVES
、HP
等
所以,让我们添加另一个 UIView
作为我们 scrollView
的子视图。通过 IBOutlet
将其连接到 SquirtleViewController
并将其命名为 contentView
。
现在,我们需要在 contentView
的上边缘和 scrollView
的上边缘之间创建一个约束。此约束的常量需要等于 backgroundView
内容的高度。这样,我们的 contentView
就不会掩盖我们想从 backgroundView
中看到的内容。我们还应该将这个高度保存为 backgroundViewContentHeight
以便我们以后可以引用它。
我们还需要 contentView
的 leading
、trailing
和 bottom
约束与其父视图的约束相同,即 scrollView
。这些不需要通过 IBOutlet
s.
此外,给 contentView
一个 height
和 width
约束,并将它们分别作为 contentViewHeight
和 contentViewWidth
通过 IBOutlet
。这将帮助我们稍后设置 scrollView
的 contentSize
。
您的代码现在应该如下所示:
class SquirtleViewController: UIViewController {
@IBOutlet var backgroundView: UIView!
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var contentView: UIView!
//New lines of code
//Our constraints
@IBOutlet var contentViewTop: NSLayoutConstraint!
@IBOutlet var contentViewHeight: NSLayoutConstraint!
@IBOutlet var contentViewWidth: NSLayoutConstraint!
var backgroundViewContentHeight = 400
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
}
extension SquirtleViewController: UIScrollViewDelegate {
}
现在,当 SquirtleViewController
布置其子视图时,我们将要设置 contentViewHeight
和 contentViewWidth
的 constant
属性。这将为我们的 scrollView
设置一个 contentSize
。我们希望我们的 contentViewWidth
只是 SquirtleViewController
的 view
宽度的大小。我们的 contentViewHeight
的 constant
会有点不同,因为它取决于我们 contentView
的子视图的高度。对于这个例子,我们假设 contentViewHeight
的 constant
应该是 1200。代码现在应该是这样的:
class SquirtleViewController: UIViewController {
@IBOutlet var backgroundView: UIView!
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var contentView: UIView!
//Our constraints
@IBOutlet var contentViewTop: NSLayoutConstraint!
@IBOutlet var contentViewHeight: NSLayoutConstraint!
@IBOutlet var contentViewWidth: NSLayoutConstraint!
var backgroundViewContentHeight = 400
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
//New lines of code
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
contentViewWidth.constant = view.frame.width
contentViewHeight.constant = 1200
}
}
extension SquirtleViewController: UIScrollViewDelegate {
}
从这里,您可以根据需要向 backgroundView
和 contentView
添加子视图,以显示宠物小精灵 (backgroundView
) 以及宠物小精灵的统计信息 (contentView
).但是,您仍然需要知道如何根据我们滚动 scrollView
的程度来更改 backgroundView
的内容。这就是 UIScrollViewDelegate
帮助我们的地方。
UIScrollViewDelegate
中有一个方法,每次我们的 scrollView
的 contentOffset.y
发生变化时都会调用该方法。这基本上意味着每次我们更改 scrollView
滚动的数量时,都会调用此方法。
在这个方法中,我们可以交叉引用我们滚动的量和背景视图的高度。当我们的 scrollView
的 contentOffset.y
接近我们 backgroundView
内容的高度时,我们可以淡出 Squirtle 的图像并淡入 UILabel
,它简单地说 "Squirtle"(就像你的例子)。
因此,在您的情况下,我建议添加 Squirtle 的 UIImage
作为 contentView
的子视图,并通过 IBOutlet
作为 pokemonImageView
连接它。 pokemonImageView
的框架应该部分位于 contentView
之外(就像您的示例一样)。如果这样做,请确保 contentView
的 clipsToBounds
属性 设置为 false
.
我还会添加一个 UILabel
作为 backgroundView
的子视图,并通过 IBOutlet
作为 pokemonNameLabel
将其连接到 SquirtleViewController
。当我们的 SquirtleViewController
视图加载时,我们应该将 pokemonNameLabel.alpha
设置为零,以便它最初是隐藏的。
您的代码现在应该如下所示:
class SquirtleViewController: UIViewController {
@IBOutlet var backgroundView: UIView!
//New line of code
@IBOutlet var pokemonNameLabel: UILabel!
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var contentView: UIView!
//New line of code
@IBOutlet var pokemonImageView: UIImageView!
//Our constraints
@IBOutlet var contentViewTop: NSLayoutConstraint!
@IBOutlet var contentViewHeight: NSLayoutConstraint!
@IBOutlet var contentViewWidth: NSLayoutConstraint!
var backgroundViewContentHeight = 400
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
//New line of code
pokemonNameLabel.alpha = 0
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
contentViewWidth.constant = view.frame.width
contentViewHeight.constant = 1200
}
}
extension SquirtleViewController: UIScrollViewDelegate {
}
现在我们只需要在 class 扩展中添加 scrollViewDidScroll
方法。这是将告诉我们 scrollView
的 contentOffset.y
属性 的方法,以便我们知道我们滚动了多少。随着这个数字的增加,我们的 pokemonImageView
的 alpha 应该减少到零,我们的 pokemonNameLabel
的 alpha 应该增加到 1。
在这个方法中,我会将 scrollView.contentOffset.y
除以 backgroundView
的高度减去 pokemonNameLabel
的高度。然后我们可以使用这个小数来设置我们各自的 pokemonImageView
和 pokemonNameLabel
.
您的代码现在应该如下所示:
class SquirtleViewController: UIViewController {
@IBOutlet var backgroundView: UIView!
//New line of code
@IBOutlet var pokemonNameLabel: UILabel!
@IBOutlet var scrollView: UIScrollView!
@IBOutlet var contentView: UIView!
//New line of code
@IBOutlet var pokemonImageView: UIImageView!
//Our constraints
@IBOutlet var contentViewTop: NSLayoutConstraint!
@IBOutlet var contentViewHeight: NSLayoutConstraint!
@IBOutlet var contentViewWidth: NSLayoutConstraint!
var backgroundViewContentHeight = 400
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
//New line of code
pokemonNameLabel.alpha = 0
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
contentViewWidth.constant = view.frame.width
contentViewHeight.constant = 1200
}
}
extension SquirtleViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//Subtracting contentView.frame.height from scrollView.frame.height
let alphaDecimal = scrollView.contentOffset.y / (backgroundViewContentHeight - pokemonNameLabel.frame.height)
pokemonNameLabel.alpha = alphaDecimal
pokemonImageView.alpha = 1 - alphaDecimal
}
}
现在,当我们向上滚动时,可以看到 backgroundView
缩小,我们的 pokemonImageView
会淡出,我们的 pokemonNameLabel
会淡入。会有一个点in-between 其中两者的 alpha 均为 0.5。你可以随意使用这个 scrollViewDidScroll
方法or 最适合你。