Статьи

Универсальный вид загрузки для iOS

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

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

Сегодня я собираюсь показать вам, как сделать загрузочный экран многократного использования с индикатором активности (это одна из тех вращающихся вещей) и градиентным фоном.

Вот как это будет выглядеть!

Загрузка iOS Spinner от BuildMobile на Vimeo .

Прежде чем мы начнем, есть некоторые предпосылки. Вам нужно немного узнать о разработке под iOS, например, как иерархия окон, представлений и контроллеров все вместе. У нас есть несколько отличных учебных пособий, которые помогут вам освоиться, если вы еще не совсем там. Ознакомьтесь с разделом Введение в программирование iOS .

Также обратите внимание, что я использую Xcode 4.1. Если вы работаете с другой версией, некоторые вещи могут выглядеть немного иначе, но, поскольку мы делаем довольно простые вещи, это не должно быть слишком далеко от цели!

Шаги малыша. Начнем с проекта

Я собираюсь начать новый проект, но, возможно, у вас уже есть такой, который вы планируете использовать, поэтому этот шаг может оказаться для вас излишним. Это простой проект на основе навигации, использующий все значения по умолчанию Xcode.

Первым реальным шагом является создание нового класса для нашего представления счетчика. Для этого потребуется создать подкласс UIView, поэтому cmd + N, выберите «Objective-C Class» и нажмите «Далее». Убедитесь, что это подкласс UIView, затем снова нажмите Next. Наконец, выберите имя для сохранения вашего класса как, я собираюсь назвать мой SpinnerView.

Теперь у вас должен быть проект, который выглядит примерно так (если только вы не используете существующий проект, в этом случае он, скорее всего, не будет выглядеть так).

Использование вида счетчика должно быть простой задачей. Цель здесь — иметь возможность загрузить представление счетчика в одну строку кода. Поэтому первое, что мы собираемся сделать, — это создать метод, который принимает UIView и выделяет новый экземпляр класса SpinnerView, а затем добавляет себя в качестве подпредставления.

Перейдите к заголовочному файлу SpinnerView и вставьте определение метода перед @end

+(SpinnerView *)loadSpinnerIntoView:(UIView *)superView;

Далее нам нужно определить фактический метод. Этот метод будет выполнять тяжелую работу в отношении создания представления с содержимым в нем и помещения его в переданный superView.

 +(SpinnerView *)loadSpinnerIntoView:(UIView *)superView{
	// Create a new view with the same frame size as the superView    
	SpinnerView *spinnerView = [[[SpinnerView alloc] initWithFrame:superView.bounds] autorelease];
	
	// If something's gone wrong, abort!
	if(!spinnerView){ return nil; }

	// Just to show we've done something, let's make the background black
	spinnerView.backgroundColor = [UIColor blackColor];

	// Add the spinner view to the superView. Boom.
	[superView addSubview:spinnerView];

	return spinnerView;
}

Этот код создаст очень простой вид с черным фоном и вставит его в предоставленный основной вид.

Теперь у нас достаточно кода, который мы можем проверить, чтобы увидеть, что мы в действии, поэтому теперь нам нужно настроить некоторый код, чтобы фактически использовать это!

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

 // In the RootViewController header definition
-(IBAction)didPressSpinnerButton:(id)sender;

// In the RootViewController class file, don't forget to #import "SpinnerView.h"
-(IBAction)didPressSpinnerButton:(id)sender{
	// Load a new spinnerView into the current view
	[SpinnerView loadSpinnerIntoView:self.view];
}

Итак, мы создали метод, который при вызове будет загружать новый spinnerView в представление контроллера. Затем мы добавим кнопку в нашу xib и подключим ее, чтобы вызвать созданный нами IBAction.

Откройте MainWindow.xib (или любой другой xib, если у вас есть собственный проект). Из инспектора объектов поместите новый вид в «Root View Controller», затем поместите круглую кнопку Rect в этот вновь созданный вид. Вставьте ярлык в свою кнопку, чтобы вы знали, что он собирается делать. Моим описательным ярлыком было «Загрузить что-то». Наконец, нажмите кнопку и, в инспекторе соединений (переключение opt + cmd + 6), перетащите курсор из круга рядом с «Touch Up Inside» поверх «Root View Controller» слева. Когда вы отпустите, вы сможете выбрать созданный вами IBAction. Как только вы это сделаете, это должно выглядеть так, как на рисунке, и теперь вы должны были подключить кнопку к методу.

Время проверить!

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

В классе SpinnerView определите новый метод removeSpinner.

 // .h file
-(void)removeSpinner;

// .m file
-(void)removeSpinner{
	// Take me the hells out of the superView!
	[super removeFromSuperview];
}

RemoveSpinner довольно прост. Это просто удаляет представление из superView. Легко.

Мы можем увидеть это в движении, добавив таймер в наш метод didPressSpinnerButton. Нам нужно будет вставить спиннер в переменную, чтобы сделать это тоже. Вот наш обновленный метод didPressSpinnerButton.

 -(IBAction)didPressSpinnerButton:(id)sender{
    SpinnerView * spinner = [SpinnerView loadSpinnerIntoView:self.view];

    [NSTimer scheduledTimerWithTimeInterval:2.0 
                                     target:spinner 
                                   selector:@selector(removeSpinner) 
                                   userInfo:nil repeats:NO];
}

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

Основы. Проверьте!

У нас есть основы для нашего класса представления счетчика. Остальное просто глазурь. И под глазурью я имею в виду интерфейс и дизайн.

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

В нашем методе loadSpinnerIntoView в файле SpinnerView.m мы собираемся создать и вставить индикатор активности.

 if(!spinnerView){ return nil; }

	// This is the new stuff here 😉
    UIActivityIndicatorView *indicator = 
    [[[UIActivityIndicatorView alloc]
      initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhiteLarge] autorelease];
    
	// Set the resizing mask so it's not stretched
    indicator.autoresizingMask = 
    UIViewAutoresizingFlexibleTopMargin |
    UIViewAutoresizingFlexibleRightMargin |
    UIViewAutoresizingFlexibleBottomMargin |
    UIViewAutoresizingFlexibleLeftMargin;
    
	// Place it in the middle of the view
    indicator.center = superView.center;

	// Add it into the spinnerView
    [spinnerView addSubview:indicator];

	// Start it spinning! Don't miss this step
	[indicator startAnimating];

Постройте это и посмотрите, как это выглядит. Надеюсь, это выглядит немного (точно) так.

Вы знаете, что нам нужно? Градиенты!

Пора нам что-то делать с этим ужасным черным фоном. Пришло время для нашего радиального градиента. Могу поспорить, что вы ожидаете, что я скажу «открыть фотошоп…», но я нет. Мы собираемся написать наш градиент в коде по двум причинам. Во-первых, нам не нужно беспокоиться о создании двух изображений (одно для старых телефонов, а другое для дисплеев сетчатки iPhone 4), которое было бы сложно обновлять! Во-вторых, если мы делаем это в коде, мы не добавляем в наше приложение столько же размеров файлов, сколько нужно. Держать это стройными людьми. Это BuildMobile Gym для приложений.

Итак … как мне это сделать?

Градиент а? Бьюсь об заклад, iOS SDK имеет удобный API для создания градиента для нас. Верный! Но тоже неверно.

IOS SDK имеет полезный способ создания линейного градиента с помощью CAGradientLayer , но он не обеспечивает быстрый и простой способ создания радиального градиента, чего мы и хотим. Для этого нам нужно немного покопаться и начать работать с платформой Core Graphics.

На самом деле мы собираемся определить метод, который возвращает объект UIImage, объект, который мы собираемся создать с нуля — используя код! Код отличный.

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

 - (UIImage *)addBackground{
	// Create an image context (think of this as a canvas for our masterpiece) the same size as the view
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 1);
    
	// Our gradient only has two locations - start and finish. More complex gradients might have more colours
    size_t num_locations = 2;

	// The location of the colors is at the start and end
    CGFloat locations[2] = { 0.0, 1.0 };

	// These are the colors! That's two RBGA values
    CGFloat components[8] = {
        0.4,0.4,0.4, 0.8,
        0.1,0.1,0.1, 0.5 };    
    
	// Create a color space
    CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();

	// Create a gradient with the values we've set up
    CGGradientRef myGradient = CGGradientCreateWithColorComponents (myColorspace, components, locations, num_locations);
    
	// Set the radius to a nice size, 80% of the width. You can adjust this
    float myRadius = (self.bounds.size.width*.8)/2;
    
	// Now we draw the gradient into the context. Think painting onto the canvas
    CGContextDrawRadialGradient (UIGraphicsGetCurrentContext(), myGradient, self.center, 0, self.center, myRadius, kCGGradientDrawsAfterEndLocation);
    
	// Rip the 'canvas' into a UIImage object
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    
	// And release memory
    CGColorSpaceRelease(myColorspace);
    CGGradientRelease(myGradient);
    UIGraphicsEndImageContext();

	// … obvious.
    return image;
}

Все еще со мной? Нет? Черт.

Следует отметить основные компоненты CGFloat, которые определяют цвета для градиента, и поплавок myRadius, который позволяет изменить размер градиента.

Если вы добавите этот метод и его соответствующее определение метода в заголовок, мы теперь готовы вызывать его из метода loadSpinnerIntoView и вставлять его в фон вместо простого черного фона.

Удалите линию, которая делает фон черным

 spinnerView.backgroundColor = [UIColor blackColor];

И добавьте это перед кодом индикатора активности (иначе он будет выше индикатора активности. Не хорошо.

 // Create a new image view, from the image made by our gradient method
    UIImageView *background = [[UIImageView alloc] initWithImage:[spinnerView addBackground]];

	// Make a little bit of the superView show through
    background.alpha = 0.7;
    
    [spinnerView addSubview:background];

Теперь, если вы создадите свое приложение, вы увидите чертовски привлекательный спиннер!

Вот и вся тяжелая работа. Осталось только добавить вишню сверху; затухание вращающегося взгляда внутрь и наружу. Это удивительно просто — за исключением того, что вы должны добавить в платформу QuartzCore.

Для тех из вас, кто забыл шаги по добавлению фреймворка: перейдите в настройки своих проектов, выберите цель (в моем случае «Spinner View») -> Фазы сборки -> Связать двоичные файлы с библиотеками, нажмите символ плюса и найдите QuartzCore.framework.

Убедитесь, что вы импортируете, а затем добавьте это непосредственно перед возвратом из метода loadSpinnerIntoView.

 // Create a new animation
    CATransition *animation = [CATransition animation];

	// Set the type to a nice wee fade
	[animation setType:kCATransitionFade];

	// Add it to the superView
	[[superView layer] addAnimation:animation forKey:@"layerAnimation"];

В функции removeSpinner код практически идентичен.

 // Add this in at the top of the method. If you place it after you've remove the view from the superView it won't work!
    CATransition *animation = [CATransition animation];
	[animation setType:kCATransitionFade];
	[[[self superview] layer] addAnimation:animation forKey:@"layerAnimation"];

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

Mint.