草庐IT

ios - NSAttributedString 背景色和圆角

coder 2023-04-26 原文

我有一个关于自定义 UIView 的圆角和文本背景颜色的问题.

基本上,我需要在自定义 UIView 中实现这样的效果(附上图片 - 注意一侧的圆角):


我认为使用的方法是:

  • 使用 Core Text 获取字形运行。
  • 检查高光范围。
  • 如果当前运行在高亮范围内,请在绘制字形运行之前绘制带圆角和所需填充颜色的背景矩形。
  • 绘制字形运行。

  • 但是,我不确定这是否是唯一的解决方案(或者就此而言,这是否是最有效的解决方案)。

    使用 UIWebView不是一个选项,所以我必须在自定义中进行 UIView .

    我的问题是,这是最好的使用方法吗,我是否在正确的轨道上?还是我错过了一些重要的事情或以错误的方式去做?

    最佳答案

    我设法达到了上述效果,所以我想我会发布相同的答案。

    如果有人对使其更有效有任何建议,请随时贡献。我一定会把你的答案标记为正确的。 :)

    为此,您需要向 NSAttributedString 添加“自定义属性”。 .

    基本上,这意味着您可以添加任何键值对,只要您可以将其添加到 NSDictionary 中即可。实例。如果系统无法识别该属性,则不会执行任何操作。作为开发人员,您可以为该属性提供自定义实现和行为。

    出于此答案的目的,让我们假设我添加了一个名为:@"MyRoundedBackgroundColor" 的自定义属性。值为 [UIColor greenColor] .

    对于接下来的步骤,您需要基本了解 CoreText完成任务。退房 Apple's Core Text Programming Guide了解什么是框架/线/字形运行/字形等。

    所以,这里是步骤:

  • 创建自定义 UIView 子类。
  • 拥有接受 NSAttributedString 的属性.
  • 创建一个 CTFramesetter使用该 NSAttributedString实例。
  • 覆盖 drawRect:方法
  • 创建一个 CTFrame来自 CTFramesetter 的实例.
  • 你需要给一个 CGPathRef创建 CTFrame .做那个 CGPath与您希望在其中绘制文本的框架相同。
  • 获取当前图形上下文并翻转文本坐标系。
  • 使用 CTFrameGetLines(...) ,获取 CTFrame 中的所有行你刚刚创建。
  • 使用 CTFrameGetLineOrigins(...) ,获取 CTFrame 的所有线起点.
  • 开始 for loop - 对于 CTLine 数组中的每一行...
  • 将文本位置设置为 CTLine 的开头使用 CGContextSetTextPosition(...) .
  • 使用 CTLineGetGlyphRuns(...)CTRunRef 获取所有 Glyph Runs ( CTLine ) .
  • 开始另一个 for loop - 对于 CTRun 数组中的每个 glyphRun ...
  • 使用 CTRunGetStringRange(...) 获取运行范围.
  • 使用 CTRunGetTypographicBounds(...) 获取排版边界.
  • 使用 CTLineGetOffsetForStringIndex(...) 获取运行的 x 偏移量.
  • 使用从上述函数返回的值计算边界矩形(我们称之为 runBounds)。
  • 记住 - CTRunGetTypographicBounds(...)需要指向变量的指针来存储文本的“上升”和“下降”。您需要添加这些以获得运行高度。
  • 使用 CTRunGetAttributes(...) 获取运行的属性.
  • 检查属性字典是否包含您的属性。
  • 如果您的属性存在,请计算需要绘制的矩形的边界。
  • 核心文本的行起点位于基线处。我们需要从文本的最低点绘制到最高点。因此,我们需要调整下降。
  • 因此,从我们在步骤 16 中计算的边界矩形中减去下降 (runBounds)。
  • 现在我们有了 runBounds ,我们知道我们要绘制的区域 - 现在我们可以使用任何 CoreGraphis/UIBezierPath使用特定圆角绘制和填充矩形的方法。
  • UIBezierPath有一个名为 bezierPathWithRoundedRect:byRoundingCorners:cornerRadii: 的便利类方法让你绕过特定的角落。您可以在第二个参数中使用位掩码指定角。
  • 现在您已经填充了矩形,只需使用 CTRunDraw(...) 绘制字形运行即可。 .
  • 庆祝您创建自定义属性的胜利 - 喝啤酒什么的! :D

  • 关于检测属性范围扩展到多次运行,当第一次运行遇到该属性时,您可以获得自定义属性的整个有效范围。如果你发现你的属性最大有效范围的长度大于你的run长度,你需要在右侧画尖角(对于从左到右的脚本)。更多的数学运算也可以让您检测下一行的高光角样式。 :)

    附上效果截图。顶部的盒子是标准的UITextView ,为此我设置了属性文本。底部的框是使用上述步骤实现的框。为两个 textViews 设置了相同的属性字符串。


    同样,如果有比我使用过的方法更好的方法,请告诉我! :D

    希望这对社区有所帮助。 :)

    干杯!

    关于ios - NSAttributedString 背景色和圆角,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16362407/

    有关ios - NSAttributedString 背景色和圆角的更多相关文章

    1. ruby-on-rails - 使用 Sublime Text 3 突出显示 HTML 背景语法中的 ERB? - 2

      所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择

    2. ruby-on-rails - 使用 Rmagick 或 ImageMagick 在背景上放置标题 - 2

      我有一张背景图片,我想在其中添加一个文本框。我想弄清楚如何将标题放置在其顶部的正确位置。(我使用标题是因为我需要自动换行功能)。现在,我只能让文本显示在左上角,但我需要能够手动定位它的开始位置。require'RMagick'require'Pry'includeMagicktext="Loremipsumdolorsitamet"img=ImageList.new('template001.jpg')img 最佳答案 这是使用convert的ImageMagick命令行的答案。如果你想在Rmagick中使用这个方法,你必须自己移植

    3. ruby - 如何验证 IO.copy_stream 是否成功 - 2

      这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

    4. Ruby 文件 IO 定界符? - 2

      我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

    5. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

      1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

    6. ruby - 为什么不能使用类IO的实例方法noecho? - 2

      print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

    7. ruby - 为 IO::popen 拯救 "command not found" - 2

      当我将IO::popen与不存在的命令一起使用时,我在屏幕上打印了一条错误消息:irb>IO.popen"fakefake"#=>#irb>(irb):1:commandnotfound:fakefake有什么方法可以捕获此错误,以便我可以在脚本中进行检查? 最佳答案 是:升级到ruby​​1.9。如果您在1.9中运行它,则会引发Errno::ENOENT,您将能够拯救它。(编辑)这是在1.8中的一种hackish方式:error=IO.pipe$stderr.reopenerror[1]pipe=IO.popen'qwe'#

    8. ruby - IO::EAGAINWaitReadable:资源暂时不可用 - 读取会阻塞 - 2

      当我尝试使用“套接字”库中的方法“read_nonblock”时出现以下错误IO::EAGAINWaitReadable:Resourcetemporarilyunavailable-readwouldblock但是当我通过终端上的IRB尝试时它工作正常如何让它读取缓冲区? 最佳答案 IgetthefollowingerrorwhenItrytousethemethod"read_nonblock"fromthe"socket"library当缓冲区中的数据未准备好时,这是预期的行为。由于异常IO::EAGAINWaitReadab

    9. ruby-on-rails - 在所有页面上使用 Prawn 的背景图像 - 2

      我在View中有这段代码prawn_document(:page_size=>"A4",:top_margin=>80,:bottom_margin=>40,:background=>"public/uploads/1.png")do|pdf|creation_date=Time.now.strftime('%d-%m-%Y')posts=@posts.eachdo|post|pdf.pad(10)dopdf.textpost.titlepdf.textpost.textendendpdf.page_count.timesdo|i|pdf.go_to_page(i+1)pdf.draw

    10. ruby - 如何使用 ruby​​ fibers 避免阻塞 IO - 2

      我需要将目录中的一堆文件上传到S3。由于上传所需的90%以上的时间都花在了等待http请求完成上,所以我想以某种方式同时执行其中的几个。Fibers能帮我解决这个问题吗?它们被描述为解决此类问题的一种方法,但我想不出在http调用阻塞时我可以做任何工作的任何方法。有什么方法可以在没有线程的情况下解决这个问题? 最佳答案 我没有使用1.9中的纤程,但是1.8.6中的常规线程可以解决这个问题。尝试使用队列http://ruby-doc.org/stdlib/libdoc/thread/rdoc/classes/Queue.html查看文

    随机推荐