当UIView内部可见时,如何绘制UIView的各个部分? [英] How to draw parts of a UIView as it becomes visible inside UICollectionView?

查看:124
本文介绍了当UIView内部可见时,如何绘制UIView的各个部分?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Android上,水平滚动列表上的项目视图可能具有较大的宽度。当视图的一部分在列表中可见时,该视图将加载并绘制大块图像。这是一种优化措施,可以避免一次绘制所有图像,因为这样做既浪费又缓慢。绘制的内容本质上是音频波形。 按照需要的方式工作,我不能将大块作为列表中的单个视图项拆分。由于android绘图体系结构的工作原理,此策略非常理想。

On Android I have item views with potentially large widths on a horizontal scrolling list. The view loads and draws chunks "images" as parts of the view become visible on the list. This is an optimization to avoid drawing all images at once as it would be wasteful and slow. The content drawn is essentially an audio waveform. Do to the ways things need to work I can't split the chunks as individual view items on a list. This strategy works perfect because of how android drawing architecture works.

现在,我正在尝试在iOS中使用类似的模式,但遇到了一些麻烦,我不太确定如何提出解决方案。

Now I'm trying to use a similar pattern in iOS but I'm having some trouble and I'm not too sure how to come up with a solution.

在iOS中,我正在使用 UICollectionView 绘制宽单元格,我们需要对加载和绘制可见块进行相同的优化。

In iOS I'm are using a UICollectionView which draws large width Cells and we need that same optimization of loading and drawing only the visible chunks.

解决方案1:

检查<$ c $的哪些部分c> UIView 是可见的,并且仅绘制那些可见的块。该解决方案的问题在于,随着 UICollectionView 滚动, UIView 不会绘制下一个可见的卡盘。以下是我正在谈论的示例。

Solution 1:
Check what parts of the UIView is visible and draw only those visible chunks. The problem with this solution is that as the UICollectionView scrolls the UIView doesn't draw the next chucks that are becoming visible. Here are examples of what I'm talking about.

UIView 加载初始块

这些可以通过不同的块颜色看到:

UIView loads initial chunks
These can be seen by their different chunk colors:

滚动一点

显示黑色,没有内容加载,因为没有提示需要再次绘制视图的提示我们无法加载下一个可见的块。

Scroll a bit
Black is shown and no content is loaded because there is no hint that the view needs to draw again so we can't load the next visible chunk.

解决方案2:

使用由 CATiledLayer 支持的自定义 UIView 。这样做之所以完美,是因为它在滚动 UICollectionView 时绘制了可见的图块。

Solution 2:
Use custom UIView backed by a CATiledLayer. This works perfect because it draws the tiles as they become visible while scrolling the UICollectionView.

问题在于绘制如果定义了 shouldDrawOnMainThread ,则会在后台线程或下一个绘制周期发生。当 UIView 调整大小或我的内部缩放逻辑出现时,这会带来问题。事情发生了变化,因为绘图周期与视图调整大小不同步。

The problem is that drawing happens on the background thread or on the next drawing cycle if shouldDrawOnMainThread is defined. This brings issues when the UIView is resized or my internal zoom logic kicks. Things shift because the drawing cycle is not synchronized to the view resizing.

所以我怎么能得到像 CATiledLayer 零件已变得可见,我可以像 CALayer 支持的 UIView

So how could I get notified like CATiledLayer that a part is becoming visible and I could draw normally like a CALayer backed UIView?

更新1

使用 preferredLayoutAttributesFittingAttributes 作为检查是否需要绘制新块的方法。每当单元由于滚动而移动到新位置时,都会调用此方法。希望这不是一个坏主意。 :)

UPDATE 1
I'm looking into using preferredLayoutAttributesFittingAttributes as a way to check if a new chunk need to be drawn. This is called every time the cell is moved into a new position because of scrolling. Hopefully, this isn't a bad idea. :)

- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes






UPDATE 2

经过大量测试和测试。不能使用解决方案1。当 UIView 达到一个很大的宽度时,使用 CATiledLayer 时的内存使用量就减少了,我猜人们会期望的。 :/


UPDATE 2
After much testing and playing around. Using solution 1 is not an option. When a UIView reaches a huge width memory usage goes off the roof while using CATiledLayer memory usage is at minimal as I guess one would expect. :/

推荐答案

我不知道您是否可以完全关闭效果。您可以通过设置 fadeDuration 设置为0。为此,您必须创建 CATiledLayer 的子类并覆盖类方法 fadeDuration

I don't know if you can completely turn off the effect. You can soften it by setting the fadeDuration to 0. To do this, you must create a subclass of CATiledLayer and overwrite the class method fadeDuration.

您也可以尝试实现 shouldDrawOnMainThread 类方法,但这是私有方法,您可能会冒险在App Store上被拒绝:

You can also try to implement shouldDrawOnMainThread class method, but this is a private method, and you're risking a rejection on the App Store:

@implementation MyTiledLayer

+(CFTimeInterval)fadeDuration {
    return 0.0;
}

+ (BOOL)shouldDrawOnMainThread {
    return YES;
}

@end

或在Swift中:

class MyTiledLayer: CATiledLayer {
    override class func fadeDuration() -> CFTimeInterval {
        return 0.0
    }

    class func shouldDrawOnMainThread() -> Bool {
        return true;
    }
}

如果要实现自己的 tiled 层,您应该放弃这些图块,并尝试计算视图的可见部分(截面和缩放级别)。比起只能将这一部分作为图层的全部内容绘制。

If you want to implement your own tiled layer instead, you should waive of the tiles and try to compute the visible part (section and zoom level) of the view. Than you can draw only this part as layer whole content.

显然,滚动滚动视图时,没有简单的方法可以重新绘制视图。但是您可以实现 scrollViewDidScroll:,并手动触发重绘。 visibleRect 方法始终返回图层的完整区域,但是您可以使用

Apparently, there is no easy way to re-draw the view when the scrollview is scrolling. But you may implement scrollViewDidScroll:, and trigger the redrawing manually. The visibleRect method always returns the complete area of the layer, but you can use

CGRect theVisibleRect = CGRectIntersection(self.frame, self.superlayer.bounds);

或在Swift中

let theVisibleRect = frame.intersection(superlayer.bounds)

确定可见层的面积。

这篇关于当UIView内部可见时,如何绘制UIView的各个部分?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