什么是最可靠的方法来强制一个UIView重绘?(What is the most robust wa

2019-07-20 10:05发布

我有一个项目列表一个UITableView。 选择一个项目推一个的viewController那然后继续执行以下操作。 从方法viewDidLoad中我火了一个URLRequest对于需要通过我的子视图的数据 - 一个UIView子类用的drawRect覆盖。 当数据从云到达我开始建立我的看法层次。 有问题的子类被传递的数据,它的drawRect方法现在有它需要呈现的一切。

但。

因为我不叫drawRect中明确 - 可可触摸手柄 - 我没有通知可可触摸,我真的,真的希望这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];

欢呼声,道格

Answer 1:

保证,岩石固的方式来强制UIView重新渲染是[myView setNeedsDisplay] 如果您遇到麻烦,你可能遇到了这些问题之一:

  • 你说它你确实有数据,或者您之前-drawRect:过度缓存的东西。

  • 你期待的观点在调用此方法的那一刻绘制。 有故意没有办法要求“画现在这个非常第二个”使用Cocoa绘制系统。 这将破坏整个视图合成系统,垃圾的性能和可能制造出各种伪像的。 只有的方式说“这需要在接下来的抽奖周期的结论。”

如果你需要的是“一些逻辑,画,多了一些逻辑,”那么你需要把“一些更多的逻辑”,在一个单独的方法,并使用调用它-performSelector:withObject:afterDelay:与0的拖延地放“一些更多的逻辑”下一个抽奖周期之后。 见这个问题的那种代码示例,并在可能需要它的情况下(虽然通常最好去寻找其他的解决方案,如果可能的,因为它的代码复杂)。

如果你不觉得事情越来越绘制做的,放在一个断点-drawRect:看当你要调用。 如果你调用-setNeedsDisplay ,但-drawRect:是没有得到所谓的下一个事件循环,然后深入到你的视图层次,并确保你不是想智取的地方。 过小聪明坏图纸在我的经验头号原因。 当你认为你最清楚如何欺骗系统去做你想要什么,你通常得到它做你不想要什么。



Answer 2:

我有一个问题,呼吁setNeedsDisplay和drawRect中之间有很大的延迟:(5秒)。 原来,我在不同的线程比主线程调用setNeedsDisplay。 此调用移动到主线程后延迟走了。

希望这个对你有帮助。



Answer 3:

该退款保证,钢筋混凝土,实心办法强迫为了同步画 (返回到调用代码之前)是配置CALayer的与你互动UIView子类。

在你的UIView子类,创建一个- 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();
}

并创建自定义- 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会告诉CALayerdisplayIfNeeded ,这将同步回调到我们的- drawLayer:inContext:做图中- internalDrawWithRect:更新目视着什么卷入背景在移动之前。


这种方法类似于@ RobNapier头顶,但调用的优势- displayIfNeeded除了- setNeedsDisplay ,这使得它同步。

这是可能的,因为CALayer的expose超过绘图功能UIView小号DO-层是较低级别比视图和明确的布局内的高度可配置的图的目的而设计的,和(如在可可多的东西)被设计为可以使用灵活(作为父类,或作为代理方,或作为一个桥梁和其他绘图系统,或者只是自己)。

有关的可配置性的更多信息CALayer可以在发现小号设置层对象的核心动画编程指南的部分 。



Answer 4:

我有同样的问题,并从SO或谷歌所有的解决方案并没有为我工作。 通常情况下, 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];
});

这是一个很好的解决方案,如果你不需要的观点,真正经常重绘。 否则,如果你正在做一些运动(动作)的东西,通常只调用没有问题setNeedsDisplay

我希望这会帮助别人谁是失去了在那里,就像我。



Answer 5:

嗯,我知道这可能是一个很大的变化,甚至不适合你的项目,但你考虑不执行推,直到你已经拥有的数据 ? 这样,你只需要一次绘制视图和用户体验也将得到更好的 - 推将在移动已加载。

你这样做的方式是在UITableView didSelectRowAtIndexPath你异步请求的数据。 一旦你收到的响应,可以手动执行SEGUE并将数据传递到您的viewController prepareForSegue 。 同时您可能希望显示一些活动的指标,为简单的加载指示灯检查https://github.com/jdg/MBProgressHUD



文章来源: What is the most robust way to force a UIView to redraw?