[英]Drawing rotated text with NSString drawInRect
我找到了關於如何使用 NSString drawInRect: 繪制旋轉文本的答案,但我不確定它是如何工作的,因為它只對我有用: https ://discussions.apple.com/thread/1779814?start =0&tstart =0
我的代碼看起來像:
CGContextSaveGState(context);
CGContextDrawLinearGradient(context, gradient, CGPointMake(0, centY - halfWidth), CGPointMake(0, centY + halfWidth), 0);
// Add text
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
NSString *str = @"some test string";
CGAffineTransform transform1 = CGAffineTransformMakeRotation(M_PI/4);
CGContextConcatCTM(context, transform1);
CGContextTranslateCTM(context, 0, 0);
UIFont *font = [UIFont systemFontOfSize:16.0];
[str drawInRect:CGRectMake(0, 0, 200, 100) withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:UIBaselineAdjustmentNone];
所以當我使用它時,我看到文本被繪制在 x 軸下方 45 度處。 我想沿着我的線性漸變垂直繪制文本。 所以我想我可以通過使用 M_PI/2 90 度來做到這一點。 我沒有看到我的文字。 我嘗試了不同的旋轉變換,只有一些看起來像 M_PI/4 和 M_PI/8。 我認為如果我使用 -M_PI/4 它將使文本在 x 軸上方 45 度處,而 M_PI/2 將在 x 軸下方 90 度處。 但兩者都一無所獲。
有什么想法嗎? 謝謝。
我用下一個方法解決這個問題。
1) 在 NSString 上聲明類別
@interface NSString (NMSchemeItemDraw)
-(void) drawWithBasePoint:(CGPoint)basePoint
andAngle:(CGFloat)angle
andFont:(UIFont*)font;
@end
此類別將使用給定的中心點在一行中以給定的字體和角度繪制文本。
2)這個類的實現看起來像:
@implementation NSString (NMSchemeItemDraw)
-(void) drawWithBasePoint:(CGPoint)basePoint
andAngle:(CGFloat)angle
andFont:(UIFont *)font{
CGSize textSize = [self sizeWithFont:font];
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform t = CGAffineTransformMakeTranslation(basePoint.x, basePoint.y);
CGAffineTransform r = CGAffineTransformMakeRotation(angle);
CGContextConcatCTM(context, t);
CGContextConcatCTM(context, r);
[self drawAtPoint:CGPointMake(-1 * textSize.width / 2, -1 * textSize.height / 2)
withFont:font];
CGContextConcatCTM(context, CGAffineTransformInvert(r));
CGContextConcatCTM(context, CGAffineTransformInvert(t));
}
@end
3) 現在我可以在我的[UIView drawRect:]
方法中使用它。 例如,在下一個方式:
-(void)drawRect:(CGRect)rect{
NSString* example = @"Title";
[example drawWithBasePoint:CGPointMake(0.0f, 0.0f)
andAngle:M_PI
andFont:[UIFont boldSystemFontOfSize:16.0]];
}
我認為發生的事情是您將文本旋轉到視圖之外的位置,因為它通過圍繞原點旋轉來旋轉上下文。
旋轉后,您需要進行平移以將上下文移回視圖中。 在下面的示例中,我將上下文逆時針旋轉 90 度。 然后我將上下文的 tx 轉換為高度的距離。
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
// Create the gradient
CGColorRef startColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0].CGColor;
CGColorRef endColor = [UIColor colorWithRed:200.0/255.0 green:200.0/255.0 blue:200.0/255.0 alpha:1.0].CGColor;
NSArray *colors = [NSArray arrayWithObjects:(id)startColor, (id)endColor, nil];
CGFloat locations[] = { 0.0, 1.0 };
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (CFArrayRef) colors, locations);
CGContextDrawLinearGradient(context, gradient, CGPointMake(rect.origin.x + rect.size.width / 2, rect.origin.y), CGPointMake(rect.origin.x + rect.size.width / 2, rect.origin.y + rect.size.height), 0);
// Create text
CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
NSString *string = @"some test string";
UIFont *font = [UIFont systemFontOfSize:16.0];
// Rotate the context 90 degrees (convert to radians)
CGAffineTransform transform1 = CGAffineTransformMakeRotation(-M_PI_2);
CGContextConcatCTM(context, transform1);
// Move the context back into the view
CGContextTranslateCTM(context, -rect.size.height, 0);
// Draw the string
[string drawInRect:rect withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentLeft];
// Clean up
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
CGContextRestoreGState(context);
}
請注意,您還可以獲得字符串呈現方式的大小,這有助於計算文本的對齊方式。
CGSize stringSize = [string sizeWithFont:font];
這是 KoNEW 答案的更新和簡化版本。 它保留了圖形上下文的狀態作為獎勵。 這也是一個簡單的函數,而不是一個字符串擴展。
func drawRotatedText(_ text: String, at p: CGPoint, angle: CGFloat, font: UIFont, color: UIColor) {
// Draw text centered on the point, rotated by an angle in degrees moving clockwise.
let attrs = [NSFontAttributeName: font, NSForegroundColorAttributeName: color]
let textSize = text.size(attributes: attrs)
let c = UIGraphicsGetCurrentContext()!
c.saveGState()
// Translate the origin to the drawing location and rotate the coordinate system.
c.translateBy(x: p.x, y: p.y)
c.rotate(by: angle * .pi / 180)
// Draw the text centered at the point.
text.draw(at: CGPoint(x: -textSize.width / 2, y: -textSize.height / 2), withAttributes: attrs)
// Restore the original coordinate system.
c.restoreGState()
}
KoNew 在 Swift 中的解決方案:
extension NSString {
func drawWithBasePoint(basePoint:CGPoint, angle:CGFloat, font:UIFont) {
var attrs: NSDictionary = [
NSFontAttributeName: font
]
var textSize:CGSize = self.sizeWithAttributes(attrs as [NSObject : AnyObject])
// sizeWithAttributes is only effective with single line NSString text
// use boundingRectWithSize for multi line text
var context: CGContextRef = UIGraphicsGetCurrentContext()
var t:CGAffineTransform = CGAffineTransformMakeTranslation(basePoint.x, basePoint.y)
var r:CGAffineTransform = CGAffineTransformMakeRotation(angle)
CGContextConcatCTM(context, t)
CGContextConcatCTM(context, r)
self.drawAtPoint(CGPointMake(-1 * textSize.width / 2, -1 * textSize.height / 2), withAttributes: attrs as [NSObject : AnyObject])
CGContextConcatCTM(context, CGAffineTransformInvert(r))
CGContextConcatCTM(context, CGAffineTransformInvert(t))
}
}
使用:
let fieldFont = UIFont(name: "Helvetica Neue", size: 14)
myNSString.drawWithBasePoint(CGPointMake(bounds.width/2, bounds.height/2), angle: CGFloat(-M_PI_2), font: fieldFont!)
感謝這篇文章,以及Chris 的回答,以及Arkadiusz 在另一篇文章中的回答。
最后,我通過一個名為MyVerticalLabel
的UILabel
子類解決了這個問題,並使其繪制了垂直文本。
@implementation MyVerticalLabel
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform transform = CGAffineTransformMakeRotation(-M_PI_2);
CGContextConcatCTM(context, transform);
CGContextTranslateCTM(context, -rect.size.height, 0);
// The drawing rect should be applied with transform to.
CGRect newRect = CGRectApplyAffineTransform(rect, transform);
newRect.origin = CGPointZero;
NSMutableParagraphStyle *textStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
textStyle.lineBreakMode = self.lineBreakMode;
textStyle.alignment = self.textAlignment;
// Apply current label attributes for drawing function.
NSDictionary *attributeDict =
@{
NSFontAttributeName : self.font,
NSForegroundColorAttributeName : self.textColor,
NSParagraphStyleAttributeName : textStyle,
};
[self.text drawInRect:newRect withAttributes:attributeDict];
}
@end
我發現上面托德的答案非常有幫助。 但是,我經常想相對於文本的邊緣之一(頂部、左側等)定位和旋轉文本。 所以,我擴展了他的回答。 此外,使用了屬性文本,因此可以獨立處理字體、顏色等。
enum StringOrigin: Int { case
upperLeft, upperCenter, upperRight,
centerLeft, centerCenter, centerRight,
lowerLeft, lowerCenter, lowerRight }
func drawRotatedAttrString(_ s: NSAttributedString, p: CGPoint, angle: CGFloat, origin: StringOrigin) {
let width = s.size().width
let height = s.size().height
let c = UIGraphicsGetCurrentContext()!
c.saveGState()
// Translate the origin to the drawing location and rotate the coordinate system.
c.translateBy(x: p.x, y: p.y)
c.rotate(by: angle * .pi / 180)
// Draw the text offset to handle "origin" choice
switch origin {
case .upperLeft:
s.draw(at: .zero)
case .upperCenter:
s.draw(at: CGPoint(x: -0.5 * width, y: 0))
case .upperRight:
s.draw(at: CGPoint(x: -width, y: 0))
case .centerLeft:
s.draw(at: CGPoint(x: 0, y: -0.5 * height))
case .centerCenter:
s.draw(at: CGPoint(x: -0.5 * width, y: -0.5 * height))
case .centerRight:
s.draw(at: CGPoint(x: -width, y: -0.5 * height))
case .lowerLeft:
s.draw(at: CGPoint(x: 0, y: -height))
case .lowerCenter:
s.draw(at: CGPoint(x: -0.5 * width, y: -height))
case .lowerRight:
s.draw(at: CGPoint(x: -width, y: -height))
}
// Restore the original coordinate system.
c.restoreGState()
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.