How to update an item inside if a TabView with .tabViewStyle(.page) in ios lower than 17?

48 views Asked by At

In my project, we work with constantly update of components. In a specific screen, we have a TabView with a dynamic list of items, these items may be updated. The problem is: If these items is inside a TabView with .tabViewStyle(.page), the item updated isn’t updated. I made a example code that can reproduce this behavior:

struct TextUIModel: Identifiable, Equatable {
    let id = UUID()
    
    let title: String
    let state: String
}

public class TextUIViewModel: ObservableObject {
    @Published var models: [TextUIModel] = [
        .init(title: "Title", state: "1"),
        .init(title: "Title", state: "2")
    ]

    func updateModel() {
        models[0] = .init(title: "Title", state: "2")
        
    }
}

public struct TextUIModelsContentView: View {
    @StateObject var viewModel: TextUIViewModel = .init()
    
    public init() {}
    
    public var body: some View {
        
        if viewModel.models.isEmpty { 
            Text("Empty") 
        } else {             
            TabViewForTExtUIModels(models: viewModel.models) 
        }
        
        Button("Update states") { viewModel.updateModel() }
    }
}

struct TabViewForTExtUIModels: View {
    let models: [TextUIModel]
    
    var body: some View {
        VStack {
            if !models.isEmpty {
                TabView {
                    ForEach(models) { model in
                        VStack {
                            Text(model.title)
                            Text(model.state)
                        }
                    }
                }
                .tabViewStyle(.page)
            } else {
                EmptyView()
            }
        }
    }
}

When the button is pressed, nothing happens, but if I change the TabView for a ScrollView works:

struct TabViewForTExtUIModels: View {
    let models: [TextUIModel]
    
    var body: some View {
        VStack {
            if !models.isEmpty {
                ScrollView {
                    LazyHStack {
                        ForEach(models) { model in
                            VStack {
                                Text(model.title)
                                Text(model.state)
                            }
                        }
                    }
                }
            } else {
                EmptyView()
            }
        }
    }
}

I tried manage the update using State and Binding, but nothing works

To have the behavior of a TabView with .tabViewStyle(.page) is a part of the demand

I tried a lot of things but nothing works, only taking off the TabView that is not an option.

Can anyone help me ?

1

There are 1 answers

0
J W On

There is the way

import SwiftUI

struct TabViewForTExtUIModels: View {
  @ObservedObject var viewModel = MainModel()
  
  var body: some View {
    VStack {
      Button(action: {
        //When complex processing is required, it is recommended to write functions inside MainModel because it is easier to manage. Like removeItem.
        let newItem = TextUIViewModel(title: "Title", state: String(viewModel.models.count))
        viewModel.models.append(newItem)
      }) {
        Text("addNew")
      }
      TabView {
        ForEach(viewModel.models) { model in
          VStack {
            Text(model.title)
            Text(model.state)
            Button(action: {
              viewModel.removeItem(item: model)
            }) {
              Text("remove")
            }
          }
        }
      }
      .tabViewStyle(.page)
    }
  }
}


class MainModel: ObservableObject {
  @Published var models: [TextUIViewModel] = []
  
  init() {
    let newModels = (0..<10).map { TextUIViewModel(title: "Title", state: String($0)) }
    models.append(contentsOf: newModels)
  }
  
  func removeItem(item: TextUIViewModel) {
    models.remove(at: models.firstIndex(of: item)!)
  }
}

struct TextUIViewModel: Identifiable, Equatable {
  let id = UUID()
  var title: String
  var state: String
}