0

I am working on a dynamic indicator for a tabView to show a slideshow of images (say 5 images). I am using GeometryReader to determine the minX position of the first picture. This works fine until I scroll to the third picture, where the minX is no longer read.

Here is the code:

struct topTabView: View {

private var numberOfImages = ["0", "1", "2", "3", "4"]

@State private var currentIndex = 0
@State var offset: CGFloat = 0

var body: some View {
    ScrollView(.init()){
        TabView(selection: $currentIndex) {
            ForEach(numberOfImages.indices, id: \.self) { index in
                
                if index == 0 {
                    Image("\(numberOfImages[index])")
                        .resizable()
                        .scaledToFill()
                        .overlay(
                            GeometryReader { proxy -> Color in
                                
                                let minX = proxy.frame(in: .global).minX
                                
                                DispatchQueue.main.async {
                                    withAnimation(.default) {
                                        self.offset = -minX
                                    }
                                }
                                
                                return Color.clear
                            }.frame(width: 0, height: 0)
                            
                            ,alignment: .leading
                            
                        )
                } else {
                    Image("\(numberOfImages[index])")
                        .resizable()
                        .scaledToFill()
                        .overlay(Color.black.opacity(0.2))
                }
            }//: ForEach
        } //: TabView
        .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
        .overlay(
            
            HStack(spacing:15) {
                
                ForEach(numberOfImages.indices, id: \.self) { index in
                    
                    Capsule()
                        .fill(Color.white)
                        .frame(width: getIndex() == index ? 20 : 7, height: 7)
                }
                
            }
    
            //Smooth Sliding effect...
                .overlay(
                    Capsule()
                        .fill(Color.white)
                        .frame(width: 20, height: 7)
                        .offset(x: getOffset())
                    , alignment: .leading
                )
                .padding(.bottom, UIApplication.shared.connectedScenes.flatMap { ($0 as? UIWindowScene)?.windows ?? [] }.first { $0.isKeyWindow }?.safeAreaInsets.bottom)
                .padding(.bottom, 10)
            
            , alignment: .bottom
        )
       
    } //: Scrollview
    .ignoresSafeArea()

} //: body

func getIndex() -> Int {
    
    print("DEBUG: Current offset is: \(offset)")
    print("DEBUG: Current getWidth is: \(getWidth())")

    let progress = round(offset / getWidth())
    let index = min(Int(progress), numberOfImages.count - 1)
    print("DEBUG: Current index is: \(index)")
    return index
}

func getOffset() -> CGFloat {
    // spacing = 15
    // Circle width = 7
    // So total = 22
    
    let progress = offset / getWidth()
    
    return 22 * progress
}}



  extension View {
func getWidth() -> CGFloat {
    return UIScreen.main.bounds.width
}}

enter image description here

enter image description here

As you can see if i scroll to the 3rd picture, it stops calculating my offset. As my screen width is 390, i would expect the offset to be 780 (and 1170 after my 4th picture), but as you can see it stopped counting at 510.

Hope to hear from you all.

Daniel C
  • 113
  • 1
  • 8

0 Answers0