加载视图和链接视图
Creating an initial app loading screen is probably not thought about too much when developing iOS apps. Today we’ll take a quick look at how we can create a relatively simple and elegant loading screen.
在开发iOS应用程序时,可能不会过多考虑创建一个初始应用程序加载屏幕。 今天,我们将快速了解如何创建一个相对简单而优雅的加载屏幕。
We want to see your work! If you’ve built something using this tutorial, send us pics! Find us on Twitter @TrailingClosure, or email us at howdy@TrailingClosure.com
我们希望看到您的作品! 如果您使用本教程构建了一些东西,请给我们发送图片! 在Twitter @TrailingClosure上找到我们,或通过howdy@TrailingClosure.com给我们发送电子邮件
This tutorial is split into two parts:
本教程分为两个部分:
Creating the
ScaledMaskModifier
创建
ScaledMaskModifier
Creating the
LoadingView
创建
LoadingView
创建ScaledMaskModifier
(Create The ScaledMaskModifier
)
Our ScaledMaskModifier
is going to be used to animate the display of our loading view. It takes a Mask
as an input that will scale up over time to display the loading view. See below for a glimpse.
我们的ScaledMaskModifier
将用于设置加载视图的动画。 它使用“ Mask
作为输入,它将随着时间的推移按比例放大以显示加载视图。 请参阅下面的内容。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/591b19d83d2c1a12e2fcd5695678e27a.png)
ScaledMaskModifier
using a
Circle
作为蒙版的
Circle
as the mask
ScaledMaskModifier
First, create a new ViewModifier
called ScaledMaskModifier
. We're going to add two variables to the class:
首先,创建一个新的ViewModifier
称为ScaledMaskModifier
。 我们将向该类添加两个变量:
mask
- The Mask described earlier. It will grow over time to display the underlying loading view.mask
-面具如前所述。 随着时间的流逝,它将显示基础的加载视图。progress
- The value to keep track of where in the animation we are.progress
跟踪动画位置的值。
Here is the template of the struct so far:
到目前为止,这是该结构的模板:
import SwiftUI
struct ScaledMaskModifier<Mask: View>: ViewModifier {
var mask: Mask
var progress: CGFloat
func body(content: Content) -> some View {
content
}
}
Next we need to calculate the height and width of the mask and then apply it to our content. The tricky thing here is we want to ensure that the mask will shape will grow to the full size of the content. Think of it similarly to how we use scaleToFill()
on an Image
.
接下来,我们需要计算蒙版的高度和宽度,然后将其应用于内容。 这里的棘手事情是我们要确保蒙版的形状将增长到内容的全部大小。 与我们如何在Image
上使用scaleToFill()
类似地考虑它。
Create a function called
calculateSize(geometry: GeometryProxy)
. This will return the size of themask
at it's maximum (at the end of the animation). It will figure out whether or not the width or height of the content is larger and return that as the size.创建一个名为
calculateSize(geometry: GeometryProxy)
的函数。 这将返回最大的mask
大小(在动画末尾)。 它将确定内容的宽度或高度是否较大,并将其返回为大小。
// Calculate Max Size of Mask
func calculateSize(geometry: GeometryProxy) -> CGFloat {
if geometry.size.width > geometry.size.height {
return geometry.size.width
}
return geometry.size.height
}
Apply the
mask
to our content while usingcalculateSize(geometry:)
andprogress
to scale the mask size over time.在使用
calculateSize(geometry:)
同时,将mask
应用于我们的内容,然后progress
缩放遮罩大小。
import SwiftUI
struct ScaledMaskModifier<Mask: View>: ViewModifier {
var mask: Mask
var progress: CGFloat
func body(content: Content) -> some View {
content
.mask(GeometryReader(content: { geometry in
self.mask.frame(width: self.calculateSize(geometry: geometry) * self.progress,
height: self.calculateSize(geometry: geometry) * self.progress,
alignment: .center)
}))
}
// Calculate Max Size of Mask
func calculateSize(geometry: GeometryProxy) -> CGFloat {
if geometry.size.width > geometry.size.height {
return geometry.size.width
}
return geometry.size.height
}
}
创建LoadingView
(Create the LoadingView
)
Next up we’ll put the ScaledMaskModifier
to work by creating the LoadingView
. Also inside the LoadingView
is where we'll handle the animations.
接下来,我们将通过创建ScaledMaskModifier
来使LoadingView
。 同样在LoadingView
内,我们将处理动画。
Create a new
View
and call itLoadingView
. Inside you need to define 3 variables: one for the contents of theLoadingView
, one for the progress of the animation, and another for the Y offset (bouncing animation). See below for an example.创建一个新的
View
并将其LoadingView
。 在内部,您需要定义3个变量:一个用于LoadingView
的内容,一个用于动画的进度,另一个用于Y偏移(弹跳动画)。 请参阅下面的示例。
import SwiftUI
struct LoadingView<Content: View>: View {
var content: Content
@Binding var progress: CGFloat
@State var logoOffset: CGFloat = 0 //Animation Y Offset
var body: some View {
content
}
}
Next, we’ll need to apply the
ScaledMaskModifier
to the content. Here we used aCircle
as the mask, but really you could use anyShape
orView
such as aRectangle
or any other custom SwiftUIView
.接下来,我们需要将
ScaledMaskModifier
应用于内容。 在这里,我们使用Circle
作为蒙版,但是实际上您可以使用任何Shape
或View
例如Rectangle
或任何其他自定义SwiftUIView
。
var body: some View {
content
.modifier(ScaledMaskModifier(mask: Circle(), progress: progress))
}
In addition the
ScaledMaskModifier
we will make thecontent
bounce up and down. To do this, we're going to animate its y offset.此外,
ScaledMaskModifier
我们将尽content
上下跳动。 为此,我们将为其y偏移量设置动画。
var body: some View {
content
.modifier(ScaledMaskModifier(mask: Circle(), progress: progress))
.offset(x: 0, y: logoOffset)
}
Time to add the animations. Here we’ll animate the
content
's progress change from0
to1
, while at the same time bouncing it up and down.是时候添加动画了。 在这里,我们将使
content
的进度从0
变为1
进行动画处理,同时将其上下跳动。
import SwiftUI
struct LoadingView<Content: View>: View {
var content: Content
@Binding var progress: Double
@State var logoOffset: CGFloat = 0 //Animation Y Offset
var body: some View {
content
.modifier(ScaledMaskModifier(mask: Circle(), progress: progress))
.offset(x: 0, y: logoOffset)
.onAppear {
withAnimation(Animation.easeInOut(duration: 1)) {
self.progress = 1.0
}
withAnimation(Animation.easeInOut(duration: 0.4).repeatForever(autoreverses: true)) {
self.logoOffset = 10
}
}
}
}
创建一个例子 (Creating an Example)
Now we’re going to put our LoadingView
to the test in an example. See below:
现在,在一个示例中,我们将LoadingView
进行测试。 见下文:
Here we’ve created a fake HomeView
that is displayed once the loading is finished. As you can see we use the variable doneLoading
to decide which vie to render on screen.
在这里,我们创建了一个伪造的HomeView
,加载完成后就会显示出来。 如您所见,我们使用变量doneLoading
决定在屏幕上渲染哪个视频。
For the LoadingView
I've passed in a Image
that will be used as the content
of the loading screen.
对于LoadingView
我传递了一个Image
,该Image
将用作加载屏幕的content
。
Finally, if you’re curious as to why I’ve used the onAppear()
function, it is so I can simulate the asynchronous nature of loading data for your app.
最后,如果您对我为什么使用onAppear()
函数感到好奇,那么我可以模拟为您的应用程序加载数据的异步特性。
import SwiftUI
struct ContentView: View {
@State var progress: CGFloat = 0
@State var doneLoading: Bool = false
var body: some View {
ZStack {
if doneLoading {
HomeView()
.transition(AnyTransition.opacity.animation(.easeInOut(duration: 1.0)))
} else {
LoadingView(content: Image("PathMaskLogo-Dark")
.resizable()
.scaledToFit()
.padding(.horizontal, 50),
progress: $progress)
// Added to simulate asynchronous data loading
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
withAnimation {
self.progress = 0
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
withAnimation {
self.doneLoading = true
}
}
}
}
}
}
}
}
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/79bd5f6137d4f97bf44b8b748b98f2cb.png)
支持像这样的未来教程! (Support Future Tutorials Like This One!)
Please consider subscribing using this link. If you aren’t reading this on TrailingClosure.com, please come check us out sometime!
请考虑使用此链接进行订阅。 如果您没有在TrailingClosure.com上阅读此书 ,请随时联系我们!
We want to see your work! If you’ve built something using this tutorial, send us pics! Find us on Twitter @TrailingClosure, or email us at howdy@TrailingClosure.com
我们希望看到您的作品! 如果您使用本教程构建了一些东西,请给我们发送图片! 在Twitter @TrailingClosure上找到我们,或通过howdy@TrailingClosure.com给我们发送电子邮件
翻译自: https://medium.com/dev-genius/simple-app-loading-view-239807a9db1e
加载视图和链接视图