gpt4 book ai didi

ios - ios 中的 Ruby 文本/注音假名

转载 作者:行者123 更新时间:2023-11-29 12:37:18 29 4
gpt4 key购买 nike

我目前正在尝试在 UITextView 上显示一些日语文本。 .是否可以在不使用 Web View 的情况下以类似于 html 中的 标记的方式在汉字上方显示假名(如下所示)?

enter image description here

涉及大量文本处理,因此我不能简单地使用 Web View 。在 iOS8 中,CTRubyAnnotationRef已添加但没有文档(我欢迎任何示例),而且我还担心与 iOS7 缺乏兼容性。我认为可以使用 NSAttributedString 来显示上面的注音假名。 ,但目前还不能。

最佳答案

更新 Swift 5.1

此解决方案是预览答案的更新,让您可以使用拼音指南编写亚洲句子,使用字符串中的模式。

让我们从处理字符串开始。

这 4 个扩展允许您在字符串中注入(inject) ruby​​ 注释。

createRuby() 函数检查字符串的一个模式,它是:|用汉字写的单词《拼音指南》。

例子:

|红 Jade 《ルビー》

|成功《せいこう》するかどうかは、きみの|努力《どりょく》に|系《かか》る。
等等。

重要的是遵循模式。

extension String {
// 文字列の範囲
private var stringRange: NSRange {
return NSMakeRange(0, self.utf16.count)
}

// 特定の正規表現を検索
private func searchRegex(of pattern: String) -> NSTextCheckingResult? {
do {
let patternToSearch = try NSRegularExpression(pattern: pattern)
return patternToSearch.firstMatch(in: self, range: stringRange)
} catch { return nil }
}

// 特定の正規表現を置換
private func replaceRegex(of pattern: String, with templete: String) -> String {
do {
let patternToReplace = try NSRegularExpression(pattern: pattern)
return patternToReplace.stringByReplacingMatches(in: self, range: stringRange, withTemplate: templete)
} catch { return self }
}

// ルビを生成
func createRuby() -> NSMutableAttributedString {
let textWithRuby = self
// ルビ付文字(「|紅玉《ルビー》」)を特定し文字列を分割
.replaceRegex(of: "(|.+?《.+?》)", with: ",$1,")
.components(separatedBy: ",")
// ルビ付文字のルビを設定
.map { component -> NSAttributedString in
// ベース文字(漢字など)とルビをそれぞれ取得
guard let pair = component.searchRegex(of: "|(.+?)《(.+?)》") else {
return NSAttributedString(string: component)
}
let component = component as NSString
let baseText = component.substring(with: pair.range(at: 1))
let rubyText = component.substring(with: pair.range(at: 2))

// ルビの表示に関する設定
let rubyAttribute: [CFString: Any] = [
kCTRubyAnnotationSizeFactorAttributeName: 0.5,
kCTForegroundColorAttributeName: UIColor.darkGray
]
let rubyAnnotation = CTRubyAnnotationCreateWithAttributes(
.auto, .auto, .before, rubyText as CFString, rubyAttribute as CFDictionary
)


return NSAttributedString(string: baseText, attributes: [kCTRubyAnnotationAttributeName as NSAttributedString.Key: rubyAnnotation])
}
// 分割されていた文字列を結合
.reduce(NSMutableAttributedString()) { $0.append($1); return $0 }
return textWithRuby
}
}

Ruby 标签:大问题

您可能知道,Apple 在 iOS 8 中引入了属性字符串的 ruby​​ 注释之类的属性,如果您确实使用 ruby​​ 注释创建了属性字符串并且做了:
myLabel.attributedText = attributedTextWithRuby

标签确实完美地显示了字符串没有问题。

不幸的是,Apple 从 iOS 11 中删除了此功能,因此,如果要显示 ruby​​ 注释,您必须覆盖方法 draw,以有效地绘制文本。为此,您必须使用 Core Text 来处理文本的行。

让我们显示代码
import UIKit

public enum TextOrientation { //1
case horizontal
case vertical
}

class RubyLabel: UILabel {

public var orientation:TextOrientation = .horizontal //2

// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
// ルビを表示
override func draw(_ rect: CGRect) {
//super.draw(rect) //3


// context allows you to manipulate the drawing context (i'm setup to draw or bail out)
guard let context: CGContext = UIGraphicsGetCurrentContext() else {
return
}
guard let string = self.text else { return }
let attributed = NSMutableAttributedString(attributedString: string.createRuby()) //4

let path = CGMutablePath()
switch orientation { //5
case .horizontal:
context.textMatrix = CGAffineTransform.identity;
context.translateBy(x: 0, y: self.bounds.size.height);
context.scaleBy(x: 1.0, y: -1.0);
path.addRect(self.bounds)
attributed.addAttribute(NSAttributedString.Key.verticalGlyphForm, value: false, range: NSMakeRange(0, attributed.length))
case .vertical:
context.rotate(by: .pi / 2)
context.scaleBy(x: 1.0, y: -1.0)
//context.saveGState()
//self.transform = CGAffineTransform(rotationAngle: .pi/2)
path.addRect(CGRect(x: self.bounds.origin.y, y: self.bounds.origin.x, width: self.bounds.height, height: self.bounds.width))
attributed.addAttribute(NSAttributedString.Key.verticalGlyphForm, value: true, range: NSMakeRange(0, attributed.length))
}

attributed.addAttributes([NSAttributedString.Key.font : self.font], range: NSMakeRange(0, attributed.length))

let frameSetter = CTFramesetterCreateWithAttributedString(attributed)

let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0,attributed.length), path, nil)

