什么是强制UIView重绘最强大的方法?

我有一个项目列表的UITableView。 select一个项目推一个viewController,然后继续执行以下操作。 从方法viewDidLoad我发射一个URLRequest为我的子视图所需的数据 – 一个UIView子类与drawRect覆盖。 当数据从云端到达时,我开始构build我的视图层次结构。 有问题的子类传递数据,它的drawRect方法现在拥有了它需要呈现的所有东西。

但。

因为我不明确调用drawRect – Cocoa-Touch处理 – 我没有办法通知Cocoa-Touch,我真的很想要这个UIView子类来呈现。 什么时候? 现在会很好!

我试过[myView setNeedsDisplay]。 有时这种工作。 很斑点。

我已经摔了几个小时。 有谁可以请我提供一个坚实的,有保证的方法来强制UIView重新渲染。

以下是将数据提供给视图的代码片段:

// Create the subview self.chromosomeBlockView = [[[ChromosomeBlockView alloc] initWithFrame:frame] autorelease]; // Set some properties self.chromosomeBlockView.sequenceString = self.sequenceString; self.chromosomeBlockView.nucleotideBases = self.nucleotideLettersDictionary; // Insert the view in the view hierarchy [self.containerView addSubview:self.chromosomeBlockView]; [self.containerView bringSubviewToFront:self.chromosomeBlockView]; // A vain attempt to convince Cocoa-Touch that this view is worthy of being displayed ;-) [self.chromosomeBlockView setNeedsDisplay]; 

干杯,道格

强制UIView重新呈现的有保证的,坚如磐石的方式是[myView setNeedsDisplay] 。 如果遇到问题,您可能会遇到以下其中一个问题:

  • 在实际拥有数据之前调用它,或者-drawRect:过度caching某些内容。

  • 您期望在您调用此方法的时刻绘制视图。 使用Cocoa绘图系统故意没有办法要求“现在画第二个”。 这将扰乱整个视图合成系统,垃圾性能和可能造成各种制造。 只有这样才能说“这需要在下一个抽签周期中”。

如果你需要的是“一些逻辑,绘制,一些更多的逻辑”,那么你需要把“更多的逻辑”放在一个单独的方法中,并使用-performSelector:withObject:afterDelay:调用它-performSelector:withObject:afterDelay:延迟0在下一个抽签周期之后放上“更多的逻辑”。 看到这个问题的例子,这种代码,以及可能需要的情况下(虽然通常是最好寻找其他解决scheme,如果可能的话,因为它使代码复杂)。

如果你不认为事物正在被绘制,在-drawRect:放置一个断点-drawRect:看看你什么时候被调用。 如果你正在调用-setNeedsDisplay ,但是-drawRect:在下一个事件循环中没有被调用,那么就深入你的视图层次结构,并确保你没有尝试智取某个地方。 过分的聪明是我经验不好的第一个原因。 当你认为如何欺骗系统做你想做的事情时,你通常会把它做到你不想要的地步。

在调用setNeedsDisplay和drawRect之间有一个很大的延迟:(5秒)。 事实certificate,我在不同于主线程的线程中调用了setNeedsDisplay。 把这个电话转到主线后,延迟就消失了。

希望这个对你有帮助。

在退还保证,钢筋混凝土坚实的方式来强制视图同步绘制 (在返回到调用代码之前)是configurationCALayer与您的UIView子类的交互。

在你的UIView子类中,创build一个- display方法,告诉图层“ 是的,它需要显示 ”,然后“ 做到这一点 ”:

 /// Redraws the view's contents immediately. /// Serves the same purpose as the display method in GLKView. /// Not to be confused with CALayer's `- display`; naming's really up to you. - (void)display { CALayer *layer = self.layer; [layer setNeedsDisplay]; [layer displayIfNeeded]; } 

还要实现一个- drawLayer:inContext:方法,它会调用你的私有/内部绘图方法(因为每个UIView都是一个CALayerDelegate)

 /// Called by our CALayer when it wants us to draw /// (in compliance with the CALayerDelegate protocol). - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context { UIGraphicsPushContext(context); [self internalDrawWithRect:self.bounds]; UIGraphicsPopContext(); } 

并创build您的自定义- internalDrawWithRect:方法,以及故障安全- drawRect: ::

 /// Internal drawing method; naming's up to you. - (void)internalDrawWithRect:(CGRect)rect { // @FILLIN: Custom drawing code goes here. // (Use `UIGraphicsGetCurrentContext()` where necessary.) } /// For compatibility, if something besides our display method asks for draw. - (void)drawRect:(CGRect)rect { [self internalDrawWithRect:rect]; } 

现在只要你真的需要绘制,就调用[myView display]- display将告诉CALayer displayIfNeeded ,它将同步callback到我们的- drawLayer:inContext:然后在- internalDrawWithRect:进行绘制- internalDrawWithRect:在继续之前更新绘制到上下文中的视觉效果。


这种方法类似于上面的@ RobNapier,但是除了- setNeedsDisplay之外,还具有调用- displayIfNeeded的优点,这使得它是同步的。

这是可能的,因为CALayerUIView显示更多的绘图function。图层比视图更低级别,并且为了布局中高度可configuration的绘图的目的而明确地devise,并且(像Cocoa中的许多事物)被devise为被使用灵活地(作为父母class级,或作为一个委托人,或作为一个桥梁,其他绘图系统,或只是自己)。

有关CALayer的可configuration性的更多信息可以在Core Animation Programming Guide的“ 设置层对象”部分find。

我遇到了同样的问题,所有来自SO或Google的解决scheme都不适合我。 通常情况下, setNeedsDisplay不起作用,但是当它不…
我试图从每一个可能的线程和东西的每一个可能的方式调用setNeedsDisplay视图 – 仍然没有成功。 我们知道,正如罗布所说的那样

“这需要在下一个绘制周期中绘制。”

但由于某种原因,这一次不会得出结论。 我发现的唯一解决方法是在一段时间后手动调用它,让任何阻止绘制的东西消失,如下所示:

 dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.005 * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { [viewToRefresh setNeedsDisplay]; }); 

如果您不需要经常重绘视图,这是一个很好的解决scheme。 否则,如果你正在做一些移动(动作)的东西,调用setNeedsDisplay通常没有问题。

我希望这会帮助那些像我一样迷失在那里的人。

那么我知道这可能是一个很大的变化,甚至不适合你的项目,但是你有没有考虑过在推进数据之前不要进行推送 ? 这样,您只需要画一次视图,用户体验也会更好 – 推送将会在已经加载的情况下移动。

你这样做的方式是在你asynchronous要求数据的UITableView didSelectRowAtIndexPath 。 一旦你收到响应,你手动执行segue并将数据传递给prepareForSegue的viewController。 同时你可能想要显示一些活动指标,对于简单的加载指标检查https://github.com/jdg/MBProgressHUD