正确使用 DrawRect 覆盖 - 我可以防止视图拉伸吗?

Posted

技术标签:

【中文标题】正确使用 DrawRect 覆盖 - 我可以防止视图拉伸吗?【英文标题】:Proper use of DrawRect override - can I prevent view stretching? 【发布时间】:2013-04-01 20:30:11 【问题描述】:

编辑:以下详细问题的简化版本:您能否通过子类 drawRect 更新 UIView 的边界而不导致视图内容拉伸?


我正在构建一个新闻阅读器应用程序,并且一直在研究如何将我的 UIView 拆分为列并仍然对内容进行分页。我相信我已经对列进行了基本编码(将 XML 节点内容按段落拆分为数组,然后通过检测不切断段落所需的总面积进行解析。)

我遇到的问题是我无法在没有文本拉伸的情况下更新 ContentBounds,即使里面的内容足够大以支持未拉伸的视图。

基本上是这样的:

contentBounds = CGSizeMake(self.bounds.size.width, self.bounds.size.height+COLUMN_YPOS);

[renderer updateContentBounds:contentBounds];

造成这种情况:(图片下方的完整代码)

- (void)drawRect:(CGRect)rect


NSString *string = contentString;
[string stringByReplacingOccurrencesOfString:@"<br>" withString:@"\n\n"];

// column width
int COLUMN_WIDTH = self.bounds.size.width/2-40;
int COLUMN_HEIGHT = self.bounds.size.height-100;

int COLUMN_XPOS = 20;
int COLUMN_YPOS = 0;

int PAGE_HEIGHT = COLUMN_HEIGHT + 40;

CGSize maximumSize = CGSizeMake(COLUMN_WIDTH, COLUMN_HEIGHT-20);

NSArray *paragraphs = [string componentsSeparatedByString:@"\n"];

NSString *textBuffer = @"";
NSString *preBuffer = @"";
NSString *currentStringSegment;

for (int i=0; i<[paragraphs count]; i++) 

    currentStringSegment = [paragraphs objectAtIndex:i];

    preBuffer = textBuffer;
    textBuffer = [textBuffer stringByAppendingString:@"\n\n"];
    textBuffer = [textBuffer stringByAppendingString:currentStringSegment];

    CGSize expectedSize = [textBuffer sizeWithFont:[UIFont fontWithName:@"Times New Roman" size:16] constrainedToSize:CGSizeMake(COLUMN_WIDTH, COLUMN_HEIGHT) lineBreakMode:NSLineBreakByWordWrapping];

    if(expectedSize.height > maximumSize.height)

        [preBuffer drawInRect:CGRectMake(COLUMN_XPOS, COLUMN_YPOS, COLUMN_WIDTH, COLUMN_HEIGHT) withFont:[UIFont fontWithName:@"Times New Roman" size:16] lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];
        i--;
        textBuffer = @"";
        preBuffer = @"";

        if(COLUMN_XPOS > 20) 

            COLUMN_XPOS = 20;
            COLUMN_YPOS += PAGE_HEIGHT;

         else 

            COLUMN_XPOS = COLUMN_WIDTH + 60;

        

    



if(![preBuffer isEqualToString:@""] && preBuffer != nil)

    [preBuffer drawInRect:CGRectMake(COLUMN_XPOS, COLUMN_YPOS, COLUMN_WIDTH, COLUMN_HEIGHT) withFont:[UIFont fontWithName:@"Times New Roman" size:16] lineBreakMode:NSLineBreakByWordWrapping alignment:NSTextAlignmentLeft];



contentBounds = CGSizeMake(self.bounds.size.width, self.bounds.size.height);

[renderer updateContentBounds:contentBounds];


【问题讨论】:

您是否将 UIView 的内容模式设置为 UIViewContentModeScaleToFill 以外的模式?您确定不想使用标签或文本视图,甚至是 Web 视图吗?在 drawRect 中处理它意味着您正在创建一个位图,因此,您必须在渲染它之前自己完成所有工作,例如放置和缩放。 我曾讨论过使用 Web 视图,但我希望能够动态呈现按页面拆分列的页面。我可以从 drawRect 中调整视图的比例吗?还是我需要将新维度传递给另一个函数来处理? 我不得不问:为什么不直接使用 UILabel 作为分页视图的子视图来充当列?或者 UITextView 如果你想滚动?这似乎是很多不必要的努力。 【参考方案1】:

当边界更改由contentMode 属性确定时UIView 的行为。

如果您查看documentation,您将阅读:

contentMode 属性中的值决定了位图是否应该缩放以适应新的边界,或者只是固定到视图的一个角或边缘。

默认情况下,contentMode 设置为 UIViewContentModeScaleToFill,您可以在同一个文档页面中阅读,

使视图的内容被缩放以适应新的帧大小。

您可能希望将视图的contentMode 更改为不失真的行为,例如UIViewContentModeTop,这将使在视图边界顶部对齐的内容居中。

您可以找到contentMode here 的所有可能值。

【讨论】:

具体来说,如果您希望系统在更改视图的边界时发送drawRect:,请将contentMode 设置为UIViewContentModeRedraw【参考方案2】:

您可以在分页模式下使用 UIScrollView。

Scrolling Using Paging Mode

您可以在 UIScrollView 中放置一个 UIWebView 并使用 html/CSS 创建列,关闭 Web 视图上的用户交互,并使用 UIScrollView 水平滚动列。

【讨论】:

以上是关于正确使用 DrawRect 覆盖 - 我可以防止视图拉伸吗?的主要内容,如果未能解决你的问题,请参考以下文章

drawRect 没有绘制正确的形状

剪辑时如何避免覆盖drawRect

覆盖绘图应用程序的drawRect

子类化 UIToolbar 并覆盖 drawRect: - UIBarButtonItems 不显示

在 UIScrollView 中覆盖 drawRect 时的黑色背景

当我覆盖“drawRect”时,UIButton 样式设置被忽略