Tankz Go! Go! Rescue Squad - бравые ребята!
Июн 01

В приложении, над которым я сейчас работаю, есть небольшая панель с дополнительной информацией мелким шрифтом поверх изображения. Внедрена она, само собой, как объект “IView“, вложенный в качестве подпредставления subview во второй “UIView“. Код загружает интерфейс панели из отдельного xib-файла, размещая его в основном представлении:

1
2
3
4
5
6
NSArray *nibContent = [[NSBundle mainBundle] loadNibNamed:@"Box"
owner:self options:NULL];
UIView* overlayBox1 = [nibContent objectAtIndex:0];
[worksheet addSubview:overlayBox1];
overlayBox1.center = worksheet.center;
overlayBox1.frame = CGRectOffset(overlayBox1.frame, 0, -140);

Однако результат получается не совсем адекватным — налицо сильная размытость. В редакторе IB и симуляторе ее не видно, а в iPhone панель выглядит просто ужасно (см. фото). Многочасовые эксперименты с настройками и цветами шрифтов ничего не дали — как оказалось, сглаживание текста тут не причем. Уже догадались, в чем проблема? Порой такие моменты сложно осознать, пока не столкнешься с ними сам…

blurryview1

Все дело в специфике технологии Core Graphics и экранных координатах, которые в данном случае являются числами не целыми, а с плавающей точкой. Core Graphics позволяет использовать в представлениях масштабируемую графику (с размером, отличным от 100%). Технология самостоятельно подгоняет изображения по размеру и обеспечивает размещение представлений с точностью менее пикселя — выполняя рендеринг “между” пикселями с аналогом сглаживающего эффекта. Возможно это благодаря тому, что координаты представления указаны в “CGRect“, работающей с “CGPoint“, где x и y — числа с плавающей запятой, а не целые значения.

Проблема возникает, если для прорисовки представления нужен 100% масштаб с точными пикселями. В представленном фрагменте кода позиция subview с именем “overlayBox1” определяется по его центру. “Center” — стандартный метод, внедренный как свойство и в действительности указывающий источник фрейма. При изменении размеров поля относительно исходного центра ровное количество пикселей (174 x 82) превращается в дробное (73.5, 69.5). Соответственно, Core Graphics выполняет визуализацию для половины пикселя. Но поскольку представление воспроизводится с масштабом 100%, каждый пиксель представления на экране соответствует полупикселю. В результате пиксель распределяется по четырем соседним, давая значительную размытость.

Это легко исправить, выровняв представление по целым пикселям:

1
2
3
4
5
overlayBox2.center = worksheet.center;
CGRect overlay2Frame = overlayBox2.frame;
overlay2Frame.origin.x = round(overlay2Frame.origin.x);
overlay2Frame.origin.y = round(overlay2Frame.origin.y);
overlayBox2.frame = overlay2Frame;

Желающие поэкспериментировать с кодом могут загрузить пример целиком [здесь].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#import "BlurryViewViewController.h"

@implementation BlurryViewViewController

// Намеченный инициализатор. Отменить для требуемой настройки перед загрузкой представления.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Пользовательская инициализация
}
return self;
}

// Внедряем viewDidLoad для дополнительной настройки после загрузки представления, обычно из nib-файла.
- (void)viewDidLoad {
[super viewDidLoad];

NSArray *nibContent = [[NSBundle mainBundle] loadNibNamed:@"Box" owner:self options:NULL];
UIView* overlayBox1 = [nibContent objectAtIndex:0];
[worksheet addSubview:overlayBox1];
overlayBox1.center = worksheet.center; //WARNING! blur ahead.
overlayBox1.frame = CGRectOffset(overlayBox1.frame, 0, -140);

nibContent = [[NSBundle mainBundle] loadNibNamed:@"Box" owner:self options:NULL];
UIView* overlayBox2 = [nibContent objectAtIndex:0];
[worksheet addSubview:overlayBox2];
overlayBox2.center = worksheet.center;
CGRect overlay2Frame = overlayBox2.frame;
overlay2Frame.origin.x = round(overlay2Frame.origin.x);
overlay2Frame.origin.y = round(overlay2Frame.origin.y);
overlayBox2.frame = overlay2Frame;

NSLog(@"Worksheet1 origin: %f,%f",overlayBox1.frame.origin.x,overlayBox1.frame.origin.y);
}

- (void)didReceiveMemoryWarning {
// Освобождаем представление, если у него нет superview.
[super didReceiveMemoryWarning];

// Освобождаем незадействованные данные из кэша, включая изображения.
}

- (void)viewDidUnload {
// Освобождаем все оставшиеся subview для основного представления.
// например, self.myOutlet = nil;
}

- (void)dealloc {
[super dealloc];
}

@end

На этом все. Успехов :)

Исходный код скачать можно [здесь]

Текст оригинальной статьи на английском языке [здесь]

Уважаемые читатели, данный материал был переведен и подготовлен к публикации проектом LookApp.ru, при публикации на другом сайте ссылка на LookApp.ru обязательна.

1 звезда2 звезд3 звезд4 звезд5 звезд (1 голосов, средний: 5.00 из 5)
Загрузка ... Загрузка ...


Оставьте комментарий