当前位置: 首页 > 工具软件 > Swift-Prompts > 使用案例 >

swiftui_在swiftui中使用自定义后退按钮的情况

齐志勇
2023-12-01

swiftui

SwiftUI streamlines many of the common functionalities, capabilities, and controls common in apps. It is quite apparent that a focus during development was to consider how devs could incorporate common UI elements simply and with a lot of the overhead powerfully automated. The framework even takes into consideration usability and design perspectives.

SwiftUI简化了应用程序中常见的许多常见功能,功能和控件。 显而易见,开发过程中的重点是考虑开发人员如何简单地合并常见的UI元素,以及如何将大量开销强大地自动化。 该框架甚至考虑了可用性和设计观点。

This is extremely welcomed by the iOS community, which has had experience working with Interface Builder, Storyboards, and ViewControllers. Anyone who has dealt with the complexity that even the most simplistic features demanded could understand SwiftUI’s benefits.

iOS社区对此非常欢迎,该社区具有使用Interface Builder,Storyboard和ViewController的经验。 任何处理过即使最简单的功能都需要的复杂性的人都可以理解SwiftUI的好处。

赶上? (The Catch?)

As devs begin to build out more and more complex apps with SwiftUI, there are times when it feels like features (such as Navigation) are almost too simplistic. As I scroll through Stack Overflow Q&A’s, I see an increasing number of tagged issues that ask for more dev control. Likewise, I see a number of solutions that involve wrapping older UIKit solutions to cover the gaps.

随着开发人员开始使用SwiftUI构建越来越复杂的应用程序,有时感觉功能(例如导航) 过于简单化。 当我滚动查看Stack Overflow问答时,我看到越来越多的标记问题要求更多的开发人员控制。 同样,我看到了许多解决方案,其中涉及包装较旧的UIKit解决方案以弥补这些空白。

My hope is that as SwiftUI continues to mature and develop, we will see less and less UIKit and more SwiftUI (and that definitely seemed to be the case at this year’s WWDC20).

我的希望是,随着SwiftUI的不断成熟和发展,我们将看到越来越少的UIKit和更多的SwiftUI(在今年的WWDC20上确实如此)。

But it’s also my hope that we only resort to tapping into another framework as a last resort. Perhaps we can find pure SwiftUI solutions, as Apple suggests, though they may seem hacky and/or less pretty. I’d argue, though, that we’d be doing the same by pulling in UIKit.

但是,我也希望我们只能求助于采用另一个框架。 正如苹果建议的那样,也许我们可以找到纯粹的SwiftUI解决方案,尽管它们看起来有些笨拙和/或不太美观。 不过,我认为我们可以通过引入UIKit来做到这一点。

For the record: I have nothing truly against UIKit — just a healthy desire to reduce dependency and see a new framework stand on its own.

记录一下:我没有真正反对UIKit的东西–只是一种健康的愿望,即减少依赖并看到一个新的框架。

SwiftUI放松吗? (SwiftUI Unwind?)

One such ability that devs seem to miss is having an unwind. We get a back button for “free” with Navigation, but there’s no option to add any code or completions to it. Way back in the olden UIKit days, there were a few options. If we had been using a segue, we could put code into an unwind. The other option was using viewWillDisapear or some other lifecycle event.

开发人员似乎会错过的一项功能就是放松。 我们使用导航获得了“免费”的后退按钮,但是没有选择向其添加任何代码或补全。 可以追溯到古老的UIKit时代,这里有一些选择。 如果我们一直在使用segue ,我们可以segue代码。 另一个选项是使用viewWillDisapear或其他一些生命周期事件。

With SwiftUI, in the instance that a developer wants to run some code before navigating back to the parent (and not immediately on a binding change), the best we can naturally do “for free” is trigger .onDisappear (listed as one of SwiftUI’s lifecycle events). However, this is technically running as the parent is already coming into view, which may produce awkward UI results. And since the parent in a NavigationView is already appearing, onAppear is not a safe bet.

使用SwiftUI,在开发人员想要在导航回父级之前(而不是立即进行绑定更改)之前运行一些代码的情况下,我们自然可以“免费”做的最好的事情是Trigger .onDisappear ( 列为SwiftUI的其中之一)生命周期事件 )。 但是,这在技术上正在运行,因为已经可以看到父级,这可能会产生尴尬的UI结果。 而且,由于NavigationView中的父项已经出现, onAppear不是一个安全的选择。

