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.
This commit is contained in:
parent
9dce94c014
commit
262aadf807
|
@ -11,24 +11,18 @@ import Combine
|
|||
|
||||
struct ComposeContainerView: View {
|
||||
let mastodonController: MastodonController
|
||||
let vcWidthSubject: PassthroughSubject<CGFloat, Never>
|
||||
@ObservedObject var uiState: ComposeUIState
|
||||
|
||||
init(
|
||||
mastodonController: MastodonController,
|
||||
vcWidthSubject: PassthroughSubject<CGFloat, Never>,
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -16,9 +16,6 @@ class ComposeHostingController: UIHostingController<ComposeContainerView> {
|
|||
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<CGFloat, Never>()
|
||||
|
||||
var draft: Draft { uiState.draft }
|
||||
|
||||
|
@ -42,7 +39,6 @@ class ComposeHostingController: UIHostingController<ComposeContainerView> {
|
|||
// 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<ComposeContainerView> {
|
|||
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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -12,10 +12,8 @@ import Combine
|
|||
|
||||
struct ComposeView: View {
|
||||
@ObservedObject var draft: Draft
|
||||
let vcWidthSubject: PassthroughSubject<CGFloat, Never>
|
||||
|
||||
@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<CGFloat, Never>
|
||||
) {
|
||||
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
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue