You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用UIKit在UITextView/NSTextView中实现文本缩进与取消缩进功能

UITextView/NSTextView 缩进/取消缩进实现方案

核心思路

选择**插入制表符\t**作为缩进标记,而非富文本段落缩进属性,无需额外重写复制逻辑,系统原生剪贴板会自动携带文本内的\t字符,粘贴到任意编辑器都能保留缩进格式,兼容性更强。

完整代码实现

1. 先给UITextView加扩展封装缩进逻辑

extension UITextView {
    /// 缩进选中文本(无选中文本则在当前光标位置插入缩进)
    func indent() {
        guard let selectedRange = selectedTextRange else { return }
        
        // 选中内容为空,直接插入\t
        if selectedRange.start == selectedRange.end {
            replace(selectedRange, withText: "\t")
            return
        }
        
        // 选中多行内容,逐行添加缩进
        guard let text = text(in: selectedRange) else { return }
        let lines = text.components(separatedBy: .newlines)
        let indentedLines = lines.map { "\t" + $0 }
        let indentedText = indentedLines.joined(separator: "\n")
        
        replace(selectedRange, withText: indentedText)
        // 调整选中范围为缩进后的内容
        if let newStart = position(from: selectedRange.start, offset: 0),
           let newEnd = position(from: newStart, offset: indentedText.count) {
            selectedTextRange = textRange(from: newStart, to: newEnd)
        }
    }
    
    /// 取消选中文本的缩进
    func outdent() {
        guard let selectedRange = selectedTextRange else { return }
        guard let text = text(in: selectedRange) else { return }
        
        let lines = text.components(separatedBy: .newlines)
        let outdentedLines = lines.map { line -> String in
            guard line.first == "\t" else { return line }
            return String(line.dropFirst())
        }
        let outdentedText = outdentedLines.joined(separator: "\n")
        
        replace(selectedRange, withText: outdentedText)
        // 调整选中范围为取消缩进后的内容
        if let newStart = position(from: selectedRange.start, offset: 0),
           let newEnd = position(from: newStart, offset: outdentedText.count) {
            selectedTextRange = textRange(from: newStart, to: newEnd)
        }
    }
}

2. 在你的ViewController中调用

你可以绑定两个按钮的点击事件触发缩进/取消缩进:

class ViewController: UIViewController {
    @IBOutlet weak var textView: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()
        textView.delegate = self
    }
    
    // 绑定缩进按钮的点击事件
    @IBAction func indentButtonTapped(_ sender: UIButton) {
        textView.indent()
    }
    
    // 绑定取消缩进按钮的点击事件
    @IBAction func outdentButtonTapped(_ sender: UIButton) {
        textView.outdent()
    }
}

extension ViewController: UITextViewDelegate {
    // 你原有其他delegate逻辑可保留在这里
}

NSTextView 适配说明

逻辑和上述实现完全一致,只需要替换API名称即可:

  • 将UITextView替换为NSTextView
  • selectedTextRange替换为selectedRange
  • 文本替换使用replaceCharacters(in:with:)方法即可

效果验证

缩进后的文本直接执行复制操作,粘贴到任意纯文本/富文本编辑器都会自动携带缩进格式,无需额外处理剪贴板逻辑。

内容的提问来源于stack exchange,提问作者Nighthawk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 05:15:05