SwiftUI:分段控制滚动
SwiftUI: Segmented Control scrolling
我正在使用分段控件在选项卡之间导航。
我的问题是,当我在一个选项卡内滚动时,所有其他选项卡也在漫步。这是我不想要的。
我希望滚动仅在所选选项卡内有效,当我单击其他选项卡时,它显示所选选项卡内容的顶部。
查看附加视频:https://imgur.com/a/Oxka4hv
这是我的代码
谢谢!
import SwiftUI
struct ContentView: View {
@State var selectedState = 0
@State var showTopTabBar: Bool = false
var body: some View {
ZStack (alignment: . top){
ScrollView (showsIndicators: false){
Text("Welcome")
.frame(height: 300)
Picker("Options", selection: $selectedState) {
Text("First").tag(0)
Text("Second").tag(1)
Text("Third").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
.background(Color.white)
.opacity(showTopTabBar ? 0 : 1)
.readPos { rect in
if showTopTabBar != (rect.minY <= 100) {
showTopTabBar.toggle()
}
}
if (selectedState==0) {
FirstView()
}
else if (selectedState==1){
Secondview()
}
else {
ThirdView()
}
Spacer()
}
.padding()
Picker("Options", selection: $selectedState) {
Text("First").tag(0)
Text("Second").tag(1)
Text("Third").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
.padding()
.background(Color.white)
.opacity(showTopTabBar ? 1 : 0)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
extension View {
func readPos(onChange: @escaping (CGRect) -> Void) -> some View {
background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: CoordinatesPreferenceKey.self, value: geometryProxy.frame(in: .global))
}
)
.onPreferenceChange(CoordinatesPreferenceKey.self, perform: onChange)
}
}
private struct CoordinatesPreferenceKey: PreferenceKey {
static var defaultValue: CGRect = .zero
static func reduce(value: inout CGRect, nextValue: () -> CGRect) {}
}
您可以使用 ScrollViewReader
向上滚动以开始更改选项卡:
struct ContentView: View {
@State var selectedState = 0
@State var showTopTabBar: Bool = false
var body: some View {
ZStack (alignment: . top) {
ScrollView (showsIndicators: false) {
// added ScrollViewReader
ScrollViewReader { scrollProxy in
Text("Welcome")
.frame(height: 300)
.id("welcome") // added id to scroll to
tabPicker
.background(Color.white)
.opacity(showTopTabBar ? 0 : 1)
.readPos { rect in
if showTopTabBar != (rect.minY <= 100) {
showTopTabBar.toggle()
}
}
if (selectedState==0) {
ListContentView(tab: "First View", color: .blue)
}
else if (selectedState==1){
ListContentView(tab: "Second View", color: .green)
}
else {
ListContentView(tab: "Third View", color: .orange)
}
Spacer()
// on Change of selected Tab scroll to top
.onChange(of: selectedState) { newValue in
scrollProxy.scrollTo("welcome", anchor: .center)
}
}
}
.padding()
tabPicker
.padding()
.background(Color.white)
.opacity(showTopTabBar ? 1 : 0)
}
}
var tabPicker: some View {
Picker("Options", selection: $selectedState) {
Text("First").tag(0)
Text("Second").tag(1)
Text("Third").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
}
}
// dummy content view
struct ListContentView: View {
let tab: String
let color: Color
var body: some View {
ForEach(0..<30) { item in
Text("\(tab) - \(item)")
.padding()
.frame(maxWidth: .infinity)
.background(color)
}
}
}
这现在总是在切换 Tab 时向上滚动。如果您想保留每个选项卡中的位置,您必须根据显示内容的 .id
将它们保存在@State 变量中。
我正在使用分段控件在选项卡之间导航。 我的问题是,当我在一个选项卡内滚动时,所有其他选项卡也在漫步。这是我不想要的。
我希望滚动仅在所选选项卡内有效,当我单击其他选项卡时,它显示所选选项卡内容的顶部。
查看附加视频:https://imgur.com/a/Oxka4hv
这是我的代码
谢谢!
import SwiftUI
struct ContentView: View {
@State var selectedState = 0
@State var showTopTabBar: Bool = false
var body: some View {
ZStack (alignment: . top){
ScrollView (showsIndicators: false){
Text("Welcome")
.frame(height: 300)
Picker("Options", selection: $selectedState) {
Text("First").tag(0)
Text("Second").tag(1)
Text("Third").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
.background(Color.white)
.opacity(showTopTabBar ? 0 : 1)
.readPos { rect in
if showTopTabBar != (rect.minY <= 100) {
showTopTabBar.toggle()
}
}
if (selectedState==0) {
FirstView()
}
else if (selectedState==1){
Secondview()
}
else {
ThirdView()
}
Spacer()
}
.padding()
Picker("Options", selection: $selectedState) {
Text("First").tag(0)
Text("Second").tag(1)
Text("Third").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
.padding()
.background(Color.white)
.opacity(showTopTabBar ? 1 : 0)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
extension View {
func readPos(onChange: @escaping (CGRect) -> Void) -> some View {
background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: CoordinatesPreferenceKey.self, value: geometryProxy.frame(in: .global))
}
)
.onPreferenceChange(CoordinatesPreferenceKey.self, perform: onChange)
}
}
private struct CoordinatesPreferenceKey: PreferenceKey {
static var defaultValue: CGRect = .zero
static func reduce(value: inout CGRect, nextValue: () -> CGRect) {}
}
您可以使用 ScrollViewReader
向上滚动以开始更改选项卡:
struct ContentView: View {
@State var selectedState = 0
@State var showTopTabBar: Bool = false
var body: some View {
ZStack (alignment: . top) {
ScrollView (showsIndicators: false) {
// added ScrollViewReader
ScrollViewReader { scrollProxy in
Text("Welcome")
.frame(height: 300)
.id("welcome") // added id to scroll to
tabPicker
.background(Color.white)
.opacity(showTopTabBar ? 0 : 1)
.readPos { rect in
if showTopTabBar != (rect.minY <= 100) {
showTopTabBar.toggle()
}
}
if (selectedState==0) {
ListContentView(tab: "First View", color: .blue)
}
else if (selectedState==1){
ListContentView(tab: "Second View", color: .green)
}
else {
ListContentView(tab: "Third View", color: .orange)
}
Spacer()
// on Change of selected Tab scroll to top
.onChange(of: selectedState) { newValue in
scrollProxy.scrollTo("welcome", anchor: .center)
}
}
}
.padding()
tabPicker
.padding()
.background(Color.white)
.opacity(showTopTabBar ? 1 : 0)
}
}
var tabPicker: some View {
Picker("Options", selection: $selectedState) {
Text("First").tag(0)
Text("Second").tag(1)
Text("Third").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
}
}
// dummy content view
struct ListContentView: View {
let tab: String
let color: Color
var body: some View {
ForEach(0..<30) { item in
Text("\(tab) - \(item)")
.padding()
.frame(maxWidth: .infinity)
.background(color)
}
}
}
这现在总是在切换 Tab 时向上滚动。如果您想保留每个选项卡中的位置,您必须根据显示内容的 .id
将它们保存在@State 变量中。