SwiftUI получает NSViewRepresentable для автоматической перерисовки
Я представил стилизованное текстовое поле NSViewRepresentable в своем макете, чтобы использовать поле текстового редактора с атрибутами. Я хочу влиять на содержимое этого текстового поля с помощью некоторых кнопок.
Я могу изменить стилизованные атрибуты поля, но оно никогда не обновляется, если я не нажму его вручную. Должен быть способ сделать это автоматически. Что я пропустил?
import SwiftUI
import Combine
let publisher = PassthroughSubject<Bool,Never>()
struct ContentView: View
{
@State var mytext = NSMutableAttributedString(string: "")
var attributedString: NSMutableAttributedString
@State var textViewID: Int = 0
init()
{
attributedString = NSMutableAttributedString(
string: "Hello World!",
attributes: [.font: NSFont.systemFont(ofSize: 18)])
_mytext = State(initialValue: attributedString)
}
var body: some View
{
VStack
{
Button("Bold")
{
attributedString.addAttribute(.font, value: NSFont.boldSystemFont(ofSize: 18), range: NSRange(location: 0, length: 5))
mytext = attributedString
publisher.send(true)
}
}
TextView(text: $mytext)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.id(textViewID)
.onReceive(publisher) { ( stateTo ) in
textViewID += 1
}
}
}
struct TextView: NSViewRepresentable
{
@Binding var text: NSMutableAttributedString
func makeNSView(context: Context) -> NSTextView
{
NSTextView()
}
func updateNSView(_ nsView: NSTextView, context: Context)
{
nsView.textStorage?.setAttributedString(text)
}
}
Или я что-то упускаю и есть более простой способ?
1 ответ
Подозреваемый обошел это и переключился на более крупную рыбу. Но для тех, кто натыкается на что-то подобное :-)
Проблема с кодом в примере заключается в том, что в нем нет ничего, что SwiftUI мог бы использовать, чтобы определить, когда ему нужно перерисовать.
Конкретно@State var mytext: NSMutableAttributedString
содержит ссылку на ту же атрибутированную строку, что иattributedString
делает. Следовательно, действие кнопкиmytext = attributedString
это от pov SwiftUI нооп.
Два подхода к тому, чтобы заставить его работать.
Во-первых, как сейчас, когда одна и та же строка сохраняется и изменяется на месте, а перерисовка действительно запрашивается явно. В этом случае действие «Кнопка» можно очистить, чтобы устранить необходимость в «Объединить» и «onReceive
таким образом:
Button("Bold") {
mytext.addAttribute(.font, value: NSFont.boldSystemFont(ofSize: 18), range: NSRange(location: 0, length: 5))
textViewID = mytext.hashValue
}
Или, во-вторых, избавьтесь от необходимости использовать атрибуты Combine, onReceive и id, удалив мутацию на месте. Вместо этого замените новой строкой атрибута, которую заметит SwiftUI, например:
Button("Bold") {
let newAttributedString:NSMutableAttributedString = mytext.mutableCopy() as! NSMutableAttributedString
newAttributedString.addAttribute(.font, value: NSFont.boldSystemFont(ofSize: 18), range: NSRange(location: 0, length: 5))
mytext = newAttributedString
}
Позже, вероятно, немного более идиоматичен SwiftUI.