YuraImashev
@YuraImashev
Just a regular guy

Swift — Как оптимизировать «нарезку» изображения?

У меня есть UIScrollView. Я хочу сделать так, чтобы когда пользователь прокручивает его - на заднике прокручивалась картинка. Картинка генерируется программно и хранится в памяти. Её высота - высота экрана устройства, а ширина чуть больше. Но почему-то на моём iPhone 4S это приложение тормозит. Это кажется мне странным, учитывая, что в Галерее я могу увеличить любую фотографию и скроллинг будет идеально плавным. Очевидно, что я что-то сделал не так.

Вот, что я делаю, когда пользователь прокручивает ScrollView:

func scrollViewDidScroll(scrollview: UIScrollView) {
    // Вычисляем смещение картинки
    var pageSize: Float = Float(scrollView.bounds.size.width)
    var page: Float = floorf((Float(scrollview.contentOffset.x) - pageSize / 2.0) / pageSize) + 1

    if (page >= Float(levelPagesCount)) {
        page = Float(levelPagesCount) - 1;
    }
    else if (page < 0) {
        page = 0;
    }
    pageControl.currentPage = Int(page)

    var dx = scrollview.contentOffset.x

    // Когда знаем смещение - можем вырезать нужную часть изображения
    let queue = NSOperationQueue()
    var cgimg: CGImageRef?
    var drawn = false

    // Запускаем функцию вырезания в отдельном потоке
    queue.addOperationWithBlock() {
        if(!self.locked) {
            self.locked = true
            cgimg = self.imageClass!.getImage(dx)
            drawn = true
        }

        NSOperationQueue.mainQueue().addOperationWithBlock() {
            if(drawn) {
                // Помещаем результат в ImageView
                self.myImageView!.layer.contents = cgimg
                self.locked = false
            }
        }
    } 
}


А вот, как я "нарезаю" изображение:

public func getImage(xOffset: CGFloat) -> CGImage {
    // Здесь 'img' - та самая "широкая" картинка
    return CGImageCreateWithImageInRect(img, CGRectMake(xOffset, 0, imgWidth, imgHeight))!
}


Возможно я допустил ошибку, а возможно всё решение неверное в принципе.
  • Вопрос задан
  • 2612 просмотров
Пригласить эксперта
Ответы на вопрос 3
ManWithBear
@ManWithBear
Swift Adept, Prague
Операции с контекстами довольно затратные. Первое что приходит в голову, это
1) отрендерить картинку один раз максимального размера, и добавить её UIImageView в скрол прижав к границам.
2) если скорость скрола текста и картинки должны быть различными, то добавить ещё один ScrollView за текущий, с картинкой и ручками его двигать.

Просто забавный факт: пробовал открыть на iPad3 в галерее картинку 40к пикселей на 40к, скролл был совершенно не плавный :)
Ответ написан
Комментировать
Flanker_4
@Flanker_4
Вы делаете не то и не в том месте.
scrollViewDidScroll вызывается очень часто. При скролинге на 10 px он дернется 10 раз (ну почти, там своя специфика). А Вы еще и заливаете это соусом очередей, а уж если очередь асинхронная - то вообще шляпа , вы получите на те же 10 пикселей 10 операций генерации картинок

Вам нужно либо взять эту большую картинку, обернуть в UIImageView , и вставить в uiscrollview как subview. Картинки высотой до 2к без проблем будут скролится.
Если картинка ну чертовски большая, от 5к и больше - то тут нужно резать, но не так как Вы.
Делаете две UIImageView определенного размера (ну к примеру 1.5x-2x высоты экрана девайса) и вставляете как выше как сабвью, когда пользователь доскраливает до половины этой картинки (это отслеживаете в didScroll) запускаете генерацию следующей порции картинки, вставляете ее в uiimageview и пихаете под первую. Когда пользователь доскролит - картинка догенерируется и для пользователя это будет выглядить безшовно. Если пользователь начинает скролить дальше - выдираете первый imageView , перегенирируете ему изображение и вставляете ниже . Вообщем две плиточки перекладываете по ходу скрола пользователя.
Ответ написан
Комментировать
@Flie
Возможно я ошибаюсь, но вам стоит попробовать запустить тайм профайлинг и в нем посмотреть какая именно операция занимает максимальное время (учитывая что тормоза заметны, думаю что как раз самая долгая операция и будет их вызывать)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы