Post

Replies

Boosts

Views

Activity

Zoom navigation transitions for tabViewBottomAccessory are not working in SwiftUI with ObservableObject or Observable
The zoom navigation transition with matchedTransitionSource in tabViewBottomAccessory does not work when a Published var in an ObservableObjector Observable gets changed. Here is an minimal reproducible example with ObservableObject: import SwiftUI import Combine private final class ViewModel: ObservableObject { @Published var isPresented = false } struct ContentView: View { @Namespace private var namespace @StateObject private var viewModel = ViewModel() // @State private var isPresented = false var body: some View { TabView { Button { viewModel.isPresented = true } label: { Text("Start") } .tabItem { Image(systemName: "house") Text("Home") } Text("Search") .tabItem { Image(systemName: "magnifyingglass") Text("Search") } Text("Profile") .tabItem { Image(systemName: "person") Text("Profile") } } .sheet(isPresented: $viewModel.isPresented) { Text("Sheet") .presentationDragIndicator(.visible) .navigationTransition(.zoom(sourceID: "tabViewBottomAccessoryTransition", in: namespace)) } .tabViewBottomAccessory { Button { viewModel.isPresented = true } label: { Text("BottomAccessory") } .matchedTransitionSource(id: "tabViewBottomAccessoryTransition", in: namespace) } } } However, when using only a State property everything works: import SwiftUI import Combine private final class ViewModel: ObservableObject { @Published var isPresented = false } struct ContentView: View { @Namespace private var namespace // @StateObject private var viewModel = ViewModel() @State private var isPresented = false var body: some View { TabView { Button { isPresented = true } label: { Text("Start") } .tabItem { Image(systemName: "house") Text("Home") } Text("Search") .tabItem { Image(systemName: "magnifyingglass") Text("Search") } Text("Profile") .tabItem { Image(systemName: "person") Text("Profile") } } .sheet(isPresented: $isPresented) { Text("Sheet") .presentationDragIndicator(.visible) .navigationTransition(.zoom(sourceID: "tabViewBottomAccessoryTransition", in: namespace)) } .tabViewBottomAccessory { Button { isPresented = true } label: { Text("BottomAccessory") } .matchedTransitionSource(id: "tabViewBottomAccessoryTransition", in: namespace) } } }
0
0
49
4d
SwiftUI: Setting offset for View in TabView causes stuttering
I'm trying to create a parallax effect for a specific view in a TabView. The problem is that the view slightly stutters while being dragged. That's why I created a small project to determine if the problem originates from my app or the TabView. I've noticed that my test project also has a similar problem. Is there a workaround to prevent this stuttering effect? The stuttering effect is more pronounced on a real device (I tried it on the iPhone 14 Pro with iOS 17). I've asked the same question in StackOverflow: https://stackoverflow.com/questions/77228741/swiftui-setting-offset-for-view-in-tabview-causes-stuttering Below is my test project: import SwiftUI struct ContentView: View { @State private var currentIndex: Int = .zero var body: some View { TabView(selection: $currentIndex) { ForEach(0..<10) { index in TabViewContentView(text: String(UUID().uuidString.prefix(Constant.prefixLength)), isVisible: index == currentIndex) .tag(index) } } .tabViewStyle(PageTabViewStyle()) } private enum Constant { static let prefixLength = 7 } } private struct TabViewContentView: View { private let text: String private let isVisible: Bool @State private var offset: CGFloat = .zero init(text: String, isVisible: Bool = true) { self.text = text self.isVisible = isVisible } var body: some View { VStack { Color.blue.frame(maxWidth: .infinity, maxHeight: .infinity) .overlay(alignment: .bottomLeading) { Text(text) .font(.largeTitle) .offset(x: offset) } .opacity(isVisible ? 1 : .zero) Color.green.frame(maxWidth: .infinity, maxHeight: .infinity) } .tabViewOffsetListener { newOffset in var parallaxOffset: CGFloat = .zero parallaxOffset = isVisible ? newOffset * -Constant.parallaxMultiplier : newOffset DispatchQueue.main.async { offset = parallaxOffset } } } private enum Constant { static let parallaxMultiplier = 0.7 } } private struct TabViewOffsetViewModifier: ViewModifier { private let offsetHandler: (CGFloat) -> Void private let clearColorView = Color.clear init(offsetHandler: @escaping (CGFloat) -> Void) { self.offsetHandler = offsetHandler } func body(content: Content) -> some View { content .background( GeometryReader { proxy -> Color in let dragOffset = proxy.frame(in: .global).minX offsetHandler(dragOffset) return clearColorView } ) } } public extension View { func tabViewOffsetListener(offsetHandler: @escaping (CGFloat) -> Void) -> some View { modifier(TabViewOffsetViewModifier(offsetHandler: offsetHandler)) } }
0
0
541
Oct ’23