|
Июн
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 панель выглядит просто ужасно (см. фото). Многочасовые эксперименты с настройками и цветами шрифтов ничего не дали — как оказалось, сглаживание текста тут не причем. Уже догадались, в чем проблема? Порой такие моменты сложно осознать, пока не столкнешься с ними сам…

Все дело в специфике технологии 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 |
На этом все. Успехов


Последние комментарии
Подскажите пожалуйста… Вот...
Код не открывает страницы по простой причине -...