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

iOS UITextView两端对齐:如何避免单词内插空格?求解决方案

UITextView两端对齐禁止单词内插空格的解决方案

问题描述

设置NSMutableParagraphStyle的alignment为.justified、hyphenationFactor为1后,系统两端对齐算法会在单词内部字符间插入空格(而非仅在单词间),导致错误排版:

A example of some
j u s t i f i e d
text that is wit-
hin some kind  of  
text box in app.

期望实现仅在单词间分配空格的两端对齐效果:

A example of some
justified    text
that  is   within 
some kind of text 
box in app.

附用户提供的示例代码:

import SwiftUI
import UIKit

struct JustifiedTextView: UIViewRepresentable {
    let string = "An example of some justified text that is within some kind of text box in app containing some longwords and some other short words. DonMag might have some ideas on how to only apply spacing within words not characters."
    
    func makeUIView(context: Context) -> UITextView {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .justified
        paragraphStyle.hyphenationFactor = 1
        let attributes = [
            NSAttributedString.Key.paragraphStyle : paragraphStyle,
            NSAttributedString.Key.font : UIFont.systemFont(ofSize: 22)
        ]
        let textView = UITextView()
        textView.attributedText = NSAttributedString(string: string, attributes: attributes)
        return textView
    }
    
    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.text = string
    }
}

使用方式:

import SwiftUI

struct MyView: View {
    var body: some View {
        HStack {
            JustifiedTextView()
            JustifiedTextView()
            JustifiedTextView()
        }
    }
}

开箱即用方案说明

iOS系统默认的两端对齐逻辑,在文本行剩余空间无法通过单词间空格填充时,会拆分单词并插入字符间空格(连字策略无法覆盖所有场景时更明显)。目前没有直接的系统API可以彻底禁止单词内插空格,但可以通过调整参数缓解:

  • 明确设置lineBreakMode为.byWordWrapping,确保优先按单词断行
  • 降低hyphenationFactor或关闭连字(设置为0),减少单词拆分,但会牺牲排版紧凑性
  • 设置固定的minimumLineHeight和maximumLineHeight,减少系统为填充行高触发的字符间空格

这些方法仅能缓解问题,无法完全实现仅单词间分配空格的两端对齐。

自定义实现方向(基于Core Text)

要彻底满足需求,需基于Core Text自定义排版逻辑,核心思路:

  1. 单词边界断行:使用Core Text的CTLine、CTFramesetter相关API逐行计算文本范围,确保断行仅发生在单词分隔符(空格、标点)处,避免拆分单词
  2. 行内空格分配:计算每行容器宽度与文本实际宽度的差值,将所有额外空间均匀分配到单词之间的空格,而非插入到单词内部
  3. 集成到视图:自定义UITextView子类,或在UIViewRepresentable中使用Core Text直接绘制处理后的文本行,替代系统默认排版

简化实现步骤

  • 将文本拆分为单词数组,逐行拼接单词直到接近容器宽度,计算该行需补充的总空格数,按比例分配到单词间的空格位置
  • 使用CTFramesetterCreateFrame创建排版框架,或通过CTLineDraw逐行绘制处理后的文本行

代码修正提示

示例代码中updateUIView方法直接设置uiView.text = string会覆盖之前配置的富文本属性,导致段落样式失效,应修改为更新富文本:

func updateUIView(_ uiView: UITextView, context: Context) {
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .justified
    paragraphStyle.hyphenationFactor = 1
    let attributes = [
        NSAttributedString.Key.paragraphStyle : paragraphStyle,
        NSAttributedString.Key.font : UIFont.systemFont(ofSize: 22)
    ]
    uiView.attributedText = NSAttributedString(string: string, attributes: attributes)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 04:20:30