iOS Swift中如何在UITextField实现文本粗体格式化功能?
Alright, let's nail this bold text toggle for UITextField. I've messed around with attributed text editing in iOS a bunch, so here's a solid implementation that handles both formatting selected text and making new input bold when the state is active—exactly what you're asking for:
Step 1: Set Up Core Components
First, we'll declare our UITextField, a bold state tracker, and the toolbar button. We'll use system fonts here, but you can swap in custom fonts as long as you have a bold variant available.
import UIKit class ViewController: UIViewController { // Our editable text field private let textField: UITextField = { let tf = UITextField() tf.borderStyle = .roundedRect tf.font = UIFont.systemFont(ofSize: 16) tf.attributedPlaceholder = NSAttributedString( string: "Type or select text to format...", attributes: [.font: UIFont.systemFont(ofSize: 16)] ) return tf }() // Track if bold formatting is active private var isBoldActive = false // Bold button for the input toolbar private let boldButton: UIBarButtonItem = { let btn = UIBarButtonItem(title: "B", style: .plain, target: nil, action: nil) btn.setTitleTextAttributes([.font: UIFont.boldSystemFont(ofSize: 18)], for: .normal) return btn }() }
Step 2: Configure the Toolbar and Text Field
In viewDidLoad, we'll attach the toolbar to the text field, set up the button action, and add an optional observer for selection changes to keep the UI in sync.
override func viewDidLoad() { super.viewDidLoad() view.addSubview(textField) // Position the text field (adjust constraints as needed for your layout) textField.frame = CGRect(x: 20, y: 100, width: view.frame.width - 40, height: 44) // Create and configure the input toolbar let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 44)) toolbar.items = [ UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil), boldButton, UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) ] toolbar.sizeToFit() textField.inputAccessoryView = toolbar // Link the bold button to our toggle function boldButton.target = self boldButton.action = #selector(toggleBold) // Optional: Update button state when user selects existing text textField.addTarget(self, action: #selector(textFieldSelectionChanged), for: .editingChanged) }
Step 3: Implement the Bold Toggle Logic
This is the core of the functionality. We'll toggle the bold state, apply formatting to selected text (if any), and update the typing attributes so new input inherits the bold state.
@objc private func toggleBold() { // Flip the active bold state isBoldActive.toggle() // Update button appearance to reflect state (visual cue for user) boldButton.tintColor = isBoldActive ? .systemBlue : .label // Get current attributed text, or create a new one if none exists guard let attributedText = textField.attributedText?.mutableCopy() as? NSMutableAttributedString else { textField.attributedText = NSMutableAttributedString( string: textField.text ?? "", attributes: typingAttributes() ) return } // Handle selected text formatting if let selectedRange = textField.selectedTextRange { let startOffset = textField.offset(from: textField.beginningOfDocument, to: selectedRange.start) let length = textField.offset(from: selectedRange.start, to: selectedRange.end) let nsRange = NSRange(location: startOffset, length: length) // Check if selected text is already bold let currentFont = attributedText.attribute(.font, at: startOffset, effectiveRange: nil) as? UIFont let targetFont: UIFont if let currentFont = currentFont, currentFont.fontDescriptor.symbolicTraits.contains(.traitBold) { // Remove bold: switch to regular font with same size targetFont = UIFont.systemFont(ofSize: currentFont.pointSize) } else { // Add bold: switch to bold font with same size let fontSize = currentFont?.pointSize ?? 16 targetFont = UIFont.boldSystemFont(ofSize: fontSize) } // Apply the font change to the selected range attributedText.addAttribute(.font, value: targetFont, range: nsRange) textField.attributedText = attributedText // Restore the selection after modifying the text textField.selectedTextRange = selectedRange } // Update typing attributes so new input uses current bold state textField.typingAttributes = typingAttributes() } // Helper to return the correct font attributes based on bold state private func typingAttributes() -> [NSAttributedString.Key: Any] { let font: UIFont if isBoldActive { font = UIFont.boldSystemFont(ofSize: textField.font?.pointSize ?? 16) } else { font = UIFont.systemFont(ofSize: textField.font?.pointSize ?? 16) } return [.font: font] }
Step 4: Optional Sync for Selected Text
This function updates the button state when the user selects existing bold text, so the UI stays consistent with the text's formatting.
@objc private func textFieldSelectionChanged() { guard let selectedRange = textField.selectedTextRange, selectedRange.start != selectedRange.end else { // No text selected, keep current state return } let startOffset = textField.offset(from: textField.beginningOfDocument, to: selectedRange.start) if let font = textField.attributedText?.attribute(.font, at: startOffset, effectiveRange: nil) as? UIFont { isBoldActive = font.fontDescriptor.symbolicTraits.contains(.traitBold) boldButton.tintColor = isBoldActive ? .systemBlue : .label } }
Key Notes:
- Selected Text Handling: The code checks if the selected text is already bold before applying changes, so tapping the button toggles the state rather than forcing it on.
- Typing Attributes: The
typingAttributesproperty ensures any new text the user types inherits the current bold state automatically. - Visual Feedback: The button's tint color changes to blue when bold is active, giving the user a clear indicator of the current formatting state.
内容的提问来源于stack exchange,提问作者adak

