13 Replies
      Latest reply on Oct 25, 2019 9:44 AM by KMT
      Core4 Level 1 Level 1 (0 points)

        Check example TabView project ( xcode starter TabView project ) -  make NavigationView, List and so on in one tab,  and for example Text("hello")  for other tab.

        Scroll list or/and navigate some screen in first tab, then goto second tab. And finally when open first tab again - view will fully reloaded ( List in 0 position, navigation reseted, But state properties will saved )

         

        Check standard native Contact app.  Switching over tabs - save ALL context was created.  Scroll down contacts list  than switch tab and switch again to contacts tab - scroll was the same ( context saved )

        • Re: TabView reload all content constantly
          Claude31 Level 8 Level 8 (7,005 points)

          Copuld you show YOUR code ?

          • Re: TabView reload all content constantly
            Jim Dovey Level 3 Level 3 (180 points)

            I can consistently reproduce this behavior with the following code:

             

            import SwiftUI
            
            struct ContentView: View {
                @State private var selection = 0
            
                var body: some View {
                    TabView(selection: $selection){
                        FirstTabView()
                            .tabItem {
                                VStack {
                                    Image("first")
                                    Text("First")
                                }
                            }
                            .tag(0)
                        SecondTabView()
                            .font(.title)
                            .tabItem {
                                VStack {
                                    Image("second")
                                    Text("Second")
                                }
                            }
                            .tag(1)
                    }
                }
            }
            
            struct FirstTabView: View {
                var body: some View {
                    List {
                        ForEach(1...50, id: \.self) { num in
                            Text("Row \(num)")
                        }
                    }
                }
            }
            
            struct SecondTabView: View {
                var body: some View {
                    Text("Second View")
                }
            }
            

             

            I'd suggest filing a bug. It seems that a layout occurs on the table view at the point it's taken offscreen (you'll see a printout from UITableView in the debugger output from the simulator), and that may be what's causing it to reset—the size may have gone to zero or become invalid, taking the scroll offset with it. This can probably be worked around with a little Anchor and PreferenceKey magic, but you'd normally not be doing such things unless you wanted to, say, have the table always snap into place at a cell division, which is not terribly likely.

             

            There's an outside possibility that this has something to do with SwiftUI's layout model; it may be discarding and recreating the views. I somewhat doubt that though—there should be a real UITabController there, holding onto its content.

              • Re: TabView reload all content constantly
                Jim Dovey Level 3 Level 3 (180 points)

                Okay, looks like this is entirely down to SwiftUI being weird. It appears to be gaming the UITabBar system. Each time you tap to select a tab, SwiftUI is changing the view controller list for the tab bar. For n tabs, it contains n-1 plain UIViewControllers with empty views, and 1 HostingController<_ViewList_View>. Tapping on a tab will update the content of hosting controller to contain the content of the SwiftUI tab, and it will reassign the UITabBarController's viewControllers property—it moves the HostingController to the index of the tapped tab, and puts a new empty UIViewController at its old position.

                 

                Here's the output of that property as I walk through four SwiftUI tabs:

                 

                (lldb) po [$21 viewControllers]
                <__NSArrayM 0x6000015091d0>(
                <_TtGC7SwiftUI19UIHostingControllerVS_14_ViewList_View_: 0x7fddabe0c600>,
                <UIViewController: 0x7fdd9bc2eeb0>,
                <UIViewController: 0x7fddabf2bd80>,
                <UIViewController: 0x7fddabd11b40>
                )
                
                (lldb) po [$21 viewControllers]
                <__NSArrayM 0x6000015087b0>(
                <UIViewController: 0x7fddabd27170>,
                <_TtGC7SwiftUI19UIHostingControllerVS_14_ViewList_View_: 0x7fddabe0c600>,
                <UIViewController: 0x7fddabf2bd80>,
                <UIViewController: 0x7fddabd11b40>
                )
                
                (lldb) po [$21 viewControllers]
                <__NSArrayM 0x600001504780>(
                <UIViewController: 0x7fddabd27170>,
                <UIViewController: 0x7fddabd0a9a0>,
                <_TtGC7SwiftUI19UIHostingControllerVS_14_ViewList_View_: 0x7fddabe0c600>,
                <UIViewController: 0x7fddabd11b40>
                )
                
                (lldb) po [$21 viewControllers]
                <__NSArrayM 0x6000015083c0>(
                <UIViewController: 0x7fddabd27170>,
                <UIViewController: 0x7fddabd0a9a0>,
                <UIViewController: 0x7fdd9bc3f830>,
                <_TtGC7SwiftUI19UIHostingControllerVS_14_ViewList_View_: 0x7fddabe0c600>
                )
                

                 

                As you can see, the same UIHostingController<_ViewList_View> is making its way to the index of the current tab, and a new blank controller is being put in its place. With this behavior, it's no surprise that your List view is always being reset—with no good way of recording your scroll offset (or setting it) via your own @State properties, there's no way to persist that information across updates of the view hierarchy.

                 

                Please file a bug.

                  • Re: TabView reload all content constantly
                    KMT Level 9 Level 9 (15,135 points)

                         > UITabBar system ~ persist that information across updates of the view hierarchy.

                     

                    Speaking of which - have you seen the docs on 'order of containment*? If you're in line with those rules (it seems maybe you are), then I'd be tempted to echo SwiftUI's acting out...if not, then all bets are off and I'm tempted instead to (ouch) blame the victim.

                     

                    *From the docs on 'Order of Containment': https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/CombiningViewControllers.html

                     

                    -=-

                    Combined View Controller Interfaces

                    You can use the view controllers that the UIKit framework provides by themselves or in conjunction with other view controllers to create even more sophisticated interfaces. When combining view controllers, however, the order of containment is important; only certain arrangements are valid. The order of containment, from child to parent, is as follows:

                    • Content view controllers, and container view controllers that have flexible bounds (such as the page view controller)
                    • Navigation view controller
                    • Tab bar controller
                    • Split view controller
                      • Re: TabView reload all content constantly
                        Jim Dovey Level 3 Level 3 (180 points)

                        Popping it open in the view debugger shows a whole lot of weird things—SwiftUI functions really quite differently in terms of hierarchy, largely due to the fact that SwiftUI views don't necessarily map to actual UIView instances. For want of a better term, often a View type is more of a coordinate space for its subviews.

                         

                        In this case, though, I expect there are reasons for how they're shuffling around the hosting controller. Perhaps it's very expensive to create these types of controllers, or shuffling it around provides significantly better performance. However, they need to determine some way to preserve scroll view offsets when moving between these, along with some heuristic that can be used to determine when they become invalidated. Even if the view tree is being re-evaluated, there should be room to maintain that state somewhere.

                          • Re: TabView reload all content constantly
                            KMT Level 9 Level 9 (15,135 points)

                                 >need to determine some way to preserve scroll view offsets ~ should be room to maintain that state

                             

                            Discussed here (sorry if these have already come up):

                             

                            ° h ttps://innovation.vivint.com/maintaining-content-offset-when-the-size-of-your-uiscrollview-changes-554d7742885a

                             

                            ° Apple docs: Preserving and Restoring State

                              • Re: TabView reload all content constantly
                                Jim Dovey Level 3 Level 3 (180 points)

                                These are all for UIKit types, and don't apply to SwiftUI's declarative model. In SwiftUI we don't have the ability to ask a view for its current state, nor to iteratively modify it at runtime.

                                  • Re: TabView reload all content constantly
                                    KMT Level 9 Level 9 (15,135 points)

                                    Jim:

                                     

                                    We've been over this... SwiftUI rides on UIKit, and while I'm sure you get that, you seem, at least in this thread, to bifurcate the two nonetheless, which I believe is a troublshooting mistake.

                                     

                                    If there are gaps in their scaffolding now that prevent working effectively in SUI, we should (a) remember it's new and (b) file enhancement requests via the bug reporter/suggestions, being sure to add your report # to your thread for reference, thanks and good luck.

                                     

                                    Ken