31 декабря 2010 г.

Конвертирование "человеческого" адреса в широту и долготу

Что б отобразить что-то на карте (MKMapView) нужно знать координаты (широту и долготу) точки в которой мы хотим отобразить элемент. У меня возникла ситуация когда в качестве координаты у меня есть только почтовый адрес. Сервисов преобразования почтового адреса в широту и долготу довольно много, я использовал "Yahoo! Maps Web Services - Geocoding API"

Функция конвертации выглядит так:
- (void) convertAddress:(NSString *) address
{
NSError *err = nil;
NSString *url = [NSString stringWithFormat:@"http://api.maps.yahoo.com/ajax/geocode?appid=onestep&qt=1&id=m&qs=%@",
[self convertChars:address]];
NSString *str = [NSString stringWithContentsOfURL:[NSURL URLWithString:url]
encoding:NSUTF8StringEncoding
error:&err];
NSLog(@"%@", str);
CGFloat lat = [[self getAttr:@"Lat" fromString:str] floatValue];
CGFloat lon = [[self getAttr:@"Lon" fromString:str] floatValue];
if (fabs(lat)>.0001 || fabs(lon)>.0001)
{
MKCoordinateRegion region;
region.center.latitude = lat;
region.center.longitude = lon;
region.span.latitudeDelta = 0.1;
region.span.longitudeDelta = 0.1;
[mapView setRegion:region];
}
}


Для начала конвертируем символы адреса, так как адрес передаем в GET запросе:

- (NSString *) convertChars:(NSString *) str
{
NSMutableString *rv = [str mutableCopy];
[rv replaceOccurrencesOfString:@" "
withString:@"+"
options:0
range:NSMakeRange(0, [rv length])];
[rv replaceOccurrencesOfString:@","
withString:@""
options:0
range:NSMakeRange(0, [rv length])];
[rv replaceOccurrencesOfString:@"."
withString:@""
options:0
range:NSMakeRange(0, [rv length])];
return [rv autorelease];
}


Результатом запроса будет javascript строка, и из нее выделяем долготу и широту:

- (NSString *) getAttr:(NSString *) attr fromString:(NSString *) str
{
NSString *rv = nil;
NSRange rng = [str rangeOfString:[NSString stringWithFormat:@"\"%@\":", attr]];
if (rng.location != NSNotFound)
{
rng.location = rng.location +rng.length;
rng.length = 0;
unichar ch = [str characterAtIndex:rng.location+rng.length];
while ((rng.location+rng.length)<[str length] && (ch!=',' && ch!='}'))
{
rng.length++;
ch = [str characterAtIndex:rng.location+rng.length];
}
rv = [str substringWithRange:rng];
}
return rv;
}


В качестве примера обновил проект на github

Так же смотрите:
- MapKit в iOS

16 декабря 2010 г.

Градиент на UINavigationBar

Так уж захотелось заказчику, что б на фон компоненты UINavigationBar плавно перетекал из одного цвета в другой. Решение было найдено довольно быстро.

Будем модифицировать метод drawRect: компоненты UINavigationBar

  1. - (void) drawRect:(CGRect) rect
  2. {
  3. // подготовка контекста для рисования
  4. CGContextRef context = UIGraphicsGetCurrentContext();
  5. CGFloat locations[2] = { 0.0, 1.0 };
  6. CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();
  7. // создаем и рисуем градиент
  8. CGFloat components[8] = COLOR_COMPONENTS;
  9. CGGradientRef gradient = CGGradientCreateWithColorComponents(myColorspace, components, locations, 2);
  10. CGContextDrawLinearGradient(context, gradient, CGPointMake(0, 0), CGPointMake(0,self.frame.size.height), 0);
  11. CGGradientRelease(gradient);
  12. CGColorSpaceRelease(myColorspace);
  13. // верхнюю линию компоненты делаем белой
  14. CGContextSetRGBStrokeColor(context, 1, 1, 1, 1.0);
  15. CGContextMoveToPoint(context, 0, 0);
  16. CGContextAddLineToPoint(context, self.frame.size.width, 0);
  17. CGContextStrokePath(context);
  18. // нижнюю линию закрашиваем черным цветом
  19. CGContextSetRGBStrokeColor(context, 0, 0, 0, 1.0);
  20. CGContextMoveToPoint(context, 0, self.frame.size.height);
  21. CGContextAddLineToPoint(context, self.frame.size.width, self.frame.size.height);
  22. CGContextStrokePath(context);
  23. }


Пример можно скачать с github

11 декабря 2010 г.

Шрифты в iOS

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

Пример можно скачать.

Работает все просто. У класса UIFont есть методы familyNames: и fontNamesForFamilyName:. Первый возвращает массив имен семейств шрифтов в системе, а второй массив имен шрифтов по семейству шрифта.

6 декабря 2010 г.

SVN добавление файла в репозиторий с "@" в имени

Столкнулся с проблемой добавления файла в svn репозиторий:

  1. $ svn add ./file\@2x.png
  2. svn: warning: 'file' not found


решается просто, нужно добавить как завершающий символ в названии файла "@":

  1. $ svn add ./file\@2x.png@
  2. A (bin) file@2x.png

2 декабря 2010 г.

Поддержка Retina-display в приложении

С выходом iPhone 4 программистам нужно в своих программах добавлять поддержку нового разрешения экрана Retina. Для поддержки этого разрешения в вашем приложении необходимо выполнить следующие условия:

- Перерисовать все изображения которые вы используете в качестве ресурсов
- Добавить иконку приложения в высоком разрешении
- Если вы используете векторную графику фраемворков Core Graphics или UIKit, то можете улучшить детализацию, смотри “Updating Your Custom Drawing Code
- Если вы используете Core Animation, то возможно вам понадобится изменить параметры маштабирования перед отрисовкой слоев “Accounting for Scale Factors in Core Animation Layers.
- Если вы используете Open GL ES для рисования, то для отрисовки в высоком разрешении вам понадобится маштабирование вашего слоя, как описано в “Drawing High-Resolution Content Using OpenGL ES.
- Если вы создаете изображения программно, то понадобится изменить код создания изображения, как описано в “Creating High-Resolution Bitmap Images Programmatically.”

Для начала опишу первые два способа.

Допустим у вас уже есть изображения оптимизированные под стандартное разрешение и под retina-display. Как же нам из программы узнать какое изображение загрузить? Ответ прост: программисту можно не знать на каком устройстве запущенно приложение. iOS может может сама выбрать нужное изображение в зависимости от устройства, на котором запущенна программа. Изображение только нужно назвать в соответствии с форматом:

- для стандартного резрешения iPhone/iPod Touch файл ресурса изображения должен иметь вид: <ImageName><device_modifier>.<filename_extension>
- для высокого (retina) разрешения: <ImageName>@2x<device_modifier>.<filename_extension>

где, ImageName - имя изображения, filename_extension - расширение, device_modifier - необязательный параметр, который указывает тип устройства для которого сделан ресурс (может быть "~iphone" и "~ipad").

Так например, если у вас ресурс для стандартного разрешения iPhone называется "image.png", то для iPhone 4 должен быть ресурс под названием "image@2x.png", если iOS его не находит, то берется ресурс для стандартного разрешения ("image.png").

так, читаем ресурс:

  1. UIImage* anImage = [UIImage imageNamed:@"image.png"];


кстати, с прошивки iOS 4.0, расширение ресурса (".png") можно не указывать, но я советую оставлять для совместимости с iPhoneOS 3.x.


Теперь о иконках приложения

С версии iOS 3.2 в файле Info.plist приложения появилась возможность задавать массив файлов иконок приложения в параметре CFBundleIconFiles (не путайте с CFBundleIconFile). В этом массиве можно перечислить список файлов иконок с разным разрешением, и система сама подберет оптимальную иконку для устройства на котором запущено приложение.

Список разрешений иконок приложения:
57х57 иконка для iPhone и iPod Touch стандартного разрешения экрана
114х114 (@2x)иконка для iPhone и iPod Touch с retina экраном
72х72iPad иконка
29х29иконка для iPhone и iPod Touch стандартного разрешения экрана, которая отображается в приложении Settings и при поиске
58х58 (@2x)иконка для iPhone и iPod Touch с retina экраном, которая отображается в приложении Settings и при поиске
50х50iPad иконка приложения в результатах поиска


По материалам "Supporting High-Resolution Screens"