12 недель. Неделя 1. FancyTwitter

Итак, вот и настал день первого приложения в разделе «12 недель программирования и дизайна». Как я уже писал ранее  что для первого раза я выбрал Александра Зайцева с его дизайном приложения для Твиттера. Мне понравился сам дизайн, а большим плюсом стало наличие PSD файла к нему. В дальнейшем придется, видимо, всегда выбирать интересные проекты на dribbble.com только c PSD. Наше микро-приложения я назвал FancyTwitter.

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

  • кастомный цвет UINavigationBar
  • две кнопочки UIBarButtonItem на нем
  • необычный кастомный элемент с текстом Favorites
  • кастомная клеточка UITableViewCell для таблицы
  • ну и красивый задник под этой табличкой

В принципе, ничего сложного. При разборе файла, я обнаружил, что слой, который прорисовывает navigation bar, состоит просто из белого слоя с 10% прозрачностью. Если я нарисую точь в точь такой в программе, то текст, который будет съезжать вверх при скроле, начнет накладываться на кнопки и заголовок, и это будет некрасиво и нечитаемо. Поэтому я обратился к автору с вопросом, что же он имел в виду. Это следует делать всегда, если вам что-то не понятно. Спрашивать заказчика или дизайнера. Чаще всего, все удается дизайнеру разложить по слоям, и мне как разработчику ничего не надо сливать в Photoshop. Но в данном случае, файл готовился для себя, поэтому совершенно нормально, что автор мне ответил, что он предполагал непрозрачный navigation bar и предложил мне просто самому растрировать этот слой и получить нужный мне png. Кстати, я всегда стараюсь сам резать присылаемые PSD, потому что дизайнер не всегда представляет как я работаю, или мой стиль нарезки, поэтому проще оказывается все резать самому. Также Александр объяснил мне, что наш красивый разблюренный задник статичен по его задумке, но предполагается еще несколько задников, которые пользователь может менять по своему желанию. Этому мы уделим особое внимание дальше.

Снимок экрана 2014-06-20 в 16.22.01

Так как мы будем только симулировать работу Твиттер-клиента, то перво-наперво я создал простой класс FTDataSource, который у нас отвечает за выдачу нам твиттов. Он организован крайне примитивно — это просто массив, содержащий NSDictionary, в которых содержаться все нужные нам данные — имя пользователя, имя его твиттера, картинка профиля, текст и картинка, которую разместил пользователь. Это очень большое упрощение, но на него на приходится идти. Мы можем впоследствии заменить код в этом классе и получать реальные твиты, но пока оставим все как есть. Наша задача просто «натянуть» этот дизайн на код.

Снимок экрана 2014-06-20 в 16.28.39

Далее в первых строках нашего приложения вы видите некий класс ThemeManager. Он служит именно для того, чтобы быстро менять внешний вид всего приложения. Этот паттерн был показан помоему на WWDC 2012, и если кому-то будет интересно, я скажу название сессии. А также к ней есть исходный код. Хотя Apple и не приветствует всякого рода skins в своих приложениях, тем не менее иногда это бывает полезно. Apple в своем гайде по стилю пишет, что всегда старайтесь делать так, чтобы удовлетворить максиально широкую аудиторию всего одной настройкой, а не делать десяток,в которых пользователь утонет. Для чего этот ThemeManager может быть полезен?  Например, вы разрабатываете приложение, и еще не решили на какой варианте остановиться. Вы делаете два-три варианта и показываете их людям. С помощью этого метода вы можете делать разные соборки только меняя один из параметров в свойствах проекта.

Как это работает? Мы делаем singleton класс — ThemeManager который соответствует нашему же протоколу Theme. В этом протоколе мы указываем все-все-все параметры, которые мы планируем менять. В нашем случае это цвета текста, изображение задника, изображение navbar-a. Когда приложение стартует, то инициализирует один из классов, которые и реализуют наш протокол Theme. Также у менеджера есть общая часть, в которой можно прописать, например, все связанное с UIAppearance. Там же есть пример, как можно кастомизировать таблицу.

#import <UIKit/UIKit.h>

@protocol Theme <NSObject>

- (UIColor *)profileNameColor;
- (UIColor *)twitterNameColor;
- (UIColor *)tweetColor;
- (UIImage *)navigationBackgroundForBarMetrics:(UIBarMetrics)metrics;
- (UIImage *)backgroundImage;

@end

@interface ThemeManager : NSObject

+ (id <Theme>)sharedTheme;

+ (void)customizeAppAppearance;
+ (void)customizeTableView:(UITableView *)tableView;

@end

Едем дальше. В Photoshop я нарезал задник в двух разрешениях — для ретины и не для ретины. Задники получились просто огромных размеров. То есть два задника в сумме порядка 3,5 мегабайт. А потом я сделал еще и зеленый вариант для демонстрации. В результате наше приложение еще ничего не умеет, а уже весит не слабо. Если кто-то, кто меня читает знает, что с этим можно сделать — то милости просим в комментарии. Мое же мнение пока такое, что все переливающиеся вещи очень красивые, но с точки зрения пользователя, они очень затратны. Программист тоже мучается, пытаясь все это реализовать. Самым приемлемым вариантом мне кажется использовать некий паттерн рисунка, а затем делать из него заливку (что-то типа обоев, которые мы все любим клеить на стены). Вообщем, это место оставило у меня чувство некой неудовлетворенности.

В Storyboard я создал ViewController, который содержит UIImageView задника, а на нем прозрачная таблица с прозрачными клеточками. Там же сразу в Storyboard я создал макет нашей клеточки, содержащий все те же 5 элементов, что и наши данные. Я использовал AutoLayout для этой клеточки. Это помогло мне не рассчитывать два раза высоту блока с текстом твитта. Один раз я обязан это сделать при расчете высоты клетки в методе heightForRowAtIndexPath. После того, как я задал высоту, AutoLayout автоматически растягивает многострочный UILabel в моей клеточке.

Снимок экрана 2014-06-20 в 16.35.12

Я создал подкласс UITableViewCell, куда передаю NSDictionary, содержащий наши данные по одной клеточке. Далее я разбираю их по местам. В данном примере мне пришлось работать с методом objectForKey. В обычной практике, я стараюсь свести к минимум такой код. Так как компилятор не может проверить ни правописание вашего key, ни тип данных, который метод возвращает. Поэтому потенциально это очень неприятно. Куда удобнее было бы, если бы мы получали, например, объект Tweet унаследованный от  NSManagedObject, а в нем были бы нужные нам properties. Но для симуляции пока пойдет и так.

Хотелось бы отметить, что в коде клеточки мы обращаемся к нашему ThemeManager, чтобы получить цвет текста. Для скругления изображений мы пользуемся старым добрым setCornerRadius:20.0 но, начиная с iOS 7.1 мы обязаны также принудительно указывать clipsToBounds = YES для данного view. Также вы можете заметить, что у нас есть специальный метод, который находит в тексте гиперссылку, и согласно дизайна отрезает у нее «http://« часть, а также окрашивает ссылку в особый цвет. Также немного пришлось повозиться с межстрочным расстоянием. Оно регулируется с помощью добавления экземпляра NSMutableParagraphStyle к нашей attributed string. Обратите внимание, что ищем вхождение гиперссылки мы с помощью Apple-овского класса NSDataDetector. Рисовать свой сеператор между клеточками я не стал, а просто отодвинул его inset в InterfaceBuilder, чтобы он соответствовал дизайну.

-(NSAttributedString*)getAttributedTweet:(NSString*)tweet
{
    NSError *error = NULL;
    NSDataDetector *detector =
      [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:&error];

    NSArray *matches = [detector matchesInString:tweet
                                         options:0
                                           range:NSMakeRange(0, )];

    NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:tweet];

    for (NSTextCheckingResult *match in matches) {

        NSString *stringWithoutHttp = [[[match URL] absoluteString]
                                       stringByReplacingOccurrencesOfString:@"http://" withString:@""];
        [string replaceCharactersInRange:[match range] withString:stringWithoutHttp];
        NSRange oldRange = [match range];
        NSRange newRange = NSMakeRange(oldRange.location, oldRange.length-7);
        [string addAttribute:NSForegroundColorAttributeName
                       value:[UIColor colorWithRed:253.0/255.0 green:166.0/255.0 blue:118.0/255.0 alpha:1.0]
                       range:newRange];

    }

    [string addAttribute:NSParagraphStyleAttributeName value:paragrahStyle range:NSMakeRange(0, [string length])];

    return string;
}

Дальше я нарезал две кнопочки, которые на navigation bar. Дизайнер совершенно правильно сделал из размером 20×20 points. Но вот только, если мы создадим на их основе кнопки, то увидим, что они смещены чуть-чуть больше к центру, чем в нашем дизайне. У нас они гораздо ближе к краю экрана. Я оставил их как есть, потому что мне этот вариант показался более правильным. Я стараюсь всегда говорить дизайнер или заказчику, что это мне кажется более правильным. Если мы нарезали нужную картинку правильного размера, сделали кнопку по умолчанию, и поставили ее на панель, а она стоит не там, то может ее правильный вариант именно этот? Заказчик всегда барин, и он может сказать, а я хочу все-таки ближе к краю экрана. И тогда мы берем один из методов, и двигаем кнопку вбок, но зато мы высказали свои замечания, что кнопка слишком близко к краю, и это может быть не удобно пользователю. Ниже мы видим наложение двух изображений в фотошопе. Так я обычно проверяю, что соответствую дизайну.

Снимок экрана 2014-06-20 в 16.39.16

Что касается Favorites со стрелочкой вниз, то такого элемента у Apple не существует, и такой навигации тоже. Но заказчик хочет именно так. Тем более, что некоторые распространенные приложения используют это — например, ВКонтакте. При нажатии на кнопочку-заголовок, у нас выезжает таблица с вариантами, мы выбираем какой-то, таблица уезжает обратно, а мы обновляем таблицы с новыми данными, а также меняем текст в этой кнопке-заголовке. Это все сделано у меня с помощью двух классов NavBarTitleView и SectionsTableViewController.

NavBarTitleView создает view, на котором расположен текст текущего раздела и изображение стрелочки вниз. К этому вью прикручен UITapGestureRecognizer, благодаря которому, мы знаем, когда пользователь нажимает на наше view. Информацию о нажатии мы передаем в наш «главный» контроллер через делагата. Этот контроллер с помощью анимации показывает нам таблицу выбора разделов и прячет ее, если мы выбрали раздел или снова нажали на середину navigation bar-a. Фантазировать на тему внешнего вида выпадающего экрана не хотелось, поэтому оставил по умолчанию. Белый фон, черный текст. В идеале, это надо все было бы заменить на соответствующий дизайнерский вид.

Хотя у нас и заранее подготовленные данные, я переживал, что очень большое количество прозрачности скажется на быстродействии скролла нашей основной таблицы. Чтобы все проверить, когда уже было закончено приложение, я запустил его на телефоне 4S и с помощью Instruments замерил FPS скролла. Он был не 60, но 57-58, что в принципе нормально, но уже сейчас мы видим просадку. Это еще раз нам говорит о том, что все-таки лучше стараться использовать непрозрачность где только возможно.

Снимок экрана 2014-06-20 в 16.43.11

Если вы выставите в свойствах проекта в разделе Apple LVVM 5.1 — Preprocessing параметр  NEW_THEME = 1, то увидите зеленый вариант приложения, о чем я вам говорил в самом начале этой статьи.

Снимок экрана 20 июня 2014 г., 15.47.31 с Симулятора iOS

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

Полный проект FancyTwitter к этой неделе на github.com

Маленькое видео с работой приложения:

До следующей недели!

Реклама

12 недель. Неделя 1. FancyTwitter: 2 комментария

    • Не брошу 🙂 не переживайте. Просто чуть-чуть появились другие дела. все-таки надеюсь в воскресенье выложить! В крайнем случае понедельник!

      Ответить

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s