SwiftUI makes UIViewRepresentable flicker while updating

Viewed 49

I am rewriting the existing UIKit cell with SwiftUI. ChartView inside of it I wrapped with UIViewRepresentable because it is out of scope right now to rewrite it as well. The data for the chart I am getting async and update the view once I have it. The viewModel for the chart I marked as @Published so SwiftUI knows when to update the view. The problem is the view flickers once the update is there.

View:

struct DashboardWatchlistView: View {

    @ObservedObject var viewModel: DashboardWatchlistViewModel

    var body: some View {
        VStack(alignment: .center) {
            ZStack {
                HStack(spacing: 4) {
                    HStack(spacing: 16) {
                        Image(systemName: "person")

                        VStack(alignment: .leading, spacing: .designSystem(8) {
                            HStack {
                                Text(viewModel.leftTitle).font(.subheadline).fontWeight(.semibold).lineLimit(1)
                            }
                            Text(viewModel.leftSubtitle).font(.caption2).foregroundColor(Color(ThemeManager.current.neutral50))
                        }
                    }

                    Spacer()

                    if let chartViewModel = viewModel.chartViewModel {
                        AssetLineChartViewRepresentable(viewModel: chartViewModel).frame(width: 65, height: 20)
                    }

                    VStack(alignment: .trailing, spacing: .designSystem(.extraSmall3)) {
                        percentChangeView(assetPercentChangeType: viewModel.assetPercentChangeType)
                        Text(viewModel.rightSubtitle).font(.caption2).foregroundColor(Color(ThemeManager.current.neutral50))
                    }.padding(.leading, .designSystem(.medium))
                }

                .padding([.leading, .trailing])

                if !viewModel.hideSeparator {
                    VStack {
                        Spacer()
                        Divider().padding(.leading)
                    }
                }
            }
        }
    }
}

ViewModel:

final class DashboardWatchlistViewModel: ObservableObject {

    @Published var logoURL: URL?
    @Published var leftTitle = ""
    @Published var leftSubtitle = ""
    @Published var rightTitle = ""
    @Published var rightSubtitle = ""
    @Published var percentageChange: Decimal = .zero
    @Published var placeholderColor = ""
    @Published var corners: Corners = .none
    @Published var assetPercentChangeType: AssetPercentChangeType = .zero
    @Published var hideSeparator = false
    @Published var isHighlighted = false
    @Published var chartViewModel: AssetLineChartViewRepresentable.ViewModel?

    let chartDataEvent: AnyPublisher<BPChartData?, Never>

    init(tradable: Tradable,
         priceString: String,
         percentageChange: Decimal,
         corners: Corners,
         hideSeparator: Bool,
         assetPercentChangeType: AssetPercentChangeType,
         chartDataEvent: AnyPublisher<BPChartData?, Never>) {
             self.logoURL = tradable.logoURL
             self.leftTitle = tradable.name
             self.rightTitle = PercentageFormatter.default.string(from: abs(percentageChange))
             self.leftSubtitle = tradable.symbol
             self.rightSubtitle = priceString
             self.percentageChange = percentageChange
             self.placeholderColor = tradable.placeholderColor ?? ""
             self.corners = corners
             self.chartDataEvent = chartDataEvent
             self.hideSeparator = hideSeparator
             self.assetPercentChangeType = assetPercentChangeType
    }
}

Cell where I set the chartViewModel:

final class DashboardWatchlistCell: UICollectionViewCell, HostingCell {

    var hostingController: UIHostingController<DashboardWatchlistView>?
    private var dashboardWatchlistView: DashboardWatchlistView?
    private var viewModel: DashboardWatchlistViewModel?

    private var cancellables = Set<AnyCancellable>()

    override var isHighlighted: Bool {
        didSet {
            viewModel?.isHighlighted = isHighlighted
        }
    }

    func configure(with viewModel: DashboardWatchlistViewModel) {
        self.dashboardWatchlistView = DashboardWatchlistView(viewModel: viewModel)
        self.viewModel = viewModel

        // HERE I SET THE VIEWMODEL
        viewModel.chartDataEvent.compactMap { $0 }
        .receive(on: DispatchQueue.main)
        .sink { chartData in
            viewModel.chartViewModel = AssetLineChartViewRepresentable.ViewModel(chartData: chartData, percentageChange: viewModel.percentageChange)
        }
        .store(in: &cancellables)
    }

    func addHostedView(to parent: UIViewController) {
        guard let dashboardWatchlistView = dashboardWatchlistView else { return }

        addHostedView(dashboardWatchlistView, to: parent)

        backgroundColor = .clear
    }
}

enter image description here

0 Answers
Related