Как программно смоделировать жест смахивания? - PullRequest
4 голосов
/ 15 февраля 2011

В настоящее время я пытаюсь написать несколько приемочных тестов для нашего нового приложения для iOS, используя frank (и, в свою очередь, UISpec ). В то время как фреймворк поддерживает касания как основной способ взаимодействия с представлениями, в настоящее время он не поддерживает более жесты (например, пинч, пролистывание и т. Д.). Мне нужно добавить поддержку смахивания, по крайней мере, потому что это ядро ​​функциональности нашего приложения, и наши тесты будут довольно бесполезны без него.

Реализация этого должна быть довольно простой, если я смогу найти способ имитировать события в Какао. Можно использовать жесты смахивания, если вы используете платформу Apple UIAutomation ( см. Здесь ), так что есть пример чего-то, что генерирует эти события извне. Я искал в Интернете, но не нашел ни одного примера того, как люди это делали (хотя была ветка , где кто-то просил что-то похожее на это ...).

Заранее большое спасибо за вашу помощь / идеи ...

1 Ответ

6 голосов
/ 16 февраля 2011

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

Во всяком случае, для всех, кто пытается сделать что-то подобное. Я основал свое решение на API, подробно описанном в этого поста - я записал последовательность событий, которую хотел смоделировать, затем воспроизвел их. Единственная загвоздка в том, что я не смог заставить работать встроенный API воспроизведения (я получил тот же сбой, который упоминался в комментариях внизу). Спустя некоторое время, копаясь в земле ASM, я закончил тем, что написал свою собственную версию.

@implementation UIApplication (EventReplay)

///
/// - replayEventsFromFile:
///
- (void)replayEventsFromFile:(NSString *)filename 
{
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
  NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:filename];
  NSArray* eventList = [[NSArray arrayWithContentsOfFile:filePath] retain];
  [self replayEvents:eventList];
}

///
/// - replayEvents:
///
- (void)replayEvents:(NSArray *)events
{
  if (!events.count)
    return;

  NSDictionary *eventDict = [events objectAtIndex:0U];
  GSEventRef thisEvent = GSEventCreateWithPlist((CFDictionaryRef)eventDict);

  uint64_t eventTime = thisEvent->record.timestamp;
  thisEvent->record.timestamp = mach_absolute_time();

  mach_port_t appPort = GSCopyPurpleNamedPort([[[NSBundle mainBundle] bundleIdentifier] UTF8String]);
  GSSendEvent(&thisEvent->record, appPort);
  mach_port_deallocate(mach_task_self(), appPort); 

  if (events.count <= 1)
    return;

  NSIndexSet *remainderIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, events.count - 1)];
  NSArray *remainingEvents = [events objectsAtIndexes:remainderIndexes];

  GSEventRef nextEvent = GSEventCreateWithPlist((CFDictionaryRef)[remainingEvents objectAtIndex:0U]);
  NSTimeInterval nextEventDelay = GetTimeDelta(nextEvent->record.timestamp, eventTime);

  if (nextEventDelay > 0.05)
    [self performSelector:@selector(replayEvents:) withObject:remainingEvents afterDelay:nextEventDelay];
  else
    [self replayEvents:remainingEvents];

  CFRelease(nextEvent);
  CFRelease(thisEvent);
}

@end

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

В любом случае, надеюсь, это поможет кому-то еще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...