Нарисуйте сетку изображений, используя Core Graphics в drawRect: - PullRequest
5 голосов
/ 18 апреля 2009

Моя проблема заключается в следующем: у меня есть простое изображение блока, из которого я хочу сделать сетку. Я создал массив CGPoints в моем UIView. Тогда я использовал

blackImage = [UIImage imageNamed:@"black.png"];

, а затем

- (void)drawRect:(CGRect)rect {
    for (int j = 0 ; j <= 11; j++)
    {
        for (int i = 0 ; i <= 7; i++) 
        {
            [blackImage drawAtPoint: (CGPointFromString([[self.points objectAtIndex:j] objectAtIndex:i]))];
        }
    }
    [whiteImage drawAtPoint:(CGPointMake((CGFloat)(floor((touchX+0.001)/40)*40), (CGFloat)(floor((touchY+0.001)/40))*40))];

    //  [whiteImage drawAtPoint:(CGPointMake(240.0, 320.0))];   
}

Где TouchX и TouchY - это CGPoints, когда пользователь коснулся экрана. Поэтому я в основном показываю другое изображение в той точке сетки, к которой прикоснулся пользователь.

Прежде всего, проблема в том, что весь экран перерисовывается каждый раз, когда я вызываю DrawRect. Я хочу иметь возможность сохранить состояние (путем изменения массива BOOL?), Чтобы пользователь перетаскивал экран и менял несколько изображений. Однако я не могу использовать метод drawAtPoint в UImage, когда я нахожусь вне DrawRect. (выдает ошибку).

Во всяком случае, я начал изучать документы CoreAnimation и Quartz, и меня это сильно смутило. Я не уверен, нужно ли мне создавать несколько UIViews для каждого кирпича (кажется чрезмерным) или сетку CALayers или CGLayers ... Я думаю, что это довольно просто, что я хочу сделать ... но я не совсем понимаю Слои и разница между использованием CALayer и CGLayer. По-видимому, «Все UIViews защищены слоем» Что это значит?

Я немного растерялся, как это реализовать. В основном я хочу поменять изображения в сетке, чтобы пользователь мог «рисовать» по экрану и переключать изображения.


Редактировать

Я пытался реализовать это, используя [self setNeedsDisplayinRect] и передавая CGRect, который находится под пальцем пользователя. Тем не менее, это все еще вызывает DrawRect в TouchesMoved, что дает мне эффект, который я хочу, но слишком медленный на iPhone. Есть ли более эффективный способ добиться того же эффекта, используя CALayers? Я новичок в Core Animation и не очень понимаю, как использовать слой для решения этой проблемы.

Ответы [ 3 ]

2 голосов
/ 18 апреля 2009

Я думаю, что в вашем случае UIImage должен справиться с этим приложением и дать хорошую производительность. Проблема заключается в том, что вы заставляете весь экран перерисовываться в ответ на каждое сообщение drawRect:. Прямоугольник, который передается, указывает «грязную область», которую нужно перерисовать. Любой другой рисунок - просто трата времени.

Точно так же прямоугольник, который вы передаете в setNeedsDisplay: вашего представления, является прямоугольником, который вы специально хотите аннулировать. Вычислите прямоугольник вокруг касания и обесцените это. UIKit (потенциально) объединит несколько грязных каналов и отправит один drawRect:.

Я бы посоветовал вам выполнить следующие оптимизации:

  1. проверьте грязный прямоугольник, переданный вашему drawRect: (в отладчике), и если он меньше, чем полноэкранный код записи, чтобы убедиться, что вы перерисовываете только изображения в грязном прямоугольнике
  2. Используйте событие touch, чтобы удостовериться, что вы сделали недействительными только те области, которые необходимо перерисовать, а затем вернитесь к 1.
  3. Если это не дает нужной вам производительности, используйте Кварц для рисования черно-белых контуров, а не используйте изображения, если это какая-то странность UIImage (но я сомневаюсь, что это так)

Если вам нужно отобразить растровые изображения, а 1 и 2 не дают нужной вам производительности, вам придется прибегнуть к технологии более низкого уровня. Есть много примеров, включая этот вопрос на SO.

1 голос
/ 19 апреля 2009

77 дискретных изображений не слишком обременительно, чтобы делать их в виде сетки CALayers или UIViews (при условии, что ваши изображения имеют ширину всего несколько пикселей), поэтому я рекомендую такой подход. UIViews не намного тяжелее, чем CALayers, поэтому я хотел бы создать сетку из отдельных UIImageViews (предполагая, что ваше черное изображение - это больше, чем просто черный цвет, если вы не можете просто установить стандартный backgroundColor UIView на черный или белый). Если вам не нужно было отслеживать прикосновения при их перемещении по видам, вы даже можете выполнить обработку касаний для переключения изображения вида в пользовательском подклассе UIImageView или с помощью методов делегирования в вашем контроллере.

Таким образом, единственная часть отображения, которая будет повторно отображаться, будет определенными UIViews, которые изменяются. Я рекомендую UIViews над CALayers просто потому, что UIViews немного легче разместить в иерархии представлений.

Чтобы получить четкое объяснение того, как CALayers, UIViews и тому подобное взаимодействуют на iPhone, я бы рекомендовал прочитать подраздел «Архитектура визуализации представлений» в разделе «Просмотр архитектуры и геометрии» в «Руководстве по программированию приложений iPhone». ».

1 голос
/ 18 апреля 2009

Чтобы сделать недействительной только часть вашего просмотра, позвоните setNeedsDisplayInRect: только с той областью, которая изменилась. Если изменилось несколько ректов, вы можете позвонить дважды с разными ректами.

Другой метод решения этой проблемы - создать несколько CALayer s и переместить / скрыть их.

Кроме того, вы никогда не должны звонить drawRect: напрямую, вместо этого используйте setNeedsDisplay. drawRect: будет вызываться UIKit всякий раз, когда область представления недействительна и требует рисования.

...