Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Как написать «скорочиталку» для iOS за 30 мин

Anna | 2.07.2014 | нет комментариев

Прочитав на прогре посты про скорочтение QuisyReader и 500 слов в минуту без подготовки, захотелось реализовать данную идею для телефонов Apple своими силами. Для этого я разработал API, начальные коды, которого опубликованы на github.

О тезисе функционирования API и о том, как сделать программу для скорочтения на его основе, я расскажу под катом

Как это работает?

За основу сделанного API был взят правило работы Spritz и его способ окрашивания и позиционирования слов.
Вначале API запускает повторяющийся таймер, срабатывающий несколько раз в секунду. Таймер вызывает способ, тот, что запрашивает очередное слово для отрисовки у своего источника данных. Позже приобретения желанного слова нам необходимо узнать позицию буквы, которую будем раскрашивать. С поддержкой эмпирических исследований удалось установить, что буквы раскрашиваются дальнейшим образом:

  • Длина слова 1. Раскрашиваемая буква 1.
  • Длина слова 2-5. Раскрашиваемая буква 2.
  • Длина слова 6-9. Раскрашиваемая буква 3.
  • и т.д.

Соответственно позиция требуемой буквы вычисляется по примитивной формуле:

(([word length]   6) / 4) - 1;

Зная позицию, используем NSAttributedString для окрашивания букв в различные цвета, черный для основного слова и алый для акцентируемой буквы.
Сейчас нужно рассчитать координаты центра требуемой буквы. Для этого подсчитываем ширину символов с поддержкой способа sizeWithFont: либо sizeWithAttributes: в зависимости от версии iOS.
Дело за малым создаем UILabel, помещаем в него NSAttributedString и устанавливаем фрейм с шириной рассчитанной для выбранного шрифта, с поддержкой всё тех же способов. Полученный UILabel и позицию центра акцентируемой буквы передаем классу RRTargetView, тот, что занимается отрисовкой мишени, помогающей сосредоточить внимание на требуемой букве, и позиционированием UILabel в пределах этой мишени.

Пишем свой Reader

Сейчас чуть подробнее об API, опубликованном на github, тот, что будем применять для реализации нашей задачи.
Класс RRViewController отвечает за образование строки, которая будет отрисовываться. У класса есть следующие публичные свойства и способы:

Запуск/приостановка чтения.

- (void)startReading;
- (void)pauseReading;

Метаморфоза скорости чтения, путем передачи негативного либо правильного значения. Скорость измеряется в словах в минуту.

- (void)changeSpeed:(int)speedModification;

Метаморфоза размера шрифта, также задается негативным либо позитивным значением, касательно нынешнего размера. Заданы пороговые значения от 16 до 100.

- (void)changeFont:(int)fontModification;

А также два свойства хранящие ссылку на объекты, которые реализуют Delegate и DataSource протоколы класса RRViewController.

@property (nonatomic, weak) id <RRViewControllerDataSource> dataSource;
@property (nonatomic, weak) id <RRViewControllerDelegate> delegate;

Отрисовка мишени и позиционирование текста выполняется преемником UIView классом RRTargetView. У класса один публичный способ и одно качество.
Устанавливает точку в диапазоне от 0.0 до 1.0 в которой отрисовывается вертикальная засечка у мишени, текст позиционируется касательно этой точки. Значение по умолчанию равно 1/3.

@property (nonatomic) CGFloat horizontalAccentPosition;

Способ принимает UILabel с текстом. AccentPoint — это точка которая будет совмещена с вертикальной засечкой.

- (void)positionLabel:(UILabel *)label withAccentPoint:(CGPoint)point;

Пример на изображении

Также имеется два протокола.
Протокол RRViewControllerDelegate

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

- (void)reportFontSize:(CGFloat)size;
- (void)reportReadingSpeed:(NSUInteger)speed;

Протокол RRViewControllerDataSource
Опциональные способы:

- (NSString *)longestWordWithFont:(UIFont *)font;

Способ возвращает RRViewController’у самое длинное слово в тексте, оно нужно для работы системы механического подбора размера шрифта. Также для работы системы механического подбора текста, необходимо в [NSUserDefaults standardUserDefaults] установить булево значение YES для ключа auto_text_size.

- (NSString *)previousWord;

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

Два непременных способа:

- (NSString *)nextWord;

RRViewController запрашивает у модели данных следующее слово для отображения.

- (NSString *)currentWord;

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

Ну а сейчас напишем свою читалку.
Для начала создаем план (Single View Application), даём ему благозвучное имя, скажем, Super Fast Reader.

Сейчас экспортируем в план API, тот, что скачиваем с github, он будет заниматься отрисовкой текста.

Открываем Storyboard, где присутствует UIViewController, сделанный по умолчанию. Добавляем в него контейнер, в качестве класс контроллера, размещенного в контейнер, указываем RRViewController. Также нам потребуются элементы для управления и ввода текста. Добавим кнопки «Старт», «Пауза», поле для ввода текста UITextView, UIView, в тот, что будут размещены все элементы управления для их группировки, а также UIScrollView в тот, что мы разместим контейнер и UIView с элементами управления. Сейчас объединяем эти элементы с кодом приложения. Создаем IBOutlet для UItextView и UIScrollView и два IBAction для обработки нажатий кнопок «Старт» и «Пауза».

@property (weak, nonatomic) IBOutlet UITextView *textView;
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;

- (IBAction)startReading:(UIButton *)sender;
- (IBAction)pauseReading:(UIButton *)sender;

Представление в Storyboard

Иерархия видов

Настало время для работы с RRViewController.
Первое, что нужно сделать, это получить на него ссылку. При создании контейнера был механически сделан «Embed segue», назначим ему имя через InterfaceBuilder, скажем, RVCBecomesChild. В момент исполнения программы, при добавлении RRViewController в контейнер будет вызван способ prepareForSegue:sender:, чем мы и воспользуемся.

Вначале создаем качество, в котором будет хранится ссылка на объект:

@property (weak, nonatomic) RRViewController *readingVC;

Сейчас реализуем способ:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"RVCBecomesChild"]) {
        self.readingVC = segue.destinationViewController;
    }
}

Ссылка на контроллер есть. Что дальше?
А дальше нужно реализовать непременные способы протокола RRViewControllerDataSource для класса RRViewController:

- (NSString *)nextWord;
- (NSString *)currentWord;

Первое, что нам нужно, осведомить RRViewController’у о том, что мы являемся его источником данных.

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.readingVC.dataSource = self;
}

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

Послесловие

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

Славного скорочтения!

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB