Как использовать TabbedView в SwiftUI?

struct ContentView : View {
    var body: some View {
        NavigationView {
            TabbedView {
                PasswordGenerator()
                    .tabItemLabel {
                        Image("KeyGlyph")
                        Text("Generator")
                }

                PasswordGeneratorSettings()
                    .tabItemLabel {
                            Image("SettingsGlyph")
                            Text("Settings")
                }
            }
        }
    }
}

Это не будет компилироваться, но оно использовалось в видео Swift Essentials на WWDC (см. Минуту 54:30), и я видел некоторые обходные пути, такие как обходной путь VStack (но даже у этого есть много недостатков, левая вкладка слишком далеко от левая и правая вкладки находятся слишком далеко вправо, и при переключении вкладок загружается только первая, которая изначально загружалась, а другая вкладка остается пустой, и использование тегов не помогает). Итак, как у меня есть две вкладки, которые загружают представления и имеют изображение и текст?


person SmushyTaco    schedule 25.06.2019    source источник
comment
У вас есть macOS Catalina?   -  person Lu_    schedule 25.06.2019
comment
@Lu_ Да, у меня есть macOS Catalina.   -  person SmushyTaco    schedule 25.06.2019


Ответы (8)


С XCode beta 3 должно работать следующее:

import SwiftUI

struct Home : View {
    @State private var currentTab = 1

    var body: some View {
        TabbedView(selection: $currentTab) {
            FirstView()
                .tabItem {
                    VStack {
                        Image(systemName: "1.circle")
                        Text("First Tab")
                    }
                }.tag(1)
            SecondView()
                .tabItem {
                    VStack {
                        Image(systemName: "2.circle")
                        Text("Second Tab")
                    }
                }.tag(2)
        }
    }
}

Однако включение метки вкладки в VStack кажется необязательным. Итак, вы можете отказаться от этого, например:

import SwiftUI

struct Home : View {
    @State private var currentTab = 1

    var body: some View {
        TabbedView(selection: $currentTab) {
            FirstView()
                .tabItem {
                    Image(systemName: "1.circle")
                    Text("First Tab")
                }.tag(1)
            SecondView()
                .tabItem {
                    Image(systemName: "2.circle")
                    Text("Second Tab")
                }.tag(2)
        }
    }
}
person Maki    schedule 09.07.2019
comment
если у меня есть элемент вкладки только с изображением, как я могу изменить его положение или выравнивание? - person JAHelia; 25.01.2020

Для тех, кто все еще ищет, как это сделать, вот обновление с Xcode 11 GM.

struct Tabs: View {

    @State private var selected = 0

    var body: some View {
        TabView(selection: $selected) {
            MyFirstView()
                .tabItem {
                    Image(systemName: (selected == 0 ? "star.fill" : "star"))
                    Text("One")
                }.tag(0)
            MySecondView()
                .tabItem {
                    Image(systemName: (selected == 1 ? "star.fill" : "star"))
                    Text("Two")
                }.tag(1)
            MyThirdView()
                .tabItem {
                    Image(systemName: (selected == 2 ? "star.fill" : "star"))
                    Text("Three")
                }.tag(2)
        }
        .edgesIgnoringSafeArea(.all) // Important if you want NavigationViews to go under the status bar...
    }
}
person D.C.    schedule 23.09.2019
comment
Привет, у меня точная проблема с использованием TabView и представления навигации. Однако, если я установлю .edgesIgnoringSafeArea (.all), все будет развернуто за пределы экрана. Как мне это исправить? - person user2153984; 18.10.2019
comment
Попробуйте EdgeIgnoringSafeArea ([. Top, .bottom]) или, возможно, вам нужен только .top (в зависимости от вашего просмотра) - person D.C.; 20.10.2019

TabbedView() устарел, используйте вместо него TabView().

Использование целых чисел для выбора представлений дурно для меня, с тех пор как я работал с tag() UIButton и UIView, лучше перечислить то, что вы делаете, а не назначать жестко закодированные значения с очень большим диапазоном. то есть от Int.min() до Int.max(). Это также упрощает чтение и поддержку кода в будущем.

TabView(selection: ) можно использовать для выбора индекса и объявляется как:

public struct TabView<SelectionValue, Content> : View where SelectionValue : Hashable, Content : View {
    public init(selection: Binding<SelectionValue>?, @ViewBuilder content: () -> Content)
…

Это означает, что вы можете выбрать индекс с любым хешируемым содержимым.

Мы можем использовать enum, который соответствует Hashable, чтобы содержать список вкладок. Таким образом, мы можем использовать Observable позже, чтобы помочь контролировать и загружать состояние представления. Или сделайте перечисление частью состояния вашего приложения. Я уверен, что есть много ресурсов, которые вы можете использовать, чтобы найти подходящее решение, отвечающее вашим потребностям.

 struct MainTabView: View {

 @State private var selection: Tabs = .profile

 private enum Tabs: Hashable {
     case content
     case profile
 }

 var body: some View {

    TabView(selection: $selection) {

        // Learn Content
        Text("The First Tab")
            .tabItem {
                Image(systemName: "book")
                Text("Learn")
        }.tag(Tabs.content)


        // The Users Profile View.
        ProfileView()
            .tabItem {
                Image(systemName: "person.circle")
                Text("Profile")
        }.tag(Tabs.profile)
    }

  }
}
person RLoniello    schedule 29.12.2019

Ваш код должен работать, однако это известная проблема из release_notes" rel="nofollow noreferrer">iOS и Примечания к выпуску iPadOS 13 Beta 2:

Модификатор tabItemLabel (_ :) не принимает закрытие @ViewBuilder.

Единственный обходной путь, пока это не будет исправлено, - это использовать VStack, как вы упомянули.

MyView()
    .tabItemLabel(VStack {
        Image("resourceName")
        Text("Item")
    })

Обновлять:

Эта проблема была устранена в Xcode 11 beta 3:

Модификатор tabItemLabel (:) - теперь названный tabItem ( :) - теперь принимает закрытие @ViewBuilder.

Пример:

.tabItem {
    Image(systemName: "circle")
    Text("Tab1")
}
person M Reza    schedule 25.06.2019

TabbedView устарел.

Вместо этого вы можете использовать TabView сейчас

struct AppTabbedView: View {
    @State private var selection = 3

    var body: some View {
        TabView (selection:$selection){
            Text("The First Tab")
                .tabItem {
                    Image(systemName: "1.square.fill")
                    Text("First")

            }
            .tag(1)
            Text("Another Tab")
                .tabItem {
                    Image(systemName: "2.square.fill")
                    Text("Second")
            }.tag(2)
            Text("The Last Tab")
                .tabItem {
                    Image(systemName: "3.square.fill")
                    Text("Third")
            }.tag(3)
        }
        .font(.headline)
    }
}
person Amir.n3t    schedule 11.08.2019

с Xcode 11 GM этот код работает: (из https://developer.apple.com/documentation/swiftui/tabview)

TabView {
    Text("The First Tab")
        .tabItem {
            Image(systemName: "1.square.fill")
            Text("First")
        }
    Text("Another Tab")
        .tabItem {
            Image(systemName: "2.square.fill")
            Text("Second")
        }
    Text("The Last Tab")
        .tabItem {
            Image(systemName: "3.square.fill")
            Text("Third")
        }
}
.font(.headline)

person Antoine Weber    schedule 13.09.2019

TabbedView устарел и был переименован в TabView. Вы можете использовать TabView следующим образом

TabView {
    (Text("Tab 1!").tabItem {
         Text("First")
    })
    (Text("Tab 2!").tabItem {
         Text("Second")
    })
}
person Awesome.Apple    schedule 01.10.2019

TabbedView можно использовать следующим образом:

    struct TabView : View {

        @State private var selection = 1

        var body: some View {
            TabbedView (selection: $selection) {
                InboxList()
                    .tabItemLabel(selection == 1 ? Image("second") : Image("first"))
                    .tag(1)

                PostsList()
                    .tabItemLabel(Image("first"))
                    .tag(2)

                Something()
                    .tabItemLabel(Image("first"))
                    .tag(3)
            }
        }
    }

Я не уверен, почему ваш пример не компилируется, но вы пропускаете параметр selection и свойство .tag на каждой «вкладке».

Кстати, в текущей версии XCode (бета 2) вы не можете отображать как текст, так и изображение в качестве метки.

person Bogdan Farca    schedule 25.06.2019