The other approach, then, is to take matters into our own hands and create a custom back button. This is natural because, although we’re not using the button created for free, we are given the ability to add bar items to our view. Should our app call for more than simply navigating back, we should absolutely take advantage of this approach.

那么,另一种方法是将事情掌握在我们自己手中,并创建一个自定义的后退按钮。 这是很自然的,因为尽管我们没有使用免费创建的按钮,但可以将条形项目添加到视图中。 如果我们的应用程序不仅仅要求返回导航,还应该绝对利用这种方法。

创建我们的后退按钮 (Creating Our Back Button)

It’s actually quite simple to create a new back button, though you may be introduced to a few new modifiers and such along the way. The assumption here is that you have a detail view that you’re using a NavigationView to navigate down the chain to and want to navigate back up the chain from with a back button.

创建一个新的后退按钮实际上非常简单,尽管在此过程中可能会向您介绍一些新的修饰符。 这里的假设是,您有一个详细视图,您正在使用NavigationView向下浏览链并希望使用后退按钮链向上导航。

First, where you would normally declare your view’s properties, you’ll need to pull in a system Environment property called presentationMode:

首先,通常在声明视图属性的地方,需要引入一个名为presentationMode的系统环境属性:

@Environment(\.presentationMode) var presentationMode

Unfortunately, the Apple docs seem to be lacking in depth regarding presentationMode (for the instance property and even less for the structure). What we do know is that it is a default property for all views that binds to your app’s environment. This will be essential in just a minute.

不幸的是,Apple文档似乎缺少关于presentationMode深度知识(对于实例属性 ,对于结构而言 ,甚至更少)。 我们所知道的是,它是绑定到应用程序环境的所有视图的默认属性。 一分钟之内,这将是必不可少的。

Views come with modifiers for interacting with Navigation should they be a part of a Navigation hierarchy. In our case, we’ll want to add a few modifiers to our detail view’s upmost layer (e.g. the encompassing stack).

如果视图是导航层次结构的一部分,则视图带有用于与导航交互的修饰符。 在我们的情况下,我们想在细节视图的最上层(例如,包围堆栈)添加一些修改器。

The first modifier will hide the default back button:

第一个修饰符将隐藏默认的后退按钮:

.navigationBarBackButtonHidden(true)

The second modifier we’ll be needing will allow us to add items to the Navigation Bar (the reserved space on the top of a Navigation descendant view):

我们将需要的第二个修饰符将使我们能够向导航栏(导航后代视图顶部的保留空间)添加项目:

.navigationBarItems(leading: <View(s)>)

For our purposes, we’ll be creating a button like this:

为了我们的目的,我们将创建一个如下所示的按钮:

.navigationBarItems(leading:
  Button(action: {
    //Your Custom Code Here
    self.presentationMode.wrappedValue.dismiss()
  }) {
    HStack {
      Image(systemName: "arrow.left")
      Text("Back")
    }
})

That’s it! We now have our back button capable of running code before we actually dismiss the view.

而已! 现在,在实际关闭视图之前,我们的后退按钮能够运行代码。

Note: One thing you may notice is we put “Back” in for the button text. If we want the name of the parent view, we’ll need to pass it to the descendant (as a property is fine — no need for state).

注意:您可能会注意到的一件事是,我们在按钮文本中添加了“返回”。 如果我们想要父视图的名称,则需要将其传递给后代(因为属性很好-不需要状态)。

备份方案 (Backing Up Scenarios)

Why would someone want a custom back button? There’s an argument to be made that most scenarios could be covered using what’s already available — especially using Bindings and Combine. Here are a few scenarios where I think it could be useful.

为什么有人要自定义后退按钮? 有一个论点是,大多数情况都可以使用已经可用的方法来覆盖,特别是使用绑定和合并。 在一些我认为可能有用的方案中。

方案1:确定吗? (Scenario 1: Are you sure?)

One possible scenario for needing a custom back button is wanting to perform an action on the current view before navigating. One such case is asking the user if they’re sure they want to navigate back (groundbreaking example, I know).

需要自定义后退按钮的一种可能情况是希望在导航之前对当前视图执行操作。 一种这样的情况是询问用户是否确定要导航回去(我知道这是一个突破性的示例)。