// Check need for truncate tail
//6
if (CTFrameGetVisibleStringRange(frame).length as Int) < attributed.length {
// Required truncate
let linesNS: NSArray = CTFrameGetLines(frame)
let linesAO: [AnyObject] = linesNS as [AnyObject]
var lines: [CTLine] = linesAO as! [CTLine]

let boundingBoxOfPath = path.boundingBoxOfPath

let lastCTLine = lines.removeLast() //7

let truncateString:CFAttributedString = CFAttributedStringCreate(nil, "\u{2026}" as CFString, CTFrameGetFrameAttributes(frame))
let truncateToken:CTLine = CTLineCreateWithAttributedString(truncateString)

let lineWidth = CTLineGetTypographicBounds(lastCTLine, nil, nil, nil)
let tokenWidth = CTLineGetTypographicBounds(truncateToken, nil, nil, nil)
let widthTruncationBegins = lineWidth - tokenWidth
if let truncatedLine = CTLineCreateTruncatedLine(lastCTLine, widthTruncationBegins, .end, truncateToken) {
lines.append(truncatedLine)
}

var lineOrigins = Array<CGPoint>(repeating: CGPoint.zero, count: lines.count)
CTFrameGetLineOrigins(frame, CFRange(location: 0, length: lines.count), &lineOrigins)
for (index, line) in lines.enumerated() {
context.textPosition = CGPoint(x: lineOrigins[index].x + boundingBoxOfPath.origin.x, y:lineOrigins[index].y + boundingBoxOfPath.origin.y)
CTLineDraw(line, context)
}
}
else {
// Not required truncate
CTFrameDraw(frame, context)
}
}

//8
override var intrinsicContentSize: CGSize {
let baseSize = super.intrinsicContentSize

return CGSize(width: baseSize.width, height: baseSize.height * 1.0)

}

}

代码说明:

1-中日文字可以横写和竖写。此枚举使您可以在水平和垂直方向之间轻松切换。

2- 带有开关方向文本的公共(public)变量。

3-此方法必须注释。原因是调用它你会看到两个重叠的字符串:一个没有属性,最后一个是你的属性字符串。

4-在这里调用 String 类扩展的方法,在该方法中使用 ruby​​ 注释创建属性字符串。

5-这个开关,如果需要在其中绘制文本的上下文,以防你想显示垂直文本。实际上,在此开关中,您添加了属性 NSAttributedString.Key.verticalGlyphForm ,以防垂直为真,否则为假。

6-这个'if'特别重要,因为标签,因为我们评论了方法'super.draw()'不知道如何管理长字符串。没有这个“如果”,标签认为只有一条线可以画。所以,你仍然有一个带有'...'的字符串,就像尾部一样。在这个“如果”中,字符串被打破了更多的线条并正确绘制。

7-当你不给标签一些设置时,标签知道有更多的一行,但因为它不能计算什么是可显示的最后一段字符串,执行时间出错,应用程序崩溃。所以要小心。但是,别担心!我们讨论正确的设置,以便稍后提供。

8-这对于使标签适合文本大小非常重要。

如何使用 RubyLabel

标签的使用非常简单:
import UIKit

class ViewController: UIViewController {
@IBOutlet weak var rubyLabel: RubyLabel! //1

override func viewDidLoad() {
super.viewDidLoad()
setUpLabel()
}

private func setUpLabel() {
rubyLabel.text = "|成功《せいこう》するかどうかは、きみの|努力《どりょく》に|係《かか》る。|人々《ひとびと》の|生死《せいし》に|係《かか》る。" //2
//3
rubyLabel.textAlignment = .left
rubyLabel.font = .systemFont(ofSize: 20.0)
rubyLabel.orientation = .horizontal
rubyLabel.lineBreakMode = .byCharWrapping
}
}

代码说明:

1- 如果使用 Storyboard或 xib 文件或创建标签,则将标签连接到 xib。

2-正如我所说,使用非常简单:这里像任何其他字符串一样使用 ruby​​ 模式分配字符串

3-这些设置是为使工作标签必须设置的设置。您可以通过代码或 Storyboard/xib 设置

小心

如果您使用 Storyboard/xib,如果您没有正确放置约束,则标签会在第 7 点为您提供错误。

结果

horizontal String

Vertical string

有效,但不完美
正如您在屏幕截图中看到的那样,此标签运行良好,但仍有一些问题。

1-垂直文本标签仍为水平形状;

2- 如果字符串包含\n 以将字符串拆分为更多行,则标签仅显示字符串在没有 '\n' 字符的情况下将具有的行数。

我正在努力解决这些问题,但感谢您的帮助。

关于ios - ios 中的 Ruby 文本/注音假名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25994057/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com