Как нарисовать части UIView, как он становится видимым внутри UICollectionView?

На Android у меня есть представления элементов с потенциально большой шириной в горизонтальном списке прокрутки. Представление загружает и рисует фрагменты "изображения", когда части представления становятся видимыми в списке. Это оптимизация, позволяющая избежать рисования всех изображений одновременно, поскольку это будет расточительным и медленным. Нарисованный контент по сути является звуковой формой волны. Делать так, как нужно, чтобы все работало. Я не могу разделить фрагменты как отдельные элементы в списке. Эта стратегия прекрасно работает из-за того, как работает архитектура рисования Android.

Сейчас я пытаюсь использовать подобный шаблон в iOS, но у меня возникли некоторые проблемы, и я не слишком уверен, как найти решение.

В iOS я использую UICollectionView который рисует ячейки большой ширины, и нам нужна та же оптимизация загрузки и рисование только видимых фрагментов.


Решение 1:
Проверьте, какие части UIView виден и рисует только те видимые куски. Проблема с этим решением заключается в том, что в качестве UICollectionView прокручивает UIView не рисует следующие патроны, которые становятся видимыми. Вот примеры того, о чем я говорю.

UIViewзагружает начальные куски
Их можно увидеть по разным цветам: введите описание изображения здесь

Прокрутите немного
Показывается черный цвет, и содержимое не загружается, потому что нет никаких намеков на то, что представление должно быть прорисовано снова, поэтому мы не можем загрузить следующий видимый фрагмент. введите описание изображения здесь


Решение 2:
Использовать пользовательские UIView при поддержке CATiledLayer, Это прекрасно работает, потому что рисует плитки, когда они становятся видимыми при прокрутке UICollectionView,

Проблема в том, что рисование происходит в фоновом потоке или в следующем цикле рисования, если shouldDrawOnMainThread определено. Это вызывает проблемы, когда UIView изменен размер или моя внутренняя логика увеличения Все меняется, потому что цикл рисования не синхронизирован с изменением размера вида.


Так как я мог получить уведомление, как CATiledLayer что часть становится видимой, и я мог бы рисовать нормально, как CALayer со спинкой UIView?


ОБНОВЛЕНИЕ 1
Я смотрю на использование preferredLayoutAttributesFittingAttributes как способ проверить, нужно ли рисовать новый кусок. Это вызывается каждый раз, когда ячейка перемещается в новую позицию из-за прокрутки. Надеюсь, это неплохая идея.:)

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

ОБНОВЛЕНИЕ 2
После долгих испытаний и тренировок. Использование решения 1 не вариант. Когда UIView достигает огромной ширины памяти использование уходит с крыши при использовании CATiledLayer использование памяти минимально, как я и ожидал.:/

1 ответ

Я не знаю, сможете ли вы полностью отключить эффект. Вы можете смягчить его, установив fadeDuration до 0. Для этого необходимо создать подкласс CATiledLayer и переписать метод класса fadeDuration,

Вы также можете попробовать реализовать shouldDrawOnMainThread метод класса, но это частный метод, и вы рискуете получить отказ в 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;
    }
}

Если вы хотите реализовать собственный плиточный слой, вам следует отказаться от плиток и попытаться вычислить видимую часть (сечение и уровень масштабирования) вида. Чем вы можете нарисовать только эту часть как весь слой слоя.

Очевидно, что при прокрутке прокрутки нет простого способа перерисовать представление. Но вы можете реализовать scrollViewDidScroll: и вызвать перерисовку вручную. visibleRect Метод всегда возвращает всю площадь слоя, но вы можете использовать

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

или в Свифте

let theVisibleRect = frame.intersection(superlayer.bounds)

определить видимую область слоя.

Другие вопросы по тегам