- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在使用 CoreGraphics 在 CGContext 中绘制单个字形和图元。以下代码适用于 XCode 9.2 中的 swift playground 当在 playground 中启动时,一个带有两倍字母 A 的小矩形应该出现在 playground liveView 的给定坐标处。
import Cocoa
import PlaygroundSupport
class MyView: NSView {
init(inFrame: CGRect) {
super.init(frame: inFrame)
}
required init?(coder decoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
// setup context properties
let context: CGContext = NSGraphicsContext.current!.cgContext
context.setStrokeColor(CGColor.black)
context.setTextDrawingMode(.fill)
context.setFillColor(CGColor(red: 0.99, green: 0.99, blue: 0.85, alpha: 1))
context.beginPath()
context.addRect(rect)
context.fillPath()
context.setFillColor(.black)
// prepare variables and constants
var font = CTFontCreateWithName("Helvetica" as CFString, 48, nil)
var glyph = CTFontGetGlyphWithName(font, "A" as CFString)
var glyph1Position = CGPoint(x: self.frame.minX, y: self.frame.maxY/2)
var glyph2Position = CGPoint(x: self.frame.minX+150, y: self.frame.maxY/2)
let text = "Hello"
var textOrigin = NSPoint(x: self.frame.minX+50, y: self.frame.maxY/2)
// draw one character
CTFontDrawGlyphs(font, &glyph, &glyph1Position, 1, context)
// *** *** when the next line is uncommented the bug appears *** ***
// text.draw(at: textOrigin)
CTFontDrawGlyphs(font, &glyph, &glyph2Position, 1, context)
}
}
var frameRect = CGRect(x: 0, y: 0, width: 200, height: 100)
PlaygroundPage.current.liveView = MyView(inFrame: frameRect)
现在我想在相同的上下文中绘制常规文本。但是,当通过自己的绘制方法在两个字形的绘制之间绘制文本字符串时,当前上下文似乎乱七八糟,第二个字形不会显示。在绘制两个单个字形后绘制文本时,一切都很好。
很明显绘制文本似乎对当前的 CGContext 有影响,但我无法找出到底发生了什么。我在绘制字符串之前尝试了 saveGstate() 方法并在之后恢复,但没有成功。
我还尝试使用 CoreText 方法通过 CTFramesetterCreateWithAttributedString 创建属性字符串并使用 CTFramesetterCreateFrame 显示它,它也不起作用,在创建框架 setter 之后,上下文变得困惑。
我的实际 playground 更复杂,字形并没有完全消失,而是显示在错误的垂直位置,但基本问题 - 问题是相同的:
如何在不在后台对上下文进行任何其他更改的情况下将文本绘制到 currentContext 中?
最佳答案
您需要设置文本矩阵(应用于文本绘制的转换)。您应该始终在绘制文本之前设置它,因为它不是图形状态的一部分,并且可能会被其他绘图代码(例如 AppKit 的字符串绘图扩展)破坏。
在调用 CTFontDrawGlyphs
之前添加以下内容:
context.textMatrix = .identity
这应该在上下文的初始设置中调用,因为在调用 drawRect
之前没有保证文本矩阵是相同的。然后,任何时候你调用了修改文本矩阵的东西,你都需要将它设置回你想要的东西(在这种情况下是身份,但如果你想以一种奇特的方式绘制它可能是其他东西)。
修改文本矩阵的内容并不总是显而易见的。 AppKit 绘图函数几乎总是如此(尽管我不知道有任何文档表明这一点)。修改上下文的 Core Text 函数,如 CTFrameDraw
和 CTLineDraw
,通常会用如下语句记录此事实:
This call can leave the context in any state and does not flush it after the draw operation.
同样 CTFontDrawGlyphs
警告:
This function modifies graphics state including font, text size, and text matrix if these attributes are specified in font. These attributes are not restored.
通常我不鼓励混合文本绘图系统。使用 AppKit 或 Core Text,但不要混用。如果您选择一个并坚持使用,那么这通常不是问题(只要您在 drawRect
的顶部初始化矩阵一次)。例如,如果您使用 CTFontDrawGlyphs
完成所有绘图,则不需要每次都重新设置矩阵;你会留在 Core Text 矩阵中并且它会很好(这就是为什么当你注释掉 draw(at:)
调用时它起作用的原因)。
关于swift text.draw 方法搞乱了 CGContext,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53047093/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!