In this case, we can add an alert to our view that prompts the user about if they’re sure they want to navigate back. We’ll also move the dismiss call out of our back button and into the alert affirmative:

在这种情况下,我们可以向视图添加警报,以提示用户是否确定要导航回去。 我们还将dismiss呼叫从后退按钮移到肯定的警报中:

//alert with the option to dismiss
.alert(isPresented:$showingAlert) {
  Alert(title: Text("Are you sure you want to leave?"), 
        message: Text("We'll miss you!"), 
        primaryButton: .default(Text("Leave")) {
          self.presentationMode.wrappedValue.dismiss()
        }, 
        secondaryButton: .cancel())
}

Lastly, we’ll want to trigger the alert through the back button:

最后,我们要通过“后退”按钮触发警报:

// Add a new State to your View
@State var showAlert: Bool = false// Add the following trigger inside the Back button
// Note: we set to true, not toggle
self.showAlert = true

方案2:准备就绪后同步 (Scenario 2: Sync when I’m ready)

If data is created or edited on the screen, there could be a scenario where we don’t necessarily want those changes to be bindable. Perhaps we would prefer the user to go about their experience, and only after they’ve signaled that they’re finished by hitting the back button, we begin to store/sync the data. Even massage the data before we do so.

如果在屏幕上创建或编辑数据,则可能会出现一种情况,即我们不一定希望这些更改具有可绑定性。 也许我们希望用户去体验他们的体验,并且只有在他们通过单击“后退”按钮表示已完成操作后,我们才开始存储/同步数据。 甚至在我们处理数据之前都要先整理数据。

The data would presumably already be available on the current view. It is a matter of simply adding the necessary code right in the back button before our dismiss.

数据可能在当前视图上已经可用。 只需在dismiss之前在后退按钮中直接添加必要的代码即可。

方案3:传递回调以实现更动态的导航 (Scenario 3: Passing callbacks for more dynamic navigation)

What happens if we have a view that we plan on navigating back to but from multiple different descendants? Upon returning to that view, we want to run some sort of process (and, as stated earlier, onAppear doesn’t count when returning to the parent).

如果我们计划将视图导航到多个不同后代,但又会如何呢? 返回到该视图后,我们要运行某种过程(并且,如前所述, onAppear在返回父级时不计在内)。

If what we want to do mainly takes place in the parent view, it could be tedious and unruly to have each potential descendant be forcibly compatible for things it shouldn’t necessarily be aware of. The solution, then, is to pass a callback closure to be run in our back button!

如果我们想做的事情主要发生在父视图中,那么让每个潜在的后代强制地兼容他们本不应该意识到的事情可能是乏味且不规则的。 然后,解决方案是传递一个回调闭包以在我们的后退按钮中运行!

This blinds the descendant from the complexity of whatever needs to be done and simply makes it the messenger and trigger.

这使后代看不到需要做的任何事情的复杂性,只是使其成为使者和触发器。

A way of accepting and running a closure is as follows:

接受和运行闭包的方法如下:

// Make a closure an optional parameter in the descendant View
var onBack: (// In our Back button, we'll run the closure, provided it's not nil
onBack?()

收回控制权 (Take Back Control)

I love SwiftUI — even more so after this year’s WWDC20. While there is still some maturing to come, it doesn’t mean that we can’t write fully robust and powerful apps. On the contrary, I expect to see some great apps written in SwiftUI.

我喜欢SwiftUI-在今年的WWDC20之后更是如此。 尽管还有一些日趋成熟,但这并不意味着我们不能编写功能强大的应用程序。 相反,我希望看到一些用SwiftUI编写的出色应用程序。

Just remember that while SwiftUI does pick up a lot of the slack and makes things simple, that doesn’t mean we can’t get the access and control we may need to create awesome apps.

只需记住,尽管SwiftUI确实吸收了很多懈怠并使事情变得简单,但这并不意味着我们无法获得创建出色应用程序所需的访问权和控制权。

Dig around and take back the control you think you’ve lost!

挖掘周围并收回您认为自己已经失去的控制权!

翻译自: https://medium.com/better-programming/the-case-for-using-custom-back-buttons-in-swiftui-99b3124f3572

swiftui

 类似资料: