пятница, 18 сентября 2009 г.

Остановить ScrollWiew

Содержимое UIscrollView может двигаться по инерции, если его резко "запустить" пальцем. Но что, если это движение надо резко остановить? Делается это так:

[scrollView scrollRectToVisible:CGRectMake(scrollView.contentOffset.x, scrollView.contentOffset.y + 0.01, scrollView.frame.size.width, scrollView.frame.size.height) animated:NO];

Все 

пятница, 28 августа 2009 г.

Контроль ввода текста с клавиатуры

Довольно часто нужно знать и контролировать те данные, что пользователь вводит в текстовые поля. Причем контролировать непосредственно в процессе ввода. Это вполне возможно. 

И UITextView и UITextField шлют системе уведомления о изменении своего состояния (UITextViewTextDidChangeNotification и UITextFieldTextDidChangeNotification ). Шлют они их, используя NSNotificationCenter.  Все что нам нужно, это слушать этот NotificationCenter и реагировать на нужные нам уведомления. 

Пара слов о работе с NSNotificationCenter
NSNotificationCenter *notCenter = [NSNotificationCenter defaultCenter];  
Это ссылка на NotificationCenter, через который по умолчанию ходят все системные сообщения (в том числе и нужные нам)  

[[NSNotificationCenter defaultCenter]postNotificationName: @"NAME_OF_NOTIFICATION" object: self];  
Так можно отправлять уведомления. Как видно, уведомление имеет имя и ссылку на объект (обычно это объект отправивший уведомлене). То есть мы можем видеть кто и какое уведомление отправил. В нашем случае мы будем только ловить уведомления, отправленные текстовыми полями

[[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(meth:) name:@"UITextViewTextDidChangeNotification" object: nil];
Регистрируем слушателя уведомлений. Рассмотрим все 4 параметра 
addObserver: Объект, который будет реагировать на уведомления
selector:  селектор (метод) объекта, который будет вызван при приходе уведомления
name: строка-имя уведомления, которое мы ждем
object: объект, уведомления от которого мы ждем. Если nil, то принимаем уведомления от любого объекта.

- (void)meth:(NSNotification*)notification;
Так выглядит метод(selector:), который будет вызван при приходе уведомления

Ну и наконец-то возвращаемся к теме статьи. Небольшой пример. Класс, который будет менять буквы, вводимые в любом текстовом поле приложения на ПРОПИСНЫЕ

-(id) init {
   if(self = [super init]) {
       [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(capitalizeText:)              name:@"UITextFieldTextDidChangeNotification" object:nil];
  [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(capitalizeText:) name:@"UITextViewTextDidChangeNotification" object:nil];
 }
 return self;
}

-(void) capitalizeText: (NSNotification*)notification{ 
 [[NSNotificationCenter defaultCenter]removeObserver: self name: [notification name] object: nil];
 UIView *textItem = [notification object]; // textField or textView
 NSString *text = [textItem text];
 text = [text uppercaseString];
 [textItem setText: text];
 [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(capitalizeText:) name:[notification name] object:nil];
}


- (void) dealloc
{
 [[NSNotificationCenter defaultCenter]removeObserver: self name: @"UITextFieldTextDidChangeNotification" object: nil];
 [[NSNotificationCenter defaultCenter]removeObserver: self name: @"UITextViewTextDidChangeNotification" object: nil];
 [super dealloc];
}


Обратите внимание на то, что уведомление  xxxTextDidChangeNotification будет слаться и при программном изменении текста в текстовом поле. поэтому мы в методе capitalizeText: временно отключаам наблюдение.

Все. Будут вопросы-предложения-комментарии - пишите ))


четверг, 13 августа 2009 г.

CGPoint, CGRect, CGSize переводим в NSString

Очень часто (особенно при отладке) необходимо выводить в консоль CGPoint, CGRect и CGSize. Чтоб не писать громоздкие конструкции, воспользуйтесь функциями

NSStringFromCGPoint(CGPoint point);

NSStringFromCGRect(CGRect rect);

NSStringFromCGSize(CGSize size);

CGRect rect = CGRectMake(1, 2, 3, 4);
 NSString *s = NSStringFromCGRect(rect);
 NSLog(s);


Так же есть и обратные функции CGPointFromString, CGRectFromString, и CGSizeFromString

пятница, 10 июля 2009 г.

Cоздание UIView cпомощью Interface Builder

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

1. Создаем в проекте класс - наследник UIView (например myView)

2. Создаем в IB вью, кладем на него все что пожелаем и в инспекторе на последней закладке указываем имя нашего класса (myView)

3. Сохраняем и подключаем к проекту (например с именем myViev.xib)

4. Теперь чтобы в проекте вызвать созданый вью пишем:

 myView *view = [[[NSBundle mainBundle] loadNibNamed:@"myViev" owner: self options:nil] objectAtIndex:0];

Все можно пользоваться этим вью как угодно )))

вторник, 23 июня 2009 г.

вторник, 9 июня 2009 г.

Дебаг

Выводим имя файла, номер строки, имя класса и метода в консоль

NSLog(@"%s === %d === %s", __FILE__, __LINE__, __PRETTY_FUNCTION__, __FUNCTION__);

четверг, 14 мая 2009 г.

Иконка приложения

Каждое приложение имеет свою иконку на рабочем столе iPhon-a

Чтобы установить эту картинку, надо в файле info.plist прописать имя картинки для параметра Icon file

Чтобы убрать с иконки уродливую полукруглую тень, надо в  файле info.plist добавить параметр UIPrerenderedIcon типа boolean и установить его значение в YES 

вторник, 12 мая 2009 г.

Всплывающая подсказка в UIWebView

Если задержать палец на гиперссылке в UIWebView, то через пару секунд вылезет окошко с предложением скопировать ссылку или перейти по ней (OS 3.0 и выше). Чтобы запретить это окошко выполняем следующий javaScript

NSString *jsString =@"document.documentElement.style.webkitTouchCallout=\"none\"";
 [webView stringByEvaluatingJavaScriptFromString: jsString];


Выполнять конечно надо после того, как webView закончит загрузку

четверг, 7 мая 2009 г.

Сохранение данных

Если нужно сохранить небольшое количество данных, и прочитать их при следующем запуске приложения, то на помощь приходит класс NSUserDefaults 

Сохранение данных:

NSString* str = @"StringToSave";
NSArray *arr = [[NSArray alloc]initWithObjects: @"array", @"to", @"save",nil];
[[NSUserDefaults standardUserDefaults] setObject: str forKey:@"stringSetting"];
[[NSUserDefaults standardUserDefaults] setObject: arr forKey:@"this_is_array"];
[[NSUserDefaults standardUserDefaults] synchronize];

Чтение данных:

NSString* str = [[NSUserDefaults standardUserDefaults] objectForKey:@"stringSetting"];
 NSArray *a = [[NSUserDefaults standardUserDefaults] objectForKey:@"this_is_array"];

Сохранять данные лучше всего при выходе из приложения - в методе - (void)applicationWillTerminate:(UIApplication *)application вашего делегата UIApplicationDelegate


среда, 6 мая 2009 г.

Полезные мелочи. Как создать анимированую картинку

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

Добавляем эти файлы в проект и делаем из них анимированое изображение:

NSArray *imagesList = [NSArray arrayWithObjects:
 [UIImage imageNamed:@"image1.png"],
 [UIImage imageNamed:@"image2.png"],
 [UIImage imageNamed:@"image3.png"],
 [UIImage imageNamed:@"image4.gif"],
 nil];
UIImageView *animatedView = [[UIImageView alloc]initWithFrame: [self frame]];
animatedView.animationImages = imagesList;
animatedView.animationDuration = 0.25; // seconds
animatedView.animationRepeatCount = 0; // 0 =  forever
[animatedView startAnimating];
[self addSubview:animatedView];
[animatedView release];  

вторник, 5 мая 2009 г.

Скроллинг в UIWebView

Если нужно получить текущее положение скролла в UIWebView, либо устоновить скролл в заданную позицию, то есть 2 пути - Использовать java script или недокументированые методы. Как правило использование законных путей лучше. Поэтому о них и поговорим

Получить текущее положение скролла (вертикальное)

int scrollPosition = [[webView stringByEvaluatingJavaScriptFromString:@"window.pageYOffset"] intValue];

Установить вертикальное положение скролла

int yOffset = 123;
NSString *jsString = [NSString stringWithFormat: @"window.scrollTo(0, %d) ", yOffset];
[_webView stringByEvaluatingJavaScriptFromString: jsString];  



Меняем размер шрифта в UIWebView

Для того, чтобы во время работы уменьшить/увеличить размер шрифта в UIWebView, воспользуемся архиполезной возможностью этого элемента, выполнять java script

 int fontScale = 150;
 NSString *jsString = [NSString stringWithFormat: @"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%d%%'",  fontScale];
  [_webView stringByEvaluatingJavaScriptFromString: jsString];

 

Конечно делать это нужно только после того, как UIWebView  закончит загрузку своего содержимого


 

Ссылки в UIWebView

Иногда надо контролировать клики пользователя по гиперссылкам в UIWebView для этого необходимо назначить для webView делегата и переопределить в нем метод - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType

Приведенный ниже код контролирует клики на линки и не дает пользователю переходить по ссылкам, заканчивающимся на ".com"

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType

     if(navigationType == UIWebViewNavigationTypeLinkClicked)
     {
        NSString *fullLink = request.URL.path;
        if([fullLink hasSuffix:@".com"])
            {return NO;}
     } 
 return YES;
}
 


Картинки в UIWebView

Иногда нужно создать свой форматированый HTML текст и вывести его на экран. Для этого используется элемент UIWebView Если же в этом  тексте должны быть картинки, то

1. Добавляем файлы с картинками в проект

2. В HTML пишем просто  

3. В коде пишем 

NSString *htmlString = @"Html with image ";
NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath: path];
[webView loadHTMLString: htmlString baseURL: baseURL];



Полезные мелочи. Запуск приложения в Landscape mode

Если Вам нужно, чтобы Ваше приложение запускалось сразу в landscape mode (горизонтально), то Вам необходимо в info.plist добавить ключ UIInterfaceOrientation  и установить его значение равным UIInterfaceOrientationLandscapeRight

понедельник, 4 мая 2009 г.

Полезные мелочи. Как сделать скриншот в iPhone

Этот код делает "фотографию экрана и помещает ее в галлерею iPhone

CGRect rect = [[UIScreen mainScreen] bounds];
UIGraphicsBeginImageContext(rect.size);
[currentViewController.view.layer renderInContext:UIGraphicsGetCurrentContext()]; 
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil);



четверг, 30 апреля 2009 г.

Полезные мелочи. Генератор случайных чисел

Иногда нужно получить случайное число. Для этого в objective-C есть 2 функции rand() и random() Однако они каждый раз при запуске будут выдавать одну и ту же последовательность псевдо-случайных чисел.

Поэтому если нужна действительно случайная последовательность, то можно привязываться к текущей дате

Этот код выдаёт случайное число в диапазоне (startVal : endVal) - не включая endVal.

srandom((unsigned)(mach_absolute_time() & 0xFFFFFFFF));
int randomValue = startVal+ (random() % (endVal - startVal));

 

среда, 29 апреля 2009 г.

Работа со свойствами (property) c помощью KVM

Как вам наверняка известно, Objective-C позволяет быстро создавать сеттеры и геттеры с помощью директив @property и @synthesize

Однако главное на мой взгляд достоинство этих @property в возможностях, представляемых механизмом Key-Value-Mechanisms Об этих возможностях чуть поподробнее:

Имеем класс

@interface ClassWithProperties
...
@property int integerProperty;
@property id idProperty;
@property NSString *strProperty;

 

1. Доступ к свойствам по их имени во время выполнения программы. Имя свойства может быть неизвестно на этапе компиляции и вычисляться только после старта. Обратите внимание, что метод работает только с наследниками NSObject И поэтому примитивные типы должны быть преобразованы в NSValue и NSNumber Обратное преобразование механизм property делает сам автоматически

ClassWithProperties *cl;
 [cl setValue: [NSNumber numberWithInt: 10] forKey: @"integerProperty"];
 [cl setValue: self forKey: @"idProperty"];
 [cl setValue: @"just a string" forKey: @"strProperty"];
 ......
 int i = [[cl valueForKey: @"integerProperty"] intValue];
 NSString *s = [cl valueForKey: @"strProperty"];

2. Иногда  возникает необходимость формировать свойства на этапе выполнения. Чтоб пользователь мог обратиться к 

[cl setValue: @"someValue" forKey: @"AnyNameAsYouWant"]; и  [cl valueForKey: @"AnyNameAsYouWant"];

даже если на этапе компиляции это имя "AnyNameAsYouWant" неизвестно.  Тут на помощь приходят методы NSObject(void)setValue:(id)value forUndefinedKey:(NSString *)key и  (id)valueForUndefinedKey:(NSString *)key переопределив эти методы мы получим возможность сохранять и полученные значения например в NSMutableDictionary.

3. Получение имен всех свойств. Если мы хотим получить значения всех  property класса (например чтобы их сохранить при выходе), то нам нужно сперва получить все имена, а потом через valueForKey можно будет вытащить и значения. Имена всех свойств класса получаются так:

 #import "objc/runtime.h" ........................
 unsigned int outCount;
 objc_property_t *properties = class_copyPropertyList([AnyClassThatYouWant class], &outCount);
 for(int i = 0; i < outCount; i++)
 {
     objc_property_t property = properties[i];
     const char *propName = property_getName(property);
     if(propName)
     {
        NSString *name = [NSString stringWithUTF8String:propName];
       NSLog(name);  
     }
 }
free(properties);



Внимание! подобным образом нельзя получить свойства, которые были объявлены в суперклассе. Если Вам нужны действительно ВСЕ свойства, то есть [NSobject superclass];

метод с переменным числом аргументов

Иногда необходимо создать метод, который будет принимать неизвестное число однотипных аргументов (Как например [NSString stringWithFormat]). 

Сделать это несложно.

Объявление метода:

-(void) multiArgsMeth: (int)agr0, ...;

Реализация метода:

-(void) multiArgsMeth: (id)agr0, ...{

va_list argumentList;
 va_start(argumentList, arg0); // Start scanning for arguments after firstObject.
 while (parType = va_arg(argumentList, id)) // As many times as we can get an argument of type "id"
 {
 //DO what yo want
 } 
  va_end(argumentList);
}

Вызов метода (не забудьте про nil в конце):

[self multiArgsMeth : myArg0 , myArg1, myArg2 , nil];

вторник, 28 апреля 2009 г.

Полезные мелочи. Работа со строками

Для того, чтобы увидеть логи, необходимо выбрать Run => Console в Xcode.

NSLog(@"log: %@ ", stringValue);
NSLog(@"log: %f ", floatValue);  
NSLog(@"log: %d ", intValue);
 

Работа NSLog() очень похожа на С-шный printf()

----------------------------------------------------------------------------------
Конвертация NSInteger в NSString
NSString *str = [NSString stringWithFormat @"%d", integerValue];

Конвертация NSString в NSInteger
NSInteger intVal = [str integerValue];

----------------------------------------------------------------------------------------------------------------------



Полезные iPhone ссылки

Итак. Программы для iPhone пишутся на языке objective-C.

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

Русскоязычных материалов для разработчика iPhone приложений не очень много.

1. Для начинающих iPhone разработчиков есть очень неплохая статья на Wikipedia

2. Пожалуй лучший русскоязычный ресурс для начинающих Pyobjc.ru Тут же есть и вяло шевелящийся форум

3. Довольно оживленный форум, где собираются русскоязычные Objective-C программисты на Iphones.ru Единственный известный мне ресурс, который хоть как-то обновляется

4. Еще один довольно интересный блог

5.  Еще одна интересная статья

6. Да пожалуй и нет шестого пункта.... Все остальное либо совсем мертвое, либо копипаст с этих. Впрочем если знаете что-то еще - добро пожаловать в комменты

Добавлено намного позже:   Вот появился еще один интересный ресурс - lookapp.ru