Objective C - 在UICollectionView中旋转节头的边界

时间:2013-07-14 04:54:36

标签: objective-c rotation uicollectionview drawrect

我确信这里有一个非常非常简单的解决方案,但我似乎无法弄明白。我有一个水平滚动UICollectionView与节标题。我希望段标题文本垂直写入:

Section headers

我知道它与旋转上下文有关,但是尽管阅读了文档并在这里阅读了类似的帖子,但我似乎无法理解这一点。这就是我到目前为止所做的:

- (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???
}

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

2 个答案:

答案 0 :(得分:2)

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

diagram 1

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

我们无法使用UIKit功能转换坐标系。我们必须进入Core Graphics(aka Quartz)级别。首先,我们获得对图形上下文的引用并保存其状态:

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

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

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

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

diagram 2

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

    CGContextRotateCTM(gc, -M_PI_2);

我可能有角度错误的迹象。如果没有显示任何内容,请尝试删除-符号。

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

diagram 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);

答案 1 :(得分:0)

这不是问题的另一个答案,而只是抢劫mayoff的优秀答案的后续行动。

旋转后,我也遇到了没有居中的问题。我想出了下面的“修复” - 呃,让我们称之为它,一个kludge - 让文本居中。

我绝不是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;
}