日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BSText - YY大神的富文本框架 YYText 的 Swift 版本

發(fā)布時間:2023/12/10 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BSText - YY大神的富文本框架 YYText 的 Swift 版本 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文鏈接

前言

??度過春節(jié)期間的安逸期,需要從慵懶的狀態(tài)盡快恢復(fù)過來,節(jié)前有幾個月時間,趁著公司業(yè)務(wù)線不怎么繁忙,抱著學(xué)習的態(tài)度,嘗試將 YY 大神的 YYText 用 Swift 重新實現(xiàn)一下(之前用 Swift 最多寫寫 Demo,沒有用來做項目)。但是由于年前還有個 bug 沒有修復(fù),怕大家的 issue 雪花般飛過來,果斷沒敢開源出來。新年新氣象,改完 bug 趕緊和大家分享一下啦 ?

??目前項目已經(jīng)實現(xiàn)了 YYText 中的所有功能,如果大家遇到什么問題,歡迎提 issue,或者郵箱聯(lián)系 a1049145827@hotmail.com ,如果覺得有用,請不要吝惜您的 star ?。

??用過 YYText 的同學(xué)應(yīng)該已經(jīng)相當熟悉了,傳送門。

一些挑戰(zhàn)

??由于近年來 Swift 發(fā)展迅速,ABI 一直不能穩(wěn)定下來,導(dǎo)致開發(fā)者們都在吐槽:“每年學(xué)習一門新語言”,這樣就直接導(dǎo)致在網(wǎng)上查資料非常困難,好不容易查到的資料,demo 代碼甚至都不能通過編譯,這樣推進的效率大打折扣,確實非常痛苦,眼看 Swift 就要發(fā)布 Swift5,心里似乎又有了希望。于是決心要用 Swift 把 YYText 的功能實現(xiàn)一遍,一來練習 Swift 語法,二來以后也可以持續(xù)維護,希望好的輪子可以被更多的開發(fā)者認可和采用,目前本項目已經(jīng)可以在 Swift5 (Xcode10 beta3)環(huán)境下正常編譯運行。

項目介紹

功能強大的 iOS 富文本編輯與顯示框架。
(該項目是 YYText 的 Swift 版本,項目的前綴 'BS' 來自于 BlueSky,就是創(chuàng)作了《冰河世紀》系列電影的 BlueSky 工作室)

特性

  • API 兼容 UILabel 和 UITextView
  • 支持高性能的異步排版和渲染
  • 擴展了 CoreText 的屬性以支持更多文字效果
  • 支持 UIImage、UIView、CALayer 作為圖文混排元素
  • 支持添加自定義樣式的、可點擊的文本高亮范圍
  • 支持自定義文本解析 (內(nèi)置簡單的 Markdown/表情解析)
  • 支持文本容器路徑、內(nèi)部留空路徑的控制
  • 支持文字豎排版,可用于編輯和顯示中日韓文本
  • 支持圖片和富文本的復(fù)制粘貼
  • 文本編輯時,支持富文本占位符
  • 支持自定義鍵盤視圖
  • 撤銷和重做次數(shù)的控制
  • 富文本的序列化與反序列化支持
  • 支持多語言,支持 VoiceOver
  • 全部代碼都有文檔注釋

架構(gòu)

本項目架構(gòu)與 YYText 保持一致

文本屬性

BSText 原生支持的屬性

DemoAttribute NameClass
TextAttachmentTextAttachment
TextHighlightTextHighlight
TextBindingTextBinding
TextShadow
TextInnerShadow
TextShadow
TextBorderTextBorder
TextBackgroundBorderTextBorder
TextBlockBorderTextBorder
TextGlyphTransform NSValue(CGAffineTransform)
TextUnderlineTextDecoration
TextStrickthroughTextDecoration
TextBackedStringTextBackedString

BSText 支持的 CoreText 屬性

DemoAttribute NameClass
Font UIFont(CTFontRef)
Kern NSNumber
StrokeWidth NSNumber
StrokeColor CGColorRef
Shadow NSShadow
Ligature NSNumber
VerticalGlyphForm NSNumber(BOOL)
WritingDirection NSArray(NSNumber)
RunDelegate CTRunDelegateRef
TextAlignment NSParagraphStyle
(NSTextAlignment)
LineBreakMode NSParagraphStyle
(NSLineBreakMode)
LineSpacing NSParagraphStyle
(CGFloat)
ParagraphSpacing
ParagraphSpacingBefore
NSParagraphStyle
(CGFloat)
FirstLineHeadIndent NSParagraphStyle
(CGFloat)
HeadIndent NSParagraphStyle
(CGFloat)
TailIndent NSParagraphStyle
(CGFloat)
MinimumLineHeight NSParagraphStyle
(CGFloat)
MaximumLineHeight NSParagraphStyle
(CGFloat)
LineHeightMultiple NSParagraphStyle
(CGFloat)
BaseWritingDirection NSParagraphStyle
(NSWritingDirection)
DefaultTabInterval
TabStops
NSParagraphStyle
CGFloat/NSArray(NSTextTab)

用法

基本用法

// BSLabel (和 UILabel 用法一致) let label = BSLabel() label.frame = ... label.font = ... label.textColor = ... label.textAlignment = ... label.lineBreakMode = ... label.numberOfLines = ... label.text = ...// BSTextView (和 UITextView 用法一致) let textView = BSTextView() textView.frame = ... textView.font = ... textView.textColor = ... textView.dataDetectorTypes = ... textView.placeHolderText = ... textView.placeHolderTextColor = ... textView.delegate = ... 復(fù)制代碼

屬性文本

// 1. 創(chuàng)建一個屬性文本 let text = NSMutableAttributedString(string: "Some Text, blabla...")// 2. 為文本設(shè)置屬性 text.bs_font = UIFont.boldSystemFont(ofSize:30) text.bs_color = UIColor.blue text.bs_set(color: UIColor.red, range: NSRange(location: 0, length: 4)) text.bs_lineSpacing = 10// 3. 賦值到 BSLabel 或 BSTextView let label = BSLabel() label.frame = CGRect(x: 15, y: 100, width: 200, height: 80) label.attributedText = textlet textView = BSTextView() textView.frame = CGRect(x: 15, y: 200, width: 200, height: 80) textView.attributedText = text 復(fù)制代碼

文本高亮

你可以用一些已經(jīng)封裝好的簡便方法來設(shè)置文本高亮:

text.bs_set(textHighlightRange: range,color: UIColor.blue,backgroundColor: UIColor.gray) { (view, text, range, rect) inprint("tap text range:...") } 復(fù)制代碼

或者用更復(fù)雜的辦法來調(diào)節(jié)文本高亮的細節(jié):

// 1. 創(chuàng)建一個"高亮"屬性,當用戶點擊了高亮區(qū)域的文本時,"高亮"屬性會替換掉原本的屬性 let border = TextBorder.border(with: UIColor.gray, cornerRadius: 3)let highlight = TextHighlight() highlight.color = .white highlight.backgroundBorder = highlightBorder highlight.tapAction = { (containerView, text, range, rect) inprint("tap text range:...")// 你也可以把事件回調(diào)放到 BSLabel 和 BSTextView 來處理。 }// 2. 把"高亮"屬性設(shè)置到某個文本范圍 let attributedText = NSMutableAttributedString(string: " ") attributedText.bs_set(textHighlight: highlight, range: highlightRange)// 3. 把屬性文本設(shè)置到 BSLabel 或 BSTextView let label = BSLabel() label.attributedText = attributedTextlet textView = BSTextView() textView.delegate = self textView.attributedText = ...// 4. 接受事件回調(diào) label.highlightTapAction = { (containerView, text, range, rect) inprint("tap text range:...") }; label.highlightLongPressAction = { (containerView, text, range, rect) inprint("tap text range:...") };// MARK: - TextViewDelegate func textView(_ textView: BSTextView, didTap highlight: TextHighlight, in characterRange: NSRange, rect: CGRect) {print("tap text range:...") } func textView(_ textView: BSTextView, didLongPress highlight: TextHighlight, in characterRange: NSRange, rect: CGRect) {print("tap text range:...") } 復(fù)制代碼

圖文混排

let text = NSMutableAttributedString() let font = UIFont.systemFont(ofSize: 16)// 嵌入 UIImage let image = UIImage.init(named: "dribbble64_imageio") guard let attachment = NSMutableAttributedString.bs_attachmentString(with: image, contentMode: .center, attachmentSize: image?.size ?? .zero, alignTo: font, alignment: .center) else {return } text.append(attachment)// 嵌入 UIView let switcher = UISwitch() switcher.sizeToFit() guard let attachment1 = NSMutableAttributedString.bs_attachmentString(with: switcher, contentMode: .center, attachmentSize: switcher.frame.size, alignTo: font, alignment: .center) else {return } text.append(attachment1)// 嵌入 CALayer let layer = CAShapeLayer() layer.path = ... guard let attachment2 = NSMutableAttributedString.bs_attachmentString(with: layer, contentMode: .center, attachmentSize: layer.frame.size, alignTo: font, alignment: .center) else {return } text.append(attachment2) 復(fù)制代碼

文本布局計算

let text = NSAttributedString() let size = CGSize(width: 100, height: CGFloat.greatestFiniteMagnitude) let container = TextContainer() container.size = size guard let layout = TextLayout(container: container, text: text) else {return }// 獲取文本顯示位置和大小 layout.textBoundingRect // get bounding rect layout.textBoundingSize // get bounding size// 查詢文本排版結(jié)果 layout.lineIndex(for: CGPoint(x: 10, y: 10)) layout.closestLineIndex(for: CGPoint(x: 10, y: 10)) layout.closestPosition(to: CGPoint(x: 10, y: 10)) layout.textRange(at: CGPoint(x: 10, y: 10)) layout.rect(for: TextRange(range: NSRange(location: 10, length: 2))) layout.selectionRects(for: TextRange(range: NSRange(location: 10, length: 2)))// 顯示文本排版結(jié)果 let label = BSLabel() label.frame = CGRect(x: 0, y: 0, width: layout.textBoundingSize.width, height: layout.textBoundingSize.height) label.textLayout = layout; 復(fù)制代碼

文本行位置調(diào)整

// 由于中文、英文、Emoji 等字體高度不一致,或者富文本中出現(xiàn)了不同字號的字體, // 可能會造成每行文字的高度不一致。這里可以添加一個修改器來實現(xiàn)固定行高,或者自定義文本行位置。// 簡單的方法: // 1. 創(chuàng)建一個文本行位置修改類,實現(xiàn) `TextLinePositionModifier` 協(xié)議。 // 2. 設(shè)置到 Label 或 TextView。let modifier = TextLinePositionSimpleModifier() modifier.fixedLineHeight = 24let label = BSLabel() label.linePositionModifier = modifier// 完全控制: let modifier = TextLinePositionSimpleModifier() modifier.fixedLineHeight = 24let container = TextContainer() container.size = CGSize(width: 100, height: CGFloat.greatestFiniteMagnitude) container.linePositionModifier = modifierguard let layout = TextLayout(container: container, text: text) else {return } let label = BSLabel() label.size = layout.textBoundingSize label.textLayout = layout 復(fù)制代碼

異步排版和渲染

// 如果你在顯示字符串時有性能問題,可以這樣開啟異步模式: let label = BSLabel() label.displaysAsynchronously = true// 如果需要獲得最高的性能,你可以在后臺線程用 `TextLayout` 進行預(yù)排版: let label = BSLabel() label.displaysAsynchronously = true // 開啟異步繪制 label.ignoreCommonProperties = true // 忽略除了 textLayout 之外的其他屬性DispatchQueue.global().async {// 創(chuàng)建屬性字符串let text = NSMutableAttributedString(string: "Some Text")text.bs_font = UIFont.systemFont(ofSize: 16)text.bs_color = UIColor.graytext.bs_set(color: .red, range: NSRange(location: 0, length: 4))// 創(chuàng)建文本容器let container = TextContainer()container.size = CGSize(width: 100, height: CGFloat.greatestFiniteMagnitude);container.maximumNumberOfRows = 0;// 生成排版結(jié)果let layout = TextLayout(container: container, text: text)DispatchQueue.main.async {label.frame = CGRect(x: 0, y: 0, width: layout.textBoundingSize.width, height: layout.textBoundingSize.height)label.textLayout = layout;} } 復(fù)制代碼

文本容器控制

let label = BSLabel() label.textContainerPath = UIBezierPath(...) label.exclusionPaths = [UIBezierPath(), ...] label.textContainerInset = UIEdgeInsets(...) label.verticalForm = true/falselet textView = BSTextView() textView.exclusionPaths = [UIBezierPath(), ...] textView.textContainerInset = UIEdgeInsets(...) textView.verticalForm = true/false 復(fù)制代碼

文本解析

// 1. 創(chuàng)建一個解析器// 內(nèi)置簡單的表情解析 let simpleEmoticonParser = TextSimpleEmoticonParser() var mapper = [String: UIImage]() mapper[":smile:"] = UIImage.init(named: "smile.png") mapper[":cool:"] = UIImage.init(named: "cool.png") mapper[":cry:"] = UIImage.init(named: "cry.png") mapper[":wink:"] = UIImage.init(named: "wink.png") simpleEmoticonParser.emoticonMapper = mapper;// 內(nèi)置簡單的 markdown 解析 let markdownParser = TextSimpleMarkdownParser() markdownParser.setColorWithDarkTheme()// 實現(xiàn) `TextParser` 協(xié)議的自定義解析器 let parser = MyCustomParser()// 2. 把解析器添加到 BSLabel 或 BSTextView let label = BSLabel() label.textParser = parserlet textView = BSTextView() textView.textParser = parser 復(fù)制代碼

Debug

// 設(shè)置一個全局的 debug option 來顯示排版結(jié)果。 let debugOption = TextDebugOption() debugOption.baselineColor = .red debugOption.ctFrameBorderColor = .red debugOption.ctLineFillColor = UIColor(red: 0, green: 0.463, blue: 1, alpha: 0.18) debugOption.cgGlyphBorderColor = UIColor(red: 1, green: 0.524, blue: 0, alpha: 0.2) TextDebugOption.setSharedDebugOption(debugOption) 復(fù)制代碼

更多示例

查看演示工程 Demo/BSTextDemo.xcodeproj:




安裝

CocoaPods

  • 在 Podfile 中添加 pod 'BSText'。

    source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.0' use_frameworks!target 'MyApp' do# your other pod# ...pod 'BSText', '~> 1.0' end 復(fù)制代碼
  • 執(zhí)行 pod install 或 pod update。

  • 導(dǎo)入模塊 import BSText,OC 項目中使用 @import BSText;。

  • Carthage

  • 在 Cartfile 中添加 github "a1049145827/BSText"。
  • 執(zhí)行 carthage update --platform ios 并將生成的 framework 添加到你的工程。
  • 導(dǎo)入模塊 import BSText,OC 項目中使用 @import BSText;。
  • 手動安裝

  • 下載 BSText 文件夾內(nèi)的所有內(nèi)容。
  • 將 BSText 內(nèi)的源文件添加(拖放)到你的工程。
  • 鏈接以下 frameworks:
    • UIKit
    • CoreFoundation
    • CoreText
    • QuartzCore
    • Accelerate
    • MobileCoreServices
  • 導(dǎo)入模塊 import BSText,OC 項目中使用 @import BSText;。
  • 注意

    你可以添加 YYImage 或 YYWebImage 到你的工程,以支持動畫格式(GIF/APNG/WebP)的圖片。

    文檔

    本項目目前還沒有生成在線文檔,你可以在 CocoaDocs 查看 YYText 的在線 API 文檔,也可以用 appledoc 本地生成文檔。

    系統(tǒng)要求

    該項目最低支持 iOS 8.0 和 Xcode 10.0。

    已知問題

    • 與 YYText 一樣,BSText 并不能支持所有 CoreText/TextKit 的屬性,比如 NSBackgroundColor、NSStrikethrough、NSUnderline、NSAttachment、NSLink 等,但 BSText 中基本都有對應(yīng)屬性作為替代。詳情見上方表格。
    • BSTextView 未實現(xiàn)局部刷新,所以在輸入和編輯大量的文本(比如超過大概五千個漢字、或大概一萬個英文字符)時會出現(xiàn)較明顯的卡頓現(xiàn)象。
    • 豎排版時,添加 exclusionPaths 在少數(shù)情況下可能會導(dǎo)致文本顯示空白。
    • 當添加了非矩形的 textContainerPath,并且有嵌入大于文本排版方向?qū)挾鹊?RunDelegate 時,RunDelegate 之后的文字會無法顯示。這是 CoreText 的 Bug(或者說是 Feature)。

    轉(zhuǎn)載于:https://juejin.im/post/5c7c8a91f265da2dd53fe444

    總結(jié)

    以上是生活随笔為你收集整理的BSText - YY大神的富文本框架 YYText 的 Swift 版本的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。