はじめに
基本的なTabViewではTabViewの活用に限界がある。
TabItemをカスタマイズし、一回タップで最初のページに戻り、2回目でスクロールを一番上に戻す機能を加える。
環境
Xcode 13.3.1
Code
MainTabView
struct MainTabView: View {
@EnvironmentObject var value : ValuesModel
@State var showNextPage = false
init(){
UITabBar.appearance().isHidden = true
}
@State var countForScroll = 0
@State var currentTab = "house"
var body: some View {
VStack {
TabView(selection: $currentTab){
HouseView(countForScroll: $countForScroll, showNextPage: $showNextPage)
.tag("house")
Text("message")
.tag("message")
Text("person")
.tag("person")
Text("mail")
.tag("mail")
}
.padding(.bottom)
}
.safeAreaInset(edge: .bottom) {
customtabview
}
}
private var customtabview : some View {
HStack(spacing: 0) {
TabVButton(image: "house")
TabVButton(image: "message")
TabVButton(image: "person")
TabVButton(image: "mail")
}
.background(Color.white)
}
@ViewBuilder
func TabVButton(image: String) -> some View {
Image(systemName: image)
.resizable()
.renderingMode(.template)
.aspectRatio(contentMode: .fit)
.frame(width: 23, height: 22)
.foregroundColor(currentTab == image ? .red : .gray )
.frame(maxWidth: .infinity)
.onTapGesture {
if currentTab == image {
if self.showNextPage {
self.showNextPage = false
} else {
self.countForScroll += 1
}
} else {
currentTab = image
}
}
}
}
HouseView
struct HouseView: View {
@EnvironmentObject var value : ValuesModel
@Binding var countForScroll : Int
@Binding var showNextPage : Bool
var body: some View {
NavigationView{
ScrollView {
ScrollViewReader{ ScrollViewProxy in
VStack{
HStack{Spacer()}
.id("Empty")
NavigationLink("", isActive: $showNextPage) {
NextView()
}
ForEach(0 ..< 20 ) { item in
HStack{
Spacer()
Text("\(item)")
Spacer()
}
.padding()
.background(Color.init(white: 0.9))
.cornerRadius(20)
}
Button {
self.showNextPage.toggle()
} label: {
Text("show next page")
}
}
.onReceive(value.$count) { XX in
withAnimation {
ScrollViewProxy.scrollTo("Empty", anchor: .top)
}
}
.onChange(of: countForScroll) { newValue in
value.count += 1
}
}
}
.navigationBarHidden(true)
}
}
}
NextView
struct NextView: View {
@State var nextPage2 = false
var body: some View {
VStack{
NavigationLink("", isActive: $nextPage2) {
Text("nextpage2")
}
Button {
self.nextPage2.toggle()
} label: {
Text("nextpage2")
}
}
}
}
ValuesModel
class ValuesModel: ObservableObject {
@Published var count = 1
}
自動スクロールのためのcountをenvironmentObjectとしてvaluesModelで管理することで、view 移動時にcountが初期化されることを防ぎました。
Screen
他のTabを押しても元のTabのViewの状態は残っている。
現在選択中のTabItemを一回タップ -> 最初のviewに戻る
2回目をタップ -> Scroll を一番上に戻す
より簡単な方法や質問があればコメントください。