How to Change Pagetabview Programmatically in iOS 14, Swiftui 2

How to change PageTabView programmatically in iOS 14, SwiftUI 2?

Here is a demo of solution. Tested with Xcode 12 / iOS 14

demo

struct OnBoardingView: View {
@State private var selectedPage = 0
var body: some View {
VStack {
HStack {
Button("<") { if selectedPage > 0 {
withAnimation { selectedPage -= 1 }
} }
Spacer().frame(width: 40)
Button(">") { if selectedPage < 2 {
withAnimation { selectedPage += 1 }
} }
}
TabView(selection: $selectedPage) {
Text("Hi").tag(0)
Text("Hello").tag(1)
Text("Welcome").tag(2)
}
.tabViewStyle(PageTabViewStyle())
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
}
}
}

Programmatically change to another tab in SwiftUI

You just need to update a @State variable responsible for the selection. But if you want to do it from a child View you can pass it as a @Binding variable:

struct ContentView: View {
@State private var tabSelection = 1

var body: some View {
TabView(selection: $tabSelection) {
FirstView(tabSelection: $tabSelection)
.tabItem {
Text("Tab 1")
}
.tag(1)
Text("tab 2")
.tabItem {
Text("Tab 2")
}
.tag(2)
}
}
}
struct FirstView: View {
@Binding var tabSelection: Int
var body: some View {
Button(action: {
self.tabSelection = 2
}) {
Text("Change to tab 2")
}
}
}

SwiftUI: customizing TabView's PageTabViewStyle to show tags instead of dots

Just use style PageIndexViewStyle.never and change tabs programmatically on tags selection as in https://stackoverflow.com/a/62833840/12299030.

swiftUI tabView pagetabviewstyle - button to next is not working

The reason for this not working is the type mismatch in your models id and the selection var.


Detail:

TabView(selection: $currentPage){
ForEach(guidelists){i in

these two lines tell the compiler that the id for every element is of type UUID (because GuideList is identifieable and id is of type UUID. Thats fine for itself, but TabView has a selection var of type Int (currentPage is an Int) so it is not working. So changing one of both types to equal the other will solve the problem.


easy example:

Change your code to:

struct GuideList: Identifiable, Hashable{//가이드리스트 구조체, 이미지와 설명넣기
let id: Int
let image: String
let explain: String
}

let guidelists = [
GuideList(id: 0, image: "image1",explain: "explain1."),
GuideList(id: 1, image: "image2",explain: "explain2." ),
GuideList(id: 2, image: "image3",explain: "explain3." )
]

Move Index View above home indicator in Tab View

EDIT: See also @nekno's fantastic additions!


This is possible if you create a custom UIPageControl, manually tag each tab in the TabView, and make sure to keep track of the numberOfPages:

struct PageControlView: UIViewRepresentable {
@Binding var currentPage: Int
@Binding var numberOfPages: Int

func makeUIView(context: Context) -> UIPageControl {
let uiView = UIPageControl()
uiView.backgroundStyle = .prominent
uiView.currentPage = currentPage
uiView.numberOfPages = numberOfPages
return uiView
}

func updateUIView(_ uiView: UIPageControl, context: Context) {
uiView.currentPage = currentPage
uiView.numberOfPages = numberOfPages
}
}

struct ContentView: View {
@State var isSheetUp = false

var body: some View {
Button("Present") {
isSheetUp.toggle()
}
.sheet(isPresented: $isSheetUp) {
Sheet()
}
}

struct Sheet: View {
@State var currentPage = 0
@State var numberOfPages = 3

var body: some View {
NavigationView {
ZStack {
TabView(selection: $currentPage) {
Page().tag(0)
Page().tag(1)
Page().tag(2)
}
// Comment this to switch layout issue
.ignoresSafeArea(edges: .bottom)
.tabViewStyle(.page(indexDisplayMode: .never))
.indexViewStyle(.page(backgroundDisplayMode: .always))
.navigationTitle("Title")
.navigationBarTitleDisplayMode(.inline)

VStack {
Spacer()
PageControlView(currentPage: $currentPage, numberOfPages: $numberOfPages)
}
}
}
}
}

struct Page: View {
var body: some View {
ScrollView {
VStack {
Rectangle()
.foregroundColor(.teal)
.padding()
.frame(minHeight: 10000)
}
}.background(Color.brown)
}
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Move Index View above home indicator in Tab View

EDIT: See also @nekno's fantastic additions!


This is possible if you create a custom UIPageControl, manually tag each tab in the TabView, and make sure to keep track of the numberOfPages:

struct PageControlView: UIViewRepresentable {
@Binding var currentPage: Int
@Binding var numberOfPages: Int

func makeUIView(context: Context) -> UIPageControl {
let uiView = UIPageControl()
uiView.backgroundStyle = .prominent
uiView.currentPage = currentPage
uiView.numberOfPages = numberOfPages
return uiView
}

func updateUIView(_ uiView: UIPageControl, context: Context) {
uiView.currentPage = currentPage
uiView.numberOfPages = numberOfPages
}
}

struct ContentView: View {
@State var isSheetUp = false

var body: some View {
Button("Present") {
isSheetUp.toggle()
}
.sheet(isPresented: $isSheetUp) {
Sheet()
}
}

struct Sheet: View {
@State var currentPage = 0
@State var numberOfPages = 3

var body: some View {
NavigationView {
ZStack {
TabView(selection: $currentPage) {
Page().tag(0)
Page().tag(1)
Page().tag(2)
}
// Comment this to switch layout issue
.ignoresSafeArea(edges: .bottom)
.tabViewStyle(.page(indexDisplayMode: .never))
.indexViewStyle(.page(backgroundDisplayMode: .always))
.navigationTitle("Title")
.navigationBarTitleDisplayMode(.inline)

VStack {
Spacer()
PageControlView(currentPage: $currentPage, numberOfPages: $numberOfPages)
}
}
}
}
}

struct Page: View {
var body: some View {
ScrollView {
VStack {
Rectangle()
.foregroundColor(.teal)
.padding()
.frame(minHeight: 10000)
}
}.background(Color.brown)
}
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

SwiftUI how to keep track of page index in PageTabViewStyle?

You can pass a selection binding to the TabView and use tag to identify the pages:

struct ContentView: View {
@State var pageIndex = 0

var body: some View {
VStack {
Text("current page = \(pageIndex) ")
TabView(selection: $pageIndex) {
Text("First").tag(0)
Text("Second").tag(1)
Text("Third").tag(2)
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
}
}
}

Note that in your original code, it was always going to say current page = 0 because you weren't interpolating the pageIndex variable into the string

SwiftUI TabView PageStyle with an optional page

Force refresh tab view by .id

TabView {
.......
.......
}.id(model.on)


Related Topics



Leave a reply



Submit