From 262aadf8071ec6d1ca37b34b5579b0c37120caad Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 6 Sep 2020 22:47:02 -0400 Subject: [PATCH] Fix very bad performance when laying out Compose reply view Using a non-scrolling UITextView wrapped in SwiftUI combined with the old hack of fixing its layout by passing the view controller's width down to the wrapped view caused very slow layouts, resulting in significant lag when typing into the main text view of the compose screen. --- .../Compose/ComposeContainerView.swift | 8 +------- .../Compose/ComposeHostingController.swift | 10 ---------- .../Compose/ComposeReplyContentView.swift | 20 ++++++++----------- Tusker/Screens/Compose/ComposeReplyView.swift | 8 ++++++-- Tusker/Screens/Compose/ComposeView.swift | 10 +--------- 5 files changed, 16 insertions(+), 40 deletions(-) diff --git a/Tusker/Screens/Compose/ComposeContainerView.swift b/Tusker/Screens/Compose/ComposeContainerView.swift index 556ba6d3f4..0809a29e0b 100644 --- a/Tusker/Screens/Compose/ComposeContainerView.swift +++ b/Tusker/Screens/Compose/ComposeContainerView.swift @@ -11,24 +11,18 @@ import Combine struct ComposeContainerView: View { let mastodonController: MastodonController - let vcWidthSubject: PassthroughSubject @ObservedObject var uiState: ComposeUIState init( mastodonController: MastodonController, - vcWidthSubject: PassthroughSubject, uiState: ComposeUIState ) { self.mastodonController = mastodonController - self.vcWidthSubject = vcWidthSubject self.uiState = uiState } var body: some View { - ComposeView( - draft: uiState.draft, - vcWidthSubject: vcWidthSubject - ) + ComposeView(draft: uiState.draft) .environmentObject(mastodonController) .environmentObject(uiState) } diff --git a/Tusker/Screens/Compose/ComposeHostingController.swift b/Tusker/Screens/Compose/ComposeHostingController.swift index d996197c32..2fca4e6174 100644 --- a/Tusker/Screens/Compose/ComposeHostingController.swift +++ b/Tusker/Screens/Compose/ComposeHostingController.swift @@ -16,9 +16,6 @@ class ComposeHostingController: UIHostingController { let mastodonController: MastodonController let uiState: ComposeUIState - // storing the width in the UI state and having SwiftUI listen to it via @ObservedObject doesn't work - // it ends up spinning forever - let widthSubject = PassthroughSubject() var draft: Draft { uiState.draft } @@ -42,7 +39,6 @@ class ComposeHostingController: UIHostingController { // to use as the UIHostingController type parameter let container = ComposeContainerView( mastodonController: mastodonController, - vcWidthSubject: widthSubject, uiState: uiState ) super.init(rootView: container) @@ -82,12 +78,6 @@ class ComposeHostingController: UIHostingController { fatalError("init(coder:) has not been implemented") } - override func viewDidLayoutSubviews() { - super.viewDidLayoutSubviews() - - widthSubject.send(view.bounds.width) - } - override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) diff --git a/Tusker/Screens/Compose/ComposeReplyContentView.swift b/Tusker/Screens/Compose/ComposeReplyContentView.swift index 1ff458f257..48d488ec86 100644 --- a/Tusker/Screens/Compose/ComposeReplyContentView.swift +++ b/Tusker/Screens/Compose/ComposeReplyContentView.swift @@ -12,37 +12,33 @@ struct ComposeReplyContentView: UIViewRepresentable { typealias UIViewType = ComposeReplyContentTextView let status: StatusMO - let maxWidth: CGFloat @EnvironmentObject var mastodonController: MastodonController + let heightChanged: (CGFloat) -> Void + func makeUIView(context: Context) -> ComposeReplyContentTextView { let view = ComposeReplyContentTextView() view.overrideMastodonController = mastodonController view.setTextFrom(status: status) - view.isScrollEnabled = false view.isUserInteractionEnabled = false view.backgroundColor = .clear - view.maxWidth = maxWidth + return view } func updateUIView(_ uiView: ComposeReplyContentTextView, context: Context) { - uiView.constraint.constant = maxWidth + uiView.heightChanged = heightChanged } } class ComposeReplyContentTextView: StatusContentTextView { + var heightChanged: ((CGFloat) -> Void)? - var maxWidth: CGFloat! - var constraint: NSLayoutConstraint! - - override func didMoveToSuperview() { - super.didMoveToSuperview() + override func layoutSubviews() { + super.layoutSubviews() - translatesAutoresizingMaskIntoConstraints = false - constraint = widthAnchor.constraint(lessThanOrEqualToConstant: maxWidth) - constraint.isActive = true + heightChanged?(contentSize.height) } } diff --git a/Tusker/Screens/Compose/ComposeReplyView.swift b/Tusker/Screens/Compose/ComposeReplyView.swift index 06d3316098..726b574533 100644 --- a/Tusker/Screens/Compose/ComposeReplyView.swift +++ b/Tusker/Screens/Compose/ComposeReplyView.swift @@ -10,9 +10,10 @@ import SwiftUI struct ComposeReplyView: View { let status: StatusMO - let maxWidth: CGFloat let stackPadding: CGFloat + @State private var contentHeight: CGFloat? + private let horizSpacing: CGFloat = 8 var body: some View { @@ -35,7 +36,10 @@ struct ComposeReplyView: View { Spacer() } - ComposeReplyContentView(status: status, maxWidth: maxWidth - 50 - horizSpacing + 4) + ComposeReplyContentView(status: status) { (newHeight) in + self.contentHeight = newHeight + } + .frame(height: contentHeight) .offset(x: -4, y: -8) .padding(.bottom, -8) } diff --git a/Tusker/Screens/Compose/ComposeView.swift b/Tusker/Screens/Compose/ComposeView.swift index 2116c64ce3..6f35a1fee3 100644 --- a/Tusker/Screens/Compose/ComposeView.swift +++ b/Tusker/Screens/Compose/ComposeView.swift @@ -12,10 +12,8 @@ import Combine struct ComposeView: View { @ObservedObject var draft: Draft - let vcWidthSubject: PassthroughSubject @EnvironmentObject var mastodonController: MastodonController - @State var viewControllerWidth: CGFloat = 0 @EnvironmentObject var uiState: ComposeUIState @State var isPosting = false @State var postProgress: Double = 0 @@ -25,12 +23,8 @@ struct ComposeView: View { private let stackPadding: CGFloat = 8 - init( - draft: Draft, - vcWidthSubject: PassthroughSubject - ) { + init(draft: Draft) { self.draft = draft - self.vcWidthSubject = vcWidthSubject } var charactersRemaining: Int { @@ -73,7 +67,6 @@ struct ComposeView: View { .coordinateSpace(name: "outer") .onAppear(perform: self.didAppear) .navigationBarTitle("Compose") - .onReceive(vcWidthSubject) { self.viewControllerWidth = $0 } .actionSheet(isPresented: $uiState.isShowingSaveDraftSheet, content: self.saveAndCloseSheet) .alert(isPresented: $isShowingPostErrorAlert) { Alert( @@ -90,7 +83,6 @@ struct ComposeView: View { let status = mastodonController.persistentContainer.status(for: id) { ComposeReplyView( status: status, - maxWidth: viewControllerWidth - (2 * stackPadding), stackPadding: stackPadding ) }