среда, 8 января 2014 г.

IOS AlertView – реализация окна диалога

Рассмотрим пример реализации стандартного окна диалога AlertView. Очень часто в приложениях необходимо участие пользователей, что бы подтвердить или уведомить его о каких либо действиях. Рассмотрим на конкретном примере вывод диалогового окна и обработку событий  в зависимости от того что выбрал пользователя. Представим ситуацию в которой вам нужно предоставить пользователю возможность оценить ваше приложение, но не реализуя для этого какой нибудь viewcontroller. Как раз в этом нам поможет UIAlertView.


Посмотрим пример кода:
-(void) isneedRateDilog{
if([Utils checkshows]){
[[[UIAlertView alloc] initWithTitle:@»Оценить приложение»
message:@»Если вам понравилось приложение вы можете оставить оценку.»
delegate:self //делегат
cancelButtonTitle:nil // не делать кнопку отмены обычно она красного цвета
otherButtonTitles:@»Оценить»,@»Позже»,@»Никогда», nil] //кнопки
show]; //показать диалог сразу при вызове метода isneedRateDilog
}
}
И так мы задами название initWithTitle, текст сообщения message и три кнопки otherButtonTitles. Обратите внимание что делегатом мы указали self – тоесть обработка событий нажатия на кнопки будет в этом же классе.
Теперь посмотрим на обработчик событий:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
switch (buttonIndex) {
case 0://оценить
//сюда можно вставить любой другой код
break;
case 1://позже
break;
case 2://никогда
break;
}
}
Как видите всё достаточно прозаично: кнопки имеют индекс попорядку от нуля и до того количества кнопок – которое имеется у вас в диалоговом окне.

Полезные методы и функции для IOS разработчиков. Часть 2

В прошлой части полезных методов и функций я описал не все интересные примеры потому, что их очень много и теперь хочу продолжить эту тематику. Так как возможно это полезно вам и мне не даст забыть как это делается :)
Начать хотелось бы с полезного метода хранения некоторых пользовательских настроек в памяти мобильного устройства по средствам NSUserDefaults. Это некий класс с примитивными методами помогающими временно(на момент существования вашего приложения в пределах одной версии) хранить фактически любые данные. Начиная от просто строк до байтовых данных NSData. И так рассмотрим методы записи данных:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:@"Строка любого содержания" forKey:@"some_str"];
В первой строке мы создаём объект класса NSUserDefaults что быработать с его методами. Во второй строке мы присваиваем значение ключу some_str в виде строки с произвольным содержимым. Теперь эта строка будет хранится пока мы не удалим приложение или не обновим его до следующей версии.  Как же теперь достать эти данные при необходимости? На самом деле очень просто:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *str = [userDefaults objectForKey:@"some_str"];
Заведома зная что у нас по этому ключу лежит строка я создал объект имено NSString. Хотя если вы например укажете там Int среда Xcode не выдаст вам ошибки так как объект содержащийся в userDefaults так сказать не индексируется. Но при использовании этого метода в период работы приложения будет ошибка и XCode напишет вам её в консоль. Поэтому надо быть поаккуратнее с подобыми операциями.
Для очистки значения по ключу достаточно присвоить ключу nil подобно тому как мы дели присвоение строки в первом листинге кода.
Ещё один не маловажный момент который может пригодится, а именно знать как выбирать между двумя разными stroyboard когда это необходимо.
Но делать такую проверку и выбор stroyboard необходимо в методе – (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions класса AppDelegate.m вашего приложения, Поскольку выбрать его можно будет только до того как он станет для приложения по умолчанию, на лету это сделать нельзя. Допустим у вас уже есть stroyboard созданный XCode при создании нового приложения и вам необходимо добавить ещё один для запуска допустим на мобильных устройствах типа IPhone но с рейтина дисплеем. Создайте файл stroyboard и назовите его к примеру Rstoryboard.
И так открываем выше упомянутый метод и пишем слдеующий код:
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
UIStoryboard *storyBoard;
CGSize result = [[UIScreen mainScreen] bounds].size;
CGFloat scale = [UIScreen mainScreen].scale;
result = CGSizeMake(result.width * scale, result.height * scale);
//проверим высоту экрана телефона
if(result.height == 1136){ //это нам подходит для определения рейтина дисплея
storyBoard = [UIStoryboard storyboardWithName:@"Rstoryboard" bundle:nil];//устанавливаем нужный нам Rstoryboard
UIViewController *initViewController = [storyBoard instantiateInitialViewController];
[self.window setRootViewController:initViewController];
}
}
Далее рассмотрим на примере код который позволит из вашего приложения открыть itunes со  страницей вашего приложения например для оценки или написания отзыва.
NSURL *appStoreURL = [NSURL URLWithString:@"ссылка на приложение"];
[[UIApplication sharedApplication] openURL:appStoreURL];
Фактически этот метод откроет safari но сам safari перенаправит пользователя на itunes. Ссылку на приложение легко сформировать нажав на стрелку возле Downlowd  на странице вашего приложения в Itunes, и выбрав copy link.

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


Я создал стандартный вид перехода от первого окна ко второму по средствам navigationController. Если скомпилировать проект мы увидим, что на первом окне уже появилась верхняя навигационная панель.



Теперь нам нужно добиться прозрачности навигационной панели в первом окне.
Для этого добавим следующий код в m файл нашего контроллера первого окна.
- (void)viewWillAppear:(BOOL)animated{
//прозрачный верхний бар
[self makeTransparentNavBar];
}
-(void) makeTransparentNavBar{
self.navigationController.navigationBar.translucent = YES;
const float colorMask[6] = {222, 255, 222, 255, 222, 255};
UIImage *img = [[UIImage alloc] init];
UIImage *maskedImage = [UIImage imageWithCGImage: CGImageCreateWithMaskingColors(img.CGImage, colorMask)];
[self.navigationController.navigationBar setBackgroundImage: maskedImage forBarMetrics:UIBarMetricsDefault];
//убираем тень
[self.navigationController.navigationBar setShadowImage: [[UIImage alloc] init]];
}
Сдесь я назначаю посути прозрачную картинку navigationBar-у и убираю тень. Вот как будет выглядеть первое окно при компиляции проекта, и ещё я добавил кнопку с помощью которой мы тоже осуществим переход на второе окно. Так же как и в случае с кнопкой Item я назначил ей push переход ко второму окну.

Во втором окне ситуация точно такая же. Верхняя панель прозрачная, но задача стоит спрятать навигационную панель только на первом окне. Для этого добавим следующий код в m файл второго контроллера:
- (void)viewWillAppear:(BOOL)animated{
//установим пустую картинку для панели
[self.navigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
}
В данном методе мы убираем картинку с заднего плана тем самым navigationController сам установит нам дефолтный задний план. Теперь уберём название с навигационной панели первого окна и кнопку Item

Теперь можете скомпилировать проект и посмотреть как выглядит первое и второе окно.

IOS Программируем жесты с UIGestureRecognizer

Все мы знаешь, что в приложениях для IOS есть возможность создавать события на основе жестов на экране IPhone или IPad. В XCode мы можем сделать это с помощью Storyboard или же описать их программно. На мой взгляд особой разницы нет как это делать, но в данной статье я напишу как делать это программно. Для начала разберемся с тем какие бывают жесты.
  • UITapGestureRecognizer   – жест нажатия пальцем на экран
  • UIPinchGestureRecognizer  - жест "ущипнуть" экран
  • UIRotationGestureRecognizer - жест вращения пальцами по экрану
  • UISwipeGestureRecognizer - жест "скольжения" то есть протянули пальцем
  • UIPanGestureRecognizer - жест, который выглядит как перетаскивание
  • UILongPressGestureRecognizer - долгое удерживание пальца на экране
Все эти жесты помогают нам так или иначе разнообразить работу и интерфейс приложения. Рассмотрим простой пример когда необходимо использовать жест нажатия например на изображение UIImageView. Поскольку IBOutlet UIImageView не имеет стандартной возможности воспринимать действия на себе  -  пример будет достаточно полезным.
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapOnImageView:)];
[image addGestureRecognizer:tap];
Tap- это объект распознователя жестов который я инициализировал с помощью указания себя в качестве передаваемого параметра в метод didTapOnImageView. Который отработает когда жест будет выполнен/или начат. Во второй строек я добавил его к объекту UIImageView image. Далее достаточно только создать метод didTapOnImageView как на примере:
-(void) didTapOnImageView:(UIGestureRecognizer*) recognizer {
//код который должен отработать
}
Почему я написал через слеш выполнен/или начат? Потому, что в методе  didTapOnImageView мы указали входящий параметр сам объект распознавания у которого можно получить его состояния и проверить их. Например таким условием:
if (recognizer.state == UIGestureRecognizerStateBegan)
//в данном случае проверка началось ли распознование жеста
При использовании UITapGestureRecognizer эта проверка встряли понадобится, но вот при UILongPressGestureRecognizer может быть к стати.
Список состояний которые можно проверить:
UIGestureRecognizerStatePossible - распознаватель еще не признал жест, но может быть сенсорным оценке событий. Это состояние по умолчанию.
UIGestureRecognizerStateFailed - распознаватель устанавливает этот статус когда жест не может быть выполнен

UIGestureRecognizerStateRecognized - распознаватель понял и распознал жест
UIGestureRecognizerStateBegan - распознавание жеста началось
UIGestureRecognizerStateChanged - распознаватель устанавливает этот статус когда жест был изменен и завершит распознавание на следующем цикле обработки

UIGestureRecognizerStateEnded  – распознавание жеста закончилось
UIGestureRecognizerStateCancelled - распознавание жеста было отменено

Манипулируя проверками этих состояний можно с точностью отловить, что происходит в тот или иной момент времени когда работает распознаватель жестов.
Рассмотрим ещё несколько опций которые могут быть использованы при работе с распознаванием жестов.  Например:
tap.minimumPressDuration = 1.0; //сколько секунд нужно удерживать палец на экране для распознавателя жеста UILongPressGestureRecognizer
[tap setNumberOfTouchesRequired:1]; //задает количество прикосновений которые необходимо сделать для распознавания жеста
Теперь рассмотрим еще один пример программной реализации жеста скольжения:
   UISwipeGestureRecognizer *swipetoleft = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(didSwipe)];
[swipetoleft setDirection:UISwipeGestureRecognizerDirectionLeft];
[optpodlozhka addGestureRecognizer:swipetoleft];
В данном примере появилась ещё одна строка [swipetoleft setDirection:UISwipeGestureRecognizerDirectionLeft]; Которая указывает направление жеста. Это свойство характерно для UISwipeGestureRecognizer. Этим я хочу сказать что для каждого вида жеста могут быть использованы разные свойства и настройки. Полный список которых можно посмотреть в UIGestureRecognizer Class Reference.

Проигрывание mp3 online через интернет в IOS.

Возможно вы когда нибудь задумывались о написании собственного приложения медиа плеера для проигрывания музыки из интернета или же просто прослушивания mp3 стрима. На самом деле реализовать такое приложение для iPhone не так уж и сложно. И так оснавная задача этой статьи объяснить как в приложении реализовать проигрывание mp3 файлов онлайн используя в качестве источника mp3 файл на удалённом сервере например адресс http://your.site.com/music.mp3
Необходимо создать проект и добавить в проект фреймворк MediaPlayer framework. Сделать это можно во вкладке Build phases вашего проекта в Xxode, нажав на плюсик в разделе Link Binary With Libraries. Он нужен нам для использования медиа плеера MPMoviePlayerController.

И так приступим к написанию кода для начала в h файле вашего метода нужно сделать импорт
#import
Далее в этом же файле давайте создадим свойство property для того что бы иметь доступ к объекту не только из данного класса:
@property (nonatomic, strong) MPMoviePlayerController *moviePlayer;
Теперь переходим в m файл вашего контроллера и незабываем про
@synthesize moviePlayer;
Теперь можем добавить следующий код например в метод viewDidLoad
   NSString* resourcePath = @»http://your.site.com/music.mp3″; // url источника mp3 файла
NSURL *url = [NSURL URLWithString:resourcePath]; //формируем NSUrl
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:url]; //инициализация плеера
//настройки оповещения системе от том что выполнить метод moviePlayBackDidFinish когда проигрывание закончится
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
//настройки плеера
moviePlayer.controlStyle = MPMovieControlStyleEmbedded;
moviePlayer.shouldAutoplay = YES;
moviePlayer.view.userInteractionEnabled = YES;
//координаты и размер окошка плеера если хотим сделать не полноэкранный режим
[moviePlayer.view setFrame:CGRectMake(30, 30, 300, 20)];
moviePlayer.view.backgroundColor = [UIColor clearColor]; //прозрачный цвет фона за плеером вместо черного
[self.view addSubview:moviePlayer.view];
[moviePlayer setFullscreen:NO animated:NO]; //если указать например setFullscreen:YES то плеер запустится на полное окно приложения

Теперь при загрузке приложения сразуже запустится плеер и будет проигрывать ваш файл, но не забываем добавить ещё метод moviePlayBackDidFinish: смотрим код
- (void) moviePlayBackDidFinish:(NSNotification*)notification {
MPMoviePlayerController *moviePlayer = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
if ([moviePlayer
respondsToSelector:@selector(setFullscreen:animated:)])
{
[moviePlayer.view removeFromSuperview]; //эта строка убирает с экрана сам плеер если хотите его оставить строку нужно удалить
}
}
Вот собственно все теперь вы умеете проигрывать музыку из интернета прямо в своём приложении. Более детальные настройки moviePlayer можно почитать в офицеальной SDK

понедельник, 28 октября 2013 г.

Работа с фото камерой в Android

В этой статье я хочу рассказать как запустить фото камеру из вашего android приложения, а также как сделать снимок и сохранить полученное фото. Предполагается что у вас уже установлена среда разработки например eclipse и настроен Android SDK.
Для начала необходимо внести изменения в файл AndroidManifest.xml, он находится в корне проекта. Если он октрыт у вас на вкладке Manifest, то вам нужно выбрать AndroidManifest.xml. Далее необходимо добавить следующий код.




здесь мы запрашиваем права на использование камерой и на использование внешним хранилищем данных например SD картой.
Далее можно работать с файлом описывающим работу активности вашего приложения, в моём случае это MainActivity.java
Код который нужно вставить либо в метод public void onCreate(Bundle savedInstanceState) { либо создать отдельный метод. Так как в первом случае камера вызовется сразу после запуска приложения.
public class MainActivity extends Activity {
private static final int CAMERA_RESULT = 100;
public static final int MEDIA_TYPE_IMAGE = 1;
private Uri fileUri;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String timeStamp = new SimpleDateFormat(«yyyyMMdd_HHmmss»).format(new Date(0, 0, 0));
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, «IMG_» + timeStamp + «.jpg»);
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
startActivityForResult(cameraIntent, CAMERA_RESULT);
}
И так поясню что гле:
private static final int CAMERA_RESULT = 100;    это константа для работы с камерй. она обязательна
И так после того как мы объявим в setContentView нашу активность нужно создать имя файла в которое будет писаться снимок фотокамеры.
Что собственно и описано в следующих строках
String timeStamp = new SimpleDateFormat(«yyyyMMdd_HHmmss»).format(new Date(0, 0, 0));
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, «IMG_» + timeStamp + «.jpg»);
Далее объявим событие вызова фото камеры.
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Теперь скажем куда сохранить полученый рисунок
fileUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
fileUri это константа типа Uri она хранит путь к файлу снимка на карте памяти.
Далее
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);  тут мы собственно задаём путь куда сохранить фотку.
И вызываем камеру startActivityForResult(cameraIntent, CAMERA_RESULT);
Теперь необходимо написать метод обработки событий фотокамеры onActivityResult, это стандартное название. Он получает фотографию сделанную с камеры и мы сможем её обработать.
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
ImageView photoimg = (ImageView)findViewById(R.id.iv_camera);
if (requestCode == CAMERA_RESULT) {
if (resultCode == RESULT_OK) {
if(fileUri != null) {
//устанавливаем превью картинки
photoimg.setImageURI(fileUri);
}
} else if (resultCode == RESULT_CANCELED) {
// User cancelled the image capture
} else {
// Image capture failed, advise user
}
}
}
Итак
ImageView photoimg = (ImageView)findViewById(R.id.iv_camera);
это созданный обобьет рисунка на layout-е activity_main.xml
вот его структура

android:id=»@+id/iv_camera»
android:layout_width=»wrap_content»
android:layout_height=»wrap_content»
android:layout_alignLeft=»@+id/textView1″
android:layout_centerVertical=»true»
android:src=»@drawable/ic_launcher» />

Это необходимо добавить на ctivity_main.xml, что бы мы могли увидеть потом что получилось в результате съёма фото.
if (requestCode == CAMERA_RESULT) {
тут мы проверяем пришел ли результат от камеры

if (resultCode == RESULT_OK) {  если всё ок
if(fileUri != null) { и не пуст файл в который сохраняется фото
//устанавливаем превью картинки
photoimg.setImageURI(fileUri);  выведем это фото в нашем окне приложения
}
}

И так мы имеем возможно вызвать камеру делать снимки и сохранять их на SD карту.
Так же если подключить телефон к компьютером где установлена среда разработки и запустить приложение на выполнение кнопкой RUN то оно автоматически установится на телефон и запустится.

Использование REDIS и Redis php library. Часть 2 – использование библиотеки.

Далие следует рассказать про ключ значение. Для работы с redis используется понятие
«Ключ=>значение» как ассоциативный массив. Где ключём является не кий виртуальный массив данных (значений). Представьте себе таблицу
Ключ Значение 1

Значение 2
Значение 3
…..
Значение n
Существует несколько разных типов ключей.
  • Strings
  • Lists
  • Sets
  • Sorted sets
  • Hashes
Самый простой типа это Strings.
Ключ значения которого это просто строки или много строк.
//определим настройки соединения с сервером$options = array(
‘namespace’ => ‘Application_’,
‘servers’ => array(
array(‘host’ => ’127.0.0.1′, ‘port’ => 6379)
)
);
include_once («Rediska.php»); //подключаем библиотеку
$rediska = new Rediska($options);
$key = new Rediska_Key(‘time’);// так мы определим ключ с именем ‘time’
$time = time();
$key->setValue($time); //так мы запишем значение в ключ
echo $key->getValue(); // вывод текущего значения ключа
Замечу что если повторно выполнить запись в ключ setValue то значение перезаписывается.
И работать с данными в таких ключах стоит как со строковыми переменными.

Далее рассмотрим пример работы с типом Lists (списки)
$list = new Rediska_Key_List(‘list’); // так мы определим ключ с именем ‘list’
$list->append(‘Apple’);
$list->append(‘Orange’);
Добавляем вконец списка сначала элемент ‘Apple’ затем ‘Orange’
$newarray = $list->toArray(true); //Если установлен параметр в true это означает,
что массив будет иметь итератор
Далее мы можем работать с массивом и удалять элементы из списка.
foreach($newarray as $key=>$item){
$list->remove($item->value); //Таким образом мы удалим все элементы списка
}
Рассмотрим пример работы с типом ключей Sets и Sorted sets
Этот тип особенно интересен так как мы можем использовать так называемые индексы значений
более-ммение в полной мере. Предположим что нам нужно хранить время входа пользователя на сайт.
Создадим сет и будем поочерёдно добавлять логин пользователя и время в формате unix timestamp.
$users = new Rediska_Key_Set(«sets»);
$users->add(‘Alexandr’,time());
$users->add(‘Oleg’,time());
$users->add(‘Ivan’,time());
Таким образом мы сформируем список пользователей с дополнительным полем – индексом в
нашем случае меткой времени.
Теперь допустим нам нужно удалить из сета пользователей. $rows = $users->toArray(true);
foreach($rows as $key=>$item){
$users->remove($item->value); //Таким образом мы удалим все элементы списка
} //Теперь рассмотрим пример удаления пользователей с использованием индекса в нашем случае метки времени.
foreach($rows as $key=>$item){
$users->removeByScore(1258125887,1258135887); //Сдесь укажем диапазон если нужен один пользователь и мы знаем время то укажем 2 одинаковых значения
}
Отличие таких ключей от Sorted sets ключей в том, что в сортированных сетах есть сортировка по полю score Это полезно при выводе данных которые должны быть отсортированы по индексу.
Теперь рассмотрим тип ключей Hashes. Эти ключи подобны ассоциативным массивам в PHP.
$user = new Rediska_Key_Hash(‘user’);
$user->set(array(‘Name’ => ‘Alex’, ‘lastName’ => ‘Ivanov’, ‘viewed’ => 1));
$user->set(array(‘Name’ => ‘Oleg’, ‘lastName’ => ‘Petrov’, ‘viewed’ => 0));
//Так мы добавим массив в данный сет // показать такие данные можно через обычный цикл
foreach($user as $field => $value) {
print «$field => $value»;
}
Все возможные методы можно посмотреть сдесь