Ios SwiftUI可滚动选项卡栏通过项目设置动画错误
我通过可滚动的选项卡栏项目构建了pageView。如果用户滚动“不是那么快”,效果非常好,但是如果用户滚动项目的速度非常快,视图浮动并且行为非常奇怪,则会出现问题,动画似乎无法跟随用户交互 我想知道,如果有人有解决方案,仍然有流体动画独立如何用户快速滚动 ContentViewIos SwiftUI可滚动选项卡栏通过项目设置动画错误,ios,swift,xcode,swiftui,Ios,Swift,Xcode,Swiftui,我通过可滚动的选项卡栏项目构建了pageView。如果用户滚动“不是那么快”,效果非常好,但是如果用户滚动项目的速度非常快,视图浮动并且行为非常奇怪,则会出现问题,动画似乎无法跟随用户交互 我想知道,如果有人有解决方案,仍然有流体动画独立如何用户快速滚动 ContentView struct ContentView: View { @State private var selection = 1 //selected page let dataModel = ["Forums"
struct ContentView: View {
@State private var selection = 1 //selected page
let dataModel = ["Forums", "Learn", "Careers", "Store", "About"]
var body: some View {
NavigationView {
VStack {
//ScrollableTabView
ScrollView(.horizontal, showsIndicators: false, content: {
ScrollViewReader { scrollReader in
ScrollableTabView(activeIdx: $selection,dataSet: dataModel)
.padding(.top).onChange(of: selection, perform: { value in
withAnimation{
scrollReader.scrollTo(value, anchor: .center)
}
})
}
})
.background(Color(UIColor.secondarySystemFill))
//Page View
LazyHStack {
PageView(selection: $selection, dataModel: dataModel)
}
}
.navigationBarTitle("Demo", displayMode: .inline)
}.onChange(of: selection, perform: { value in
//update tab
})
}
}
分页
struct PageView: View {
@Binding var selection: Int
let dataModel: [String]
var body: some View {
TabView(selection:$selection) {
ForEach(0..<dataModel.count) { i in
VStack {
HStack {
Text(dataModel[i])
.foregroundColor(Color.primary)
.padding()
Spacer()
}
Spacer()
}.tag(i)
}
}
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height - 170)
//give padding nav height + scrollable Tab
.tabViewStyle(PageTabViewStyle.init(indexDisplayMode: .never))
}
}
struct页面视图:视图{
@绑定变量选择:Int
let dataModel:[字符串]
var body:一些观点{
选项卡视图(选择:$selection){
ForEach(0..CGFloat{
返回d[前导]
}
}
静态let underlineLeading=水平对齐(underlineLeading.self)
}
结构宽度首选项键:首选项键{
静态var defaultValue=CGFloat(0)
静态函数reduce(值:inout CGFloat,nextValue:()->CGFloat){
value=nextValue()
}
typealias值=CGFloat
}
结构ScrollableTabView:视图{
@绑定变量activeIdx:Int
@国有-私有var w:[CGFloat]
私有let数据集:[字符串]
初始化(activeIdx:绑定,数据集:[字符串]){
self.\u activeIdx=activeIdx
self.dataSet=dataSet
_w=State.init(initialValue:[CGFloat](重复:0,计数:dataSet.count))
}
var body:一些观点{
VStack(对齐:。下划线删除){
HStack{
ForEach(0..some视图{
团体{
如果activeIdx==idx{
content.alignmentGuide(.underlineEleding){d在中
返回d[前导]
}.ontapsigne{
动画片{
self.activeIdx=self.idx
}
}
}否则{
content.ontaps{
动画片{
self.activeIdx=self.idx
}
}
}
}
}
}
结构内容视图\u预览:PreviewProvider{
静态var预览:一些视图{
ContentView()
}
}
extension HorizontalAlignment {
private enum UnderlineLeading: AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
return d[.leading]
}
}
static let underlineLeading = HorizontalAlignment(UnderlineLeading.self)
}
struct WidthPreferenceKey: PreferenceKey {
static var defaultValue = CGFloat(0)
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
typealias Value = CGFloat
}
struct ScrollableTabView : View {
@Binding var activeIdx: Int
@State private var w: [CGFloat]
private let dataSet: [String]
init(activeIdx: Binding<Int>, dataSet: [String]) {
self._activeIdx = activeIdx
self.dataSet = dataSet
_w = State.init(initialValue: [CGFloat](repeating: 0, count: dataSet.count))
}
var body: some View {
VStack(alignment: .underlineLeading) {
HStack {
ForEach(0..<dataSet.count) { i in
Text(dataSet[i])
.font(Font.title2.bold())
.modifier(ScrollableTabViewModifier(activeIdx: $activeIdx, idx: i))
.background(TextGeometry())
.onPreferenceChange(WidthPreferenceKey.self, perform: { self.w[i] = $0 })
.id(i)
Spacer().frame(width: 20)
}
}
.padding(.horizontal, 5)
Rectangle()
.alignmentGuide(.underlineLeading) { d in d[.leading] }
.frame(width: w[activeIdx], height: 4)
.animation(.linear)
}
}
}
struct TextGeometry: View {
var body: some View {
GeometryReader { geometry in
return Rectangle().fill(Color.clear).preference(key: WidthPreferenceKey.self, value: geometry.size.width)
}
}
}
struct ScrollableTabViewModifier: ViewModifier {
@Binding var activeIdx: Int
let idx: Int
func body(content: Content) -> some View {
Group {
if activeIdx == idx {
content.alignmentGuide(.underlineLeading) { d in
return d[.leading]
}.onTapGesture {
withAnimation{
self.activeIdx = self.idx
}
}
} else {
content.onTapGesture {
withAnimation{
self.activeIdx = self.idx
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}