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

27. UITextField

Видео урок 27 находится здесь.
В этом уроке подробно рассмотрено поле ввода - UITextField.
Как и для других контролов настройки можно проводить в сторибоард.
Так же эти операции можно делать в коде

    self.firstNameField.keyboardAppearance= UIKeyboardAppearanceLight;
    self.lastNameField.keyboardAppearance=UIKeyboardAppearanceDark;

Установка  цвета всплывающей клавиатуры



    [self.firstNameField becomeFirstResponder];
установка фокуса ввода на элемент (клавиатура для ввода сразу появляется)

if ([self.lastNameField isFirstResponder]){
        [self.lastNameField resignFirstResponder];
    }
отмена фокуса ввода если он был 

Считывать и сохранять информацию с текста ввода можно по разным событиям.

- (IBAction)actionTextChange:(UITextField *)sender {
     NSLog(@"%@",sender.text);
   
}
Экшн установлен в сторибоард по изменению данных.
Для доступа к тексту используется пробреди .text


Работать с текстовые полем можно через экшн, делегаты и нотификации

Методы делегата

    self.firstNameField.delegate=self;

Установка в качестве делегата self.

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
    return [textField isEqual:self.firstNameField];
}

Метод вызывается перед началом вводом. YES разрешает ввод

- (BOOL)textFieldShouldClear:(UITextField *)textField{
    
    return NO;
}

Метод используется для переопределния крестика стирания всего текста из поля ввода (здесь стирание запрещено)

- (BOOL)textFieldShouldReturn:(UITextField *)textField{
    if([textField isEqual:self.firstNameField]){
        [self.lastNameField becomeFirstResponder];
    }
    else{
        [textField resignFirstResponder];
    }
    return YES;

}

Этот метод вызывается когда нажат Return на клавиатуре
в данном случае если это поле ввода имени, при нажатии Return автоматически переходит в поле фамилии.

Нотификации

Подписываемся на нужные нотификации и тут же  отписываемся  (чтобы не забыть) в методе  dealloc  от всех нотификаций.

    NSNotificationCenter *nc=[NSNotificationCenter defaultCenter];
    [nc addObserver:self selector:@selector(notificationTextDidBeginEditing:) 
name:UITextFieldTextDidBeginEditingNotification object:nil];
}

-(void) dealloc{
    [[NSNotificationCenter defaultCenterremoveObserver:self];

}


Нотификация приходит когда начинают работать с полем ввода
    [nc addObserver:self selector:@selector(UITextFieldTextDidEndEditing:) name:UITextFieldTextDidEndEditingNotification object:nil];

В конце работы с полем
    [nc addObserver:self selector:@selector(UITextFieldTextDidChange:) name:UITextFieldTextDidChangeNotification object:nil];

в процессе ввода символов
    
    
Методы вызываемые в случае прихода нотификации:

-(void) notificationTextDidBeginEditing :(NSNotification *) notification{
    NSLog(@"notificationTextDidBeginEditing. User Info: %@",notification.userInfo);
}

-(void) UITextFieldTextDidEndEditing :(NSNotification *) notification{
    NSLog(@"UITextFieldTextDidEndEditing. User Info: %@",notification.userInfo);
}

-(void) UITextFieldTextDidChange :(NSNotification *) notification{
    NSLog(@"UITextFieldTextDidChange. User Info: %@",notification.userInfo);

}

Вот прикольное решение проблемы когда выскакивающая клавиатура закрывает TextField:
#pragma mark - keyboard

-(void)textFieldDidBeginEditing:(UITextField *)textField{
    
    [self animateTextField:textField up:YES withOffset:textField.frame.origin.y / 2];
}

-(void)textFieldDidEndEditing:(UITextField *)textField{
    
    [self animateTextField:textField up:NO withOffset:textField.frame.origin.y / 2];
    
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
    
    [textField resignFirstResponder];
    return true;
}

-(void)animateTextField:(UITextField*)textField up:(BOOL)up withOffset:(CGFloat)offset
{
    const int movementDistance = -offset;
    const float movementDuration = 0.4f;
    int movement = (up ? movementDistance : -movementDistance);
    [UIView beginAnimations: @"animateTextField" context: nil];
    [UIView setAnimationBeginsFromCurrentState: YES];
    [UIView setAnimationDuration: movementDuration];
    self.view.frame = CGRectOffset(self.view.frame, 0, movement);
    [UIView commitAnimations];

}


Исходник урока 27

Домашнее задание к уроку 27:

Создаем форму для регистрации студента.

Ученик.

1. Создайте поля (и лейблы напротив как в уроке): имя, фамилия, логин, пароль, возраст, телефон, имеил адрес.
2. Установите правильные виды клавиатур для каждого текстового поля.
3. У всех текстовых полей кроме последнего кнопка ретерн должна быть NEXT, а у последнего DONE.
4. Осуществите переход по кнопкам NEXT и уберите клаву с экрана кнопкой DONE.
5. Каждое поле при нажатии должно иметь кнопку очистки

Студент

6. Совет, чтобы осуществить переход по NEXT без проверки тонны пропертей, попробуйте использовать UIOutletCollection
7. Создайте соответствующие каждому текстовому полю UILabel чтобы выводить туда информацию из текстовых полей. Сделайте их мелкими и другого цвета.
8. По изменению текста (даже буквы) обновляйте эти лейблы (не забудте про CLEAR button)

Мастер

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

Супермен

11. Для поля ввода имеила ограничте ввод символов недопустимых в адресе
12. Более того, сибвол "@" может быть введен только 1 раз
13. установите разумное ограничение для этого поля

Все задания к уроку 27 выполнены

Единственный непонятный момент - даже при пустом, только что созданном проекте и текстом поле, в половине эмуляторов (айпад, айфон разных моделей) не всплывает клавиатура или клавиатура появляется без символов (клавиш в эмуляторах айпада), причем курсор в поле мигает и тест вводится с клавиатуры компьютера. Но в некоторых эмуляторах всплывающая клавиатура работает как надо. Но в процессе написания кода по непонятным причинам она перестает всплывать даже на тех эмуляторах на которых работала. Много бился с этой проблемой, но решить её не получилось.



суббота, 26 сентября 2015 г.

26. Controls: UISlider, UISwitch, UISegmentedControl

Видео урок находится здесь.
В этом уроке рассматриваются элементы управления (controls): UISlider, UISwitch, UISegmentedControl.

С помощью сторибоард создаем контролы.
UISlider - слайдер, полоска с бегунком.
UISwitch - переключатель имеющий 2 положения (включено/выключено).
UISegmentedControl - переключатель с множеством вариантов, но выбрать можно только один вариант.

После создания контролов и событий, заголовочный файл выглядит так:

@property (weak, nonatomic) IBOutlet UILabel *infoLabel;
@property (weak, nonatomic) IBOutlet UISlider *redComponentSlider;
@property (weak, nonatomic) IBOutlet UISlider *greenComponentSlider;
@property (weak, nonatomic) IBOutlet UISlider *blueComponentSlider;
@property (weak, nonatomic) IBOutlet UISegmentedControl* colorSchemeControl;


- (IBAction)actionSlider:(UISlider *)sender;

- (IBAction)actionEnable:(UISwitch *)sender;


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

    CGFloat red = self.redComponentSlider.value;
    CGFloat green = self.greenComponentSlider.value;
    CGFloat blue = self.blueComponentSlider.value;

При переключении свитча вызывается actionEnable.
Для того, чтобы считать значения переключателя, используется измененный геттер sender.isOn :
@property(nonatomic,getter=isOn) BOOL on;

Для отключения control от сообщений, применяется property .enable
    self.redComponentSlider.enabled = self.greenComponentSlider.enabled = self.blueComponentSlider.enabled = sender.isOn;

В процессе перетягивания переключателя switch  приходит много сообщений(событий), если это мешает (большие вычисления или анимация), можно сделать задержку обработки сообщений на короткое время:
    [[UIApplication sharedApplication] beginIgnoringInteractionEvents];
    double delayInSeconds = 0.4f;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        
        if ([[UIApplication sharedApplication] isIgnoringInteractionEvents]) {
            [[UIApplication sharedApplication] endIgnoringInteractionEvents];
        }
    });
Приложение игнорирует события, происходит задержка на 0.4 секунды, затем заканчивается режим игнорирования событий.

Для контрола UISegmentedControl в данном примере состоит из 2-х возможных значений, создадим энную (чтобы не обращаться по неинфврмативному индексу 0 и 1):
typedef enum {
    
    ASColorSchemeTypeRGB,
    ASColorSchemeTypeHSV
    

} ASColorSchemeType;

Для установки выбранного значения задаем 0 индекс или ASColorSchemeTypeRGB

    self.colorSchemeControl.selectedSegmentIndex = ASColorSchemeTypeRGB;

Для определения какой элемент выбран:
   if (self.colorSchemeControl.selectedSegmentIndex == ASColorSchemeTypeRGB)



Домашнее задание к уроку 26 - Controls:

Ученик.

1. Расположите тестируюмую вьюху на верхней половине экрана
2. На нижней половине создайте 3 свича: Rotation, Scale, Translation. По умолчанию все 3 выключены
3. Также создайте сладер скорость, со значениями от 0.5 до 2, стартовое значение 1
4. Создайте соответствующие проперти для свитчей и слайдера, а также методы для события valueChanged

Студент.

5. Добавьте сегментед контрол с тремя разными сегментами
6. Они должны соответствовать трем разным картинкам, которые вы должны добавить
7. Когда переключаю сегменты, то картинка должна меняться на соответствующую

Мастер.

8. Как только мы включаем один из свичей, наша вьюха должна начать соответствующую анимацию
(либо поворот, либо скеил, либо перенос). Используйте свойство transform из урока об анимациях
9. Так же следует помнить, что если вы переключили свич, но какойто другой включен одновременно с ним, то вы должны делать уже двойную анимацию. Например и увеличение и поворот одновременно (из урока про анимации)
10. Анимации должны быть бесконечно повторяющимися, единственное что их может остановить, так это когда все три свича выключены

Супермен.

11. Добавляем использование слайдера. Слайдер регулирует скорость. То есть когда значение на 0.5, то скорость анимаций должна быть в два раза медленнее, а если на 2, то в два раза быстрее обычной.
12. Попробуйте сделать так, чтобы когда двигался слайдер, то анимация обновлялась без прерывания, а скорость изменялась в соответствующую сторону.

Выполнены все задания к 26 уроку и много чего плюсом.



Horror Controls - 3 анимированных призрака, 4 параметра анимации, можно все параметры независимо друг от друга менять. При изменении призраков и параметров для редактирования восстанавливается соответствующее значения слайдера и светлей.

Исходный код приложения здесь.



понедельник, 21 сентября 2015 г.

25.Button - Кнопки

Видео урок 25 Buttons находится здесь.
В этом уроке рассказывается как создавать кнопки программно (в коде) и с помощью сториборд.

Для примера создания
UIButton наследник UIView, поэтому большинство моментов уже рассмотрено.

Создается кнопка настраиваемая (custom)

    UIButton * button =[UIButton buttonWithType:UIButtonTypeCustom];

Размер и положение кнопки

    button.frame=CGRectMake(200, 200, 200, 200);

Фон
    button.backgroundColor=[UIColor lightGrayColor];

Надписи в нормальном режиме 
    [button setTitle:@"Button" forState:UIControlStateNormal];
И при нажатии
    [button setTitle:@"Button Pressed" forState:UIControlStateHighlighted];
Цвет надписи при нормальном состоянии
    [button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
Цвет надписи при нажатии
    [button setTitleColor:[UIColor greenColor] forState:UIControlStateHighlighted];

Установка кнопки на основную вью:
    [self.view addSubview:button];

Установка шрифта  и цвета, текста для нормального состояния

    NSDictionary *attributes=@{NSFontAttributeName : [UIFont systemFontOfSize:30],
                               NSForegroundColorAttributeName: [UIColor orangeColor]};
    NSAttributedString *title= [[NSAttributedString alloc] initWithString:@"Button" attributes:attributes];
    [button setAttributedTitle:title forState:UIControlStateNormal    ];

То же самое для нажатого состояния
    
    NSDictionary *attributes2=@{NSFontAttributeName : [UIFont systemFontOfSize:20],
                               NSForegroundColorAttributeName: [UIColor blackColor]};
    NSAttributedString *title2= [[NSAttributedString alloc] initWithString:@"Button" attributes:attributes2];
    [button setAttributedTitle:title2 forState:UIControlStateHighlighted    ];

Можно установить отступы для надписи

    UIEdgeInsets insets=UIEdgeInsetsMake(100, 100, 0, 0);
    button.titleEdgeInsets=insets;

Установка обработчиков нажатий на кнопку

    [button addTarget:self action:@selector(actionTest:event:) forControlEvents:UIControlEventTouchUpInside];
Обработчик срабатывает когда пользователь нажал и отпустил кнопку в пределах кнопки.


    [button addTarget:self action:@selector(actionTestOutSide:) forControlEvents:UIControlEventTouchUpOutside];
Обработчик срабатывает когда пользователь нажал кнопку и отпустил за пределами кнопки

Сами обработчики нажатий

-(void) actionTest:(UIButton *) but event:(UIEvent *) event {
    NSLog(@"Button Pressed Inside!");
}
-(void) actionTestOutSide:(UIButton *) but{
    NSLog(@"Button Pressed OutSide!");
}

Если создавать кнопки через сторибоард обработчик создаются автоматически


- (IBAction)actionTest2:(UIButton *)sender;
-(IBAction) actionTest2TouchDown:(UIButton *)sender;

Так же в этом уроке рассматривается UILabel:

При создании в сорибоард - аутлет

@property (weaknonatomicIBOutlet UILabel *indicatorLabel;

При создании в коде
    UILabel * label=[UILabel alloc] initWithFrame:(rect)

Чтобы изменить текст в Label

 self.indicatorLabel.text=[NSString stringWithFormat:@"%@ ",@(sender.tag)];


Домашнее задание к уроку 25 Buttons - Кнопки

Ученик.

1. Создайте и разместите кнопки цифр и операторов, создайте нужные акшины
2. Добавьте лейбл и создайте соответствующий проперти
3. По нажатию на кнопку на индикатор должна выводиться либо цифра, либо оператор (никаких вычислений - выводим просто значения кнопок)

Студент.

4. Наведите более / менее красоту, можете насоздавать линий (вьюхи с малой шириной)б ставить бэкграундыб используйте картинки если надо и тд. - проявите творчество :)
5. Сделайте так, чтобы когда нажимаешь на цифровую кнопку, то число росло
6. Сделайте кнопку сброса

Мастер.

7. Сохраняйте вводимое число
8. Первую операцию тоже надо сохранить, пока не ввели второе число (используйте енумы!)
9. Когда нажимаешь равно то первое число выболняет операцию над вторым и выводится результат
10. После того, как результат вывелся на экран, он автоматом становиться первым числом и к нему уже можно прибавлять, вычитать и т.д. - как в калькуляторе

Супермен

11. Добавьте точку, теперь можно вводить и дробное число, точка должна работать также, как и точка на обычном калькуляторе (имею в виду, что двух точек в числе быть не может в случае повторного нажатия)
12. С дробным вводом будет посложнее - задание для настоящих суперменов :)

Выполнены все задания




среда, 16 сентября 2015 г.

24.Drawing - Рисование

Ссылка на видео урок.
В этом уроке рассматриваются функции применяемые для рисования линий, прямоугольников, окружностей, дуг и т.д.
 При рисовании применяются Си`шные  функции.
Получаем контекст для рисования:

CGContextRef context=UIGraphicsGetCurrentContext();

Для задания цвета заливки применяется функция:

    CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);


Для задания цвета линий контура фигур или линий:

    CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);

Определяем квадрат и добавляем его для отрисовки

    CGRect rect1=CGRectMake(50, 50, 100, 100);
    
    CGContextAddRect(context, rect1);

Для отрисовки контуров этих квадратов выполняем:

    CGContextStrokePath(context);

Для заливки этих квадратов:

    CGContextFillPath(context);

Для добавления к отрисовке  окружности можно использовать функцию:

    CGContextAddEllipseInRect(context, rect1);

Для установки ширины линии:

CGContextSetLineWidth(context, 3);

Для установки округлой формы начала и конца линий (шапки линии):

    CGContextSetLineCap(context, kCGLineCapRound);


Для установки точки с которой начнется рисования линии:

    CGContextMoveToPoint(context, CGRectGetMinX(rect1), CGRectGetMaxY(rect1));


Для рисования линии от установленной точки к следующей (указанной):

   CGContextAddLineToPoint(context, CGRectGetMinX(rect3), CGRectGetMaxY(rect3));

Выводим линии:

   CGContextStrokePath(context);

Добавляем окружность (указывается центр окружности, радиус,  начальный и конечный угол, по часовой стрелке или против):
    
   CGContextAddArc(context, CGRectGetMaxX(rect1), CGRectGetMaxY(rect1), CGRectGetWidth(rect1), 0, M_PI, NO);


Для рисования текста необходимо сформировать атрибуты в NSDictionary:

Определяем текст
    NSString *text=@"test";

Задаем шрифт и размер шрифта
    UIFont *font=[UIFont systemFontOfSize:14.f];

Тень от текста
    NSShadow *shadow=[[NSShadow alloc] init];

Сдвиг тени
    shadow.shadowOffset = CGSizeMake(1, 1);

Цвет тени
    shadow.shadowColor=[UIColor blackColor];

Радиус размытия
    shadow.shadowBlurRadius=0.5;

Записываем все это в словарь дикшионари
    NSDictionary *attributes= [NSDictionary dictionaryWithObjectsAndKeys:
                               [UIColor grayColor],         NSForegroundColorAttributeName,
                               shadow,                      NSShadowAttributeName,
                               font,                        NSFontAttributeName,
                               nil];
    
Определяем размер текста для вывода
    CGSize textSize=[text sizeWithAttributes:attributes];
Определяем место для вывода в центре квадрата
    CGRect textRect = CGRectMake(CGRectGetMidX(rect2), CGRectGetMidY(rect2), textSize.width, textSize.height);
Округляем величины квадрата для отрисовки текста - устраняет эффект размытости возникающий при при дробных значения
    textRect=CGRectIntegral(textRect);

Выводим текст в заданном прямоугольнике с заданными атрибутами

    [text drawInRect:textRect withAttributes:attributes];

Можно выводить текст так же с помощью этой функции указывая точку Origin:

    [text drawAtPoint:CGPointMake(CGRectGetMidX(rect2)-textSize.width/2, CGRectGetMidY(rect2)-textSize.height/2) withAttributes:attributes];



Во второй части урока для примера рисуется шахматная доска:

    CGFloat offset=50;
    CGFloat boarderWidth=4.f;
    CGFloat maxBoardSize=MIN(CGRectGetWidth(rect)-(offset+boarderWidth)*2, CGRectGetHeight(rect)-(offset+boarderWidth)*2);
    int cellSize=(int) maxBoardSize/8;
    int boardSize=cellSize*8;
    CGRect boardRect=CGRectMake((CGRectGetWidth(rect)-boardSize)/2, (CGRectGetHeight(rect)-boardSize)/2, boardSize, boardSize );
    
    
        for (int i=0; i<8; i++) {
        for (int j=0; j<8; j++) {
            if(i%2!=j%2){
                CGRect cellRect=
                CGRectMake(CGRectGetMinX(boardRect)+i*cellSize,
                           CGRectGetMinY(boardRect) +j*cellSize,
                           cellSize,cellSize);
                CGContextAddRect(context, cellRect);
            }
        }
    }
    
    CGContextSetFillColorWithColor(context, [UIColor grayColor].CGColor);
    CGContextFillPath(context);
    CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor);
    CGContextAddRect(context, boardRect);
    CGContextSetLineWidth(context, boarderWidth);
    CGContextStrokePath(context);




Исходный текст урока 24.

Домашнее задание к уроку 24 UIView Drawing:

Ученик.

1. Нарисуйте пятиконечную звезду :)
2. Добавьте окружности на концах звезды
3. Соедините окружности линиями

Выполнено



Студент.

4. Закрасте звезду любым цветом цветом
5. При каждой перерисовке рисуйте пять таких звезд (только мелких) в рандомных точках экрана

Выполнено


Мастер

6. После того как вы попрактиковались со звездами нарисуйте что-то свое, проявите творчество :)

Выполнено

Ссылка на проект с заданиями ученик, студент, мастер.



Супермен

7. Сделайте простую рисовалку - веду пальцем по экрану и рисую :)

Выполнено

Ссылка на проект