SwiftUI на macOS: TextField не реагирует на цвет выделения

Вопрос или проблема

Мне нужно иметь возможность стилизовать TextField в моем приложении SwiftUI для macOS. В частности, мне нужно изменить курсор (вводимый знак) и цвет выделения. Как я читал в интернете, для этого люди используют либо устаревшую и помеченную для удаления функцию .accentColor(), либо более новую функцию .tint(). Однако, похоже, что приложение просто игнорирует эти функции.

struct ContentView: View {
    @State private var text = ""

    var body: some View {
        VStack {
            TextField("Поле ввода текста", text: $text)
                .tint(.red)
        }
        .padding()
    }
}

Этот код создает такое окно. Как вы можете видеть, .tint(.red) игнорируется, и используется оранжевый системный цвет акцента.

Я пробовал использовать устаревшую и помеченную для удаления .accentColor() – это не сработало. Пытался создать пользовательский стиль для TextField и установить .tint()/.accentColor() там – результат тот же.

Я на macOS 14.6.1 (23G93) и использую Xcode версии 16.0 (16A242d).

Я неправильно настроил проект? Или есть что-то, чего я не учел?

Ответ или решение

К сожалению, в macOS SwiftUI является более новым фреймворком, и некоторые функции, такие как изменение цвета курсора (caret) и выделения текста в TextField, могут работать не так, как ожидается. На момент macOS 14.6.1 и Xcode 16.0 выполнение вашего кода с использованием .tint(.red) не приводит к ожидаемым результатам, поскольку эта функция не влияет на стандартный интерфейс, используемый TextField на macOS.

Вот несколько способов изменить цвета курсора и выделения текста в TextField:

  1. Использование .foregroundColor() для цветного текста:
    Вы можете изменить цвет текста в поле ввода, но это не изменит цвет выделенного текста или курсора.

    struct ContentView: View {
       @State private var text = ""
    
       var body: some View {
           VStack {
               TextField("Текстовое поле", text: $text)
                   .foregroundColor(.red) // Изменяет цвет текста
                   .padding()
                   .background(Color.white) // Для более четкого видения результата
                   .border(Color.gray)
           }
           .padding()
       }
    }
  2. Использование кастомных стилей:
    Создайте свой собственный стиль для TextField, но имейте в виду, что это также не позволит изменить цвет выделенного текста или курсора, так как они связаны со стандартными системными настройками.

    struct CustomTextFieldStyle: TextFieldStyle {
       func _body(configuration: TextField<_Label>) -> some View {
           configuration
               .padding(10)
               .background(RoundedRectangle(cornerRadius: 5).stroke(Color.red, lineWidth: 1))
       }
    }
    
    struct ContentView: View {
       @State private var text = ""
    
       var body: some View {
           VStack {
               TextField("Текстовое поле", text: $text)
                   .textFieldStyle(CustomTextFieldStyle())
           }
           .padding()
       }
    }
  3. Кастомизация через NSViewRepresentable:
    Если необходимо изменить цвет курсора и выделенного текста, вы можете использовать NSViewRepresentable для создания настраиваемого текстового поля на основе NSControl.

    import SwiftUI
    
    struct CustomTextField: NSViewRepresentable {
       @Binding var text: String
    
       func makeNSView(context: Context) -> NSTextField {
           let textField = NSTextField()
           textField.isBordered = true
           textField.isEditable = true
           textField.font = NSFont.systemFont(ofSize: 14)
           textField.textColor = NSColor.red // Цвет текста
           textField.backgroundColor = NSColor.white
           textField.selectable = true
           return textField
       }
    
       func updateNSView(_ nsView: NSTextField, context: Context) {
           nsView.stringValue = text
       }
    }
    
    struct ContentView: View {
       @State private var text = ""
    
       var body: some View {
           VStack {
               CustomTextField(text: $text)
                   .frame(height: 30)
           }
           .padding()
       }
    }

Этот подход позволит вам контролировать внешний вид приложения гораздо больше, чем стандартный SwiftUI. Однако, если вы решите использовать NSViewRepresentable, убедитесь, что вы также управляете состоянием и поведением вашего текстового поля.

Пожалуйста, следите за обновлениями документации SwiftUI и macOS, так как возможности кастомизации могут улучшаться в будущих версиях.

Оцените материал
Добавить комментарий

Капча загружается...