0

我敢肯定这里有一个非常非常简单的解决方案,但我似乎无法弄清楚。我有一个带有节标题的水平滚动 UICollectionView。我希望节标题文本垂直书写,如下所示:

节标题

我知道这与旋转上下文有关,但是尽管阅读了文档并阅读了此处的类似帖子,但我似乎无法完全掌握这一点。这是我到目前为止所拥有的:

- (void)drawTitle
{
    CGRect titleRect = self.bounds;

    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc]init];
    paragraphStyle.alignment = NSTextAlignmentCenter;
    UIFont *cellFont = [UIFont fontWithName: DEFAULT_FONT size: self.bounds.size.width * FONT_WIDTH_FACTOR];

    NSAttributedString *cellText = [[NSAttributedString alloc] initWithString: self.title attributes: @{ NSParagraphStyleAttributeName : paragraphStyle, NSFontAttributeName : cellFont, NSForegroundColorAttributeName : [UIColor whiteColor] }];

    [cellText drawInRect: titleRect];

    // Rotation code???
}

我真的很感激这方面的帮助,就像我确定它一样简单。我只是显然在这里遗漏了一些东西。非常感谢,提前。

4

2 回答 2

2

这是您的图形上下文的图表,如果您按照现在的方式绘制文本:

图1

我们需要做两件事。我们需要旋转坐标系以使文本垂直绘制,并且我们需要移动坐标系(或文本矩形)以使旋转后的文本矩形恰好与(未旋转的)self.bounds矩形重叠。

我们根本无法使用 UIKit 函数来转换坐标系。我们必须深入到核心图形(又名 Quartz)级别。所以首先,我们得到一个图形上下文的引用并保存它的状态:

CGContextRef gc = UIGraphicsGetCurrentContext();
CGContextSaveGState(gc); {

现在我们可以变换坐标系了。首先,我们将原点“平移”(移动)到边界矩形的左下角:

    CGContextTranslateCTM(gc, 0, titleRect.size.height);

此时,如果我们绘制字符串,图形上下文将如下所示:

图2

所以现在我们将坐标系旋转一个直角:

    CGContextRotateCTM(gc, -M_PI_2);

可能我的角度符号错误。如果没有任何显示,请尝试删除该-标志。

现在,如果我们绘制字符串,图形上下文将如下所示:

图 3

请注意,在我们传递给 的矩形中drawInRect:width始终是沿 x 轴的距离,现在 x 轴是垂直的。所以我们希望文本矩形与视图的高度一样宽,并且我们希望文本矩形与视图的宽度一样高。因此:

    [cellText drawInRect:CGRectMake(0, 0, titleRect.size.height, titleRect.size.width)];

我们都完成了,所以我们恢复图形上下文的状态:

} CGContextRestoreGState(gc);

全部一起:

CGContextRef gc = UIGraphicsGetCurrentContext();
CGContextSaveGState(gc); {
    CGContextTranslateCTM(gc, 0, titleRect.size.height);
    CGContextRotateCTM(gc, -M_PI_2);
    [cellText drawInRect:CGRectMake(0, 0, titleRect.size.height, titleRect.size.width)];
} CGContextRestoreGState(gc);
于 2013-07-14T05:29:19.253 回答
0

这不是对这个问题的另一个答案,而只是对 rob mayoff 已经非常出色的答案的跟进。

我也遇到了旋转后文本没有居中的问题。我想出了以下“修复”——嗯,让我们称之为它是什么,一个杂物——让文本居中。

我绝不是 iPhone 编程专家,毫无疑问有更好的方法可以做到这一点,但这对我有用。

if (...scrolling is horizontal...) {
    // Rotate the text so it runs vertically.
    CGAffineTransform rotateItem = CGAffineTransformMakeRotation(-M_PI_2);
    header.label.transform = rotateItem;

    // After rotating the label the text is always left-justified,
    // i.e. it appears at the bottom of the screen. Do some calculations
    // to get the title space-padded so it appears roughly centered.

    // Calculate the size of the label.
    float sizeOfLabel = [header.label.text sizeWithFont:header.label.font].width;

    // Calculate where the label should start if it is to appear centered.
    float centeredLabelStartPosition = (header.frame.size.height - sizeOfLabel) / 2.0;

    // Calculate the size of a space character.
    float sizeOfSpaceChar = [@" " sizeWithFont:header.label.font].width;

    // Calculate how many leading space characters are needed to appear before the label
    // so that the label appears centered. (The +1 is because I like it shifted
    // ever-so-slightly toward the top of the screen, rather than true center.)
    int numberOfLeadingSpaces = roundf(centeredLabelStartPosition / sizeOfSpaceChar) + 1;

    // Create the label with leading space padding to get it centered.
    header.label.text = [NSString stringWithFormat:@"%*s%@", numberOfLeadingSpaces, "", header.label.text];
} else {
    // For vertical scrolling, turn off the rotation (which might have been left on
    // if this label was used previously).
    header.label.transform = CGAffineTransformIdentity;
}

重要提示:当用户在水平和垂直之间旋转 iPhone 方向时,iOS 不会调用 collectionView:viewForSupplementaryElementOfKind:atIndexPath: 来重绘节标题。因此,标题不会自动重新以旋转为中心。


这是使标题文本居中的更简单方法……如果您愿意为您的应用关闭“自动布局”。这还有一个好处是标题可以在旋转时自动重新居中。在情节提要中,您必须将标题设置为水平扩展(或以编程方式进行)。

if (...scrolling is horizontal...) {
    // Rotate the text so it runs vertically.
    header.label.transform = CGAffineTransformMakeRotation(-M_PI_2);
    // Center the text after rotation.
    header.label.frame = CGRectMake(0.0, 0.0, header.frame.size.width, header.frame.size.height);
    header.label.center = CGPointMake(header.frame.size.width/2, header.frame.size.height/2);
} else {
    // For vertical scrolling, turn off the rotation (which might have been left on
    // if this label was used previously).
    header.label.transform = CGAffineTransformIdentity;
}
于 2013-07-24T19:32:17.783 回答