Главная » iPhone » Graphics Services iPhone

0

Всякий раз при получении события объект взаимодействует с платформой Graphics Services для получения детальной информации о событии. Платформа Graphics Services предоставляет множество различных функций расшифровки для извлечения информации о событии.

Местоположение события

Для событий одного касания функция GSEventGetLocationinWindow возвращает структуру CGPoint, содержащую координаты X, Y места, где произошло событие. Эти координаты, как правило, являются смещением относительно положения окна, которое получило событие. Например, если окно находится в нижней половине экрана, с координатами левого верхнего угла (0. 240), и событие получено в точке (0, 0), то это означает, что событие на самом деле произошло на экране в точке (0, 240), в которой расположен левый верхний угол (0, 0) окна.

Метод GSEventGetLocationinWindow возвращает структуру CGPoint, которую вы можете распаковать следующим образом:

CGPoint point = GSEventGetLocationinWindow(event); float x = point.x; float у = point.у;

Если используется касание двумя пальцами, то вы должны вызвать две отдельные функции, чтобы получить координаты окна для каждого пальца. Крайнее левое касание считается внутренним, а крайнее правое касание— внешним. Методы GSEventGetlnnerMostPathPosition И GSEventGetOuterMostPathPosition возвращают структуры CGPoint, содержащие координаты X и Г окна для каждого касания:

CGPoint leftFinger = GSEventGetlnnerMostPathPosition(event); CGPoint rightFinger = GSEventGetOuterMostPathPosition(event);

Когда ориентация iPhone является альбомной, эти позиции меняются местами:

int orientation = [ UIHardware deviceOrientation: YES ];

if (orientation == kOrientationHorizontalLeft I I orientation == kOrientationHorizontalRight)

{

leftFinger = GSEventGetOuterMostPathPosition(event); rightFinger = GSEventGetlnnerMostPathPosition(Event);

} •

Тип события

Тип события определяет, использовалось ли касание одним пальцем, скользил ли палец по экрану или был убран с экрана.

Большинство событий может быть легко определено посредством метода, который получил уведомление. Например, если палец коснулся экрана, то уведомляется метод mouseDown, тогда как в результате касания двумя пальцами уведомляется метод gesturestarted: unsigned int eventType = GSEventGetType(event);

Для события касания одним пальцем событие началось бы с одного опущенного пальца, а продолжилось бы всеми поднятыми пальцами (когда пользователь уберет палец с экрана). Касание двумя пальцами несколько сложнее. Оно начинается с одного опущенного пальца, и затем переходит в касание двумя пальцами. Если пользователь поднимает один палец, то тип события меняется на событие "один палец поднят", за ним следует событие "все пальцы подняты", когда пользователь убирает и второй палец.

События связаны со значениями типа событий так, как указано в табл. 4.1.

Таблица 4.1

Тип

Описание

1

Один палец опущен, включая первый палец в касании

2

Все пальцы подняты

5

Один палец поднят при касании двумя пальцами

6

Касание двумя пальцами

Событие аккорда

(события многократного касания)

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

Для определения количества пальцев, коснувшихся экрана в момент возникновения события, может использоваться метод GSEventlsChordingHandEvent: int eventChording = GSEventlsChordingHandEvent(event);

Эта функция возвращает значение 0, если произошедшее событие — событие касания одним пальцем, и значение 1, если это событие считается аккордом.

События мыши

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

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

Ginterface MyTable : UiTable {

)

-   (void) mouseDown:(struct _GSEvent *)event;

-   (void) mouseup:(struct _GSEvent *)event; @end

Поскольку базовый класс может также воспользоваться событием мыши, то вы захотите вызвать версию суперкласса метода либо до, либо после того, как обработаете событие:

-   (void) mouseDown:(struct _GSEvent *)event {

/* Обработка отпускания мыши */ [ super mouseDown: event ];

}

mouseDown

Метод mouseDown вызывается всякий раз, когда вы нажимаете одним пальцем на экран, включая и первое нажатие пальцем при двойном касании. Местоположение события представляет координаты, в которых произошло нажатие экрана в пределах окна объекта:

-   (void) mouseDown:(struct _GSEvent *)event {

CGPoint pointDown = GSEventGetLocationlnWindow(event);

/* Обработка отпускания мыши */ [ super mouseDown: event ];

)

mouseUp

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

-   (void) mouseUp:(struct _GSEvent *)event {

CGPoint pointUp = GSEventGetLocationinWindow(event);

[ super mouseUp: event ];

/* Проверка значения элемента управления и т. п. */

}

mouseDragged

Метод mouseDragged получает уведомление, если пользователь продолжает удерживать палец после отправки события mouseDown, и если палец перемещается со своего исходного положения на экране. Этот метод является аналогом функции перетаскивания на рабочем столе. Местоположение события представляет собой координаты точки, куда пользователь переместил свой палец прежде, чем убрать его с экрана:

-   (void) mouseDragged:(struct _GSEvent *)event {

CGPoint movedTo = GSEventGetLocationinWindow(event); .

[ super mouseDragged: event ]; /* Обработка перетаскивания мыши */

}

Этот метод следует за пальцем пользователя, поэтому он вызывается через определенные промежутки времени по мере перемещения пальца.

mouseEntered, mouseExited, mouseMoved

На рабочем столе эти методы уведомляют приложение о перемещениях указателя мыши внутри, за пределами или в пределах фрейма объекта при отсутствии щелчка кнопкой мыши. Поскольку в iPhone как таковой мыши нет, то ваше касание пальцем экрана рассматривается как щелчок мышью. Эти методы бесполезны для iPhone, но последующие мобильные устройства Apple, возможно, будут использовать мышь или трекбол.

События жестов

Когда пользователь переключается с касания одним пальцем на касание двумя пальцами, то это рассматривается как начало жеста (gesture). Это приводит к созданию событий жеста, которые могут быть перехвачены путем подмены соответствующих методов. Жесты представлены в базовом классе uiview. и только унаследовавшие от него объекты поддерживают их.

Порядок событий следующий: в момент начала жеста вызывается метод gestureStarted. Затем, если пользователь меняет положение своего пальца, вызывается метод gestureChanged для уведомления объекта о каждом новом положения жеста. При завершении жеста пользователем вызывается метод

gestureEnded.

Чтобы отправить события жеста, класс должен подменить метод canHandleGestures, который возвращает значение типа Boolean. Возвращая значение yes, вы приказываете iPhone отправить события:

-   (BOOL)canHandleGestures {

return YES;

}

gestureStarted

Метод gestureStarted получает уведомление, когда пользователь дотрагивается до экрана двумя пальцами или переходит от использования одного пальца к использованию двух. Этот метод является версией метода mouseDown для двух пальцев. Внутренние и внешние координаты соответствуют первой точке прикосновения к экрану. Возвращаемые положения события в структурах CGPoint представляют координаты точек, в которых произошли касания каждым пальцем:

-   (void)gestureStarted:(struct _GSEvent)event {

CGPoint leftFinger = GSEventGetlnnerMostPathPosition(event); CGPoint rightFinger = GSEventGetOuterMostPathPosition(event);

[ super gestureStarted: event ]; /* Обработка события начала касания */

}

gestureEnded

Метод gestureEnded является аналогом метода mouseup для двух пальцев и сообщает приложению, что пользователь убрал с экрана, по крайней мере, один палец. Если пользователь одновременно убирает оба пальца, то iPhone отправляет оба события методам gestureEnded и mouseup.. Если пользователь убирает пальцы поочередно, то поднятие первого пальца приводит к вызову метода gestureEnded, а второго — К вызову метода mouseUp.

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

-   (void)gestureEnded:(struct GSEvent)event {

CGPoint leftFinger = GSEventGetInnerMostPathPosition(event); CGPoint rightFinger = GSEventGetOuterMostPathPosition(event);

[ super gestureEnded: event ];

/* Обработка завершения жеста */

}

gestureChanged

Метод gestureChanged вызывается всякий раз, когда пользователь перемещает свои пальцы во время жеста. Этот метод является аналогом метода mouseDragged для двух пальцев. Когда это происходит, приложение должно переоценить положения пальцев в жесте и отреагировать соответствующим образом. Местоположения события представляют новые координаты, куда были передвинуты пальцы:

-   (void)gestureChanged:(struct _GSEvent)event (

CGPoint leftFinger – GSEventGetlnnerMostPathPosition(event); CGPoint rightFinger = GSEventGetOuterMostPathPosition(event);

[ super gestureChanged: event ]; /* Обработка события изменения жеста */

}

События строки текущего состояния

Строка состояния iPhone сама по себе является окном, способным получать события мыши. Приложение Safari создает прецедент действий, которые должны выполняться при таких событиях, т. е. когда основной вид прокручивается к началу. Класс uiApplication содержит три уведомления строки состояния, которые могут быть подменены в вашей программе.

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

-   (void)statusBarMouseDown:(struct _GSEvent *)event;

Если пользователь опускает палец и перемещает его в другое место, то метод statusBarMouseDragged получает уведомление с событием, содержащим координаты места на экране, к которому его перетащили:

-   (void)statusBarMouseDragged:(struct _GSEvent *)event;

Наконец, когда пользователь поднимает палец, метод statusBarMouseUp получает уведомление с событием, содержащим координаты точки отрыва пальца пользователя от экрана:

(void)statusBarMouseUp:(struct _GSEvent *)event;

Пример: перетаскивание значка

Этот пример создает на экране четыре значка и позволяет пользователю свободно их перемещать либо каждый по отдельности, либо по два сразу с помощью жеста. Тем самым иллюстрируется использование различных геометрических структур и функций, уведомлений событий и функций платформы Graphics Services. Чтобы подцепить значок, коснитесь его пальцем и не отпускайте, переместите, куда требуется, а затем отпустите палец. Если коснуться строки состояния, то значки вернутся на свои исходные позиции.

Чтобы скомпилировать этот пример из командной строки, помимо основных платформ вы должны будете использовать несколько других платформ: Core Graphics, Graphics, Services и UIKit:

$ arm-apple-darwin9-gcc -о MyExample MyExample.m -lobjc Ъ -framework CoreFoundation -framework Foundation -framework UIKit -framework CoreGraphics -framework GraphicsServices

Листинги 4.1 и 4.2 содержат файлы заголовков и исполняемые методы примера.

#impoгt <СогеFoundation/CoreFoundation.h> #import <UIKit/UIKit.h> #import <UIKit/UITextView.h>

@interface MainView : UlView

{

UIImage *images[4]; CGRect positions[ 4 ]; CGPoint offsets[4 ]; int dragLeft, dragRight;

}

-   (id)initwithFrame:(struct CGRect)windowRect;

-   (void)relnit;

-   (void)mouseDown: (struct _GSEvent *)event;

-   (void)mouseUp: (struct _GSEvent *)event;

-   (void)mouseDragged: (struct _GSEvent *)event;

-   (void)gestureStarted: (struct _GSEvent *)event;

-   (void)gestureEnded: (struct _GSEvent *)event;

-   (void)gestureChanged: (struct _GSEvent *)event;

-   (void)drawRect:(CGRect)rect; @end

@interface MyApp : UIApplication

{

UlWindow *window; MainView *mainView;

}

-   (void)applicationDidFinishLaunching:(NSNotification *)aNotification;

-   (void)statusBarMouseDown:(struct _GSEvent *)event; @end

#import <Foundation/Foundation.h> #import <CoreFoundation/CoreFoundation.h> #import <GraphicsServices/GraphicsServices.h> #import "MyExample.h"

int main(int argc, char **argv) {

NSAutoreleasePool *autoreleasePool = [ [ NSAutoreleasePool alloc ] init

1;

UIApplicationUseLegacyEvents(YES);

int returnCode = UIApplicationMain(argc, argv, @"MyApp", @"MyApp"); [ autoreleasePool release ]; return returnCode;

}

@implementation MyApp

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { window = [ [ UlWindow alloc ] initWithContentRect: [ UIHardware fullScreenApplicationContentRect ]

];

CGRect rect = [ UIHardware fullScreenApplicationContentRect ]; rect.origin.x = rect.origin.у = O.Of;

mainView = [ [ MainView alloc ] initWithFrame: rect ]; [ window setContentView: mainView ];

[ window orderFront: self ]; [ window makeKey: self ]; [ window _setHidden: NO ];

}

-   (void)statusBarMouseDown:(struct _GSEvent *)event {

[ mainView relnit ]; [ mainView setNeedsDisplay ];

}

@end

@implementation MainView

-   (id)initwithFrame:(struct CGRect)windowRect {

self = [ super initwithFrame: windowRect ]; if (nil != self) { int i;

images [0] = [ Ullmage

imageAtPath: /Applications/MobilePhone.app/icon.png" ]; images[1] = [ Ullmage

imageAtPath: @"/Applications/MobileMail.app/icon.png" ]; images[2] = [ Ullmage

imageAtPath: @"/Applications/MobileSafari.app/icon.png" ]; images[3] = [ Ullmage

imageAtPath: /Applications/MobileMusicPlayer.app/icon.png" ];

[ self relnit ];

}

return self;

}

-   (void)relnit {

positions[0] = CGRectMake(98, 178, 60, 60); positions[1] = CGRectMake(162, 178, 60, 60); positions[2] = CGRectMake(98, 242, 60, 60); positions[3] = CGRectMake(162, 242, 60, 60);

dragLeft = dragRight = -1;

}

-   (void)drawRect: (CGRect).rect {

float black[4] = { 0, 0, 0, 1 }; CGContextRef ctx = UlCurrentContext(); int i;

CGContextSetFillColor(ctx, black); CGContextFillRect(ctx, rect);

for(i=0;i<4;i++) {

[ images[i] drawlPartImagelnRect: positionsfi] ];

}

}

-   (void)mouseDown: (struct _GSEvent *)event {

CGPoint point = GSEventGetLocationlnWindow(event); int i;

for(i=0;i<4;i++) {

if (CGRectContainsPoint(positions[i], point)) { dragLeft = i;

offsets[i] = CGPointMake(point.x – positions[i].origin.x,

point.у – positions[i].origin.у) ;

}

}

}

-   (void)mouseUp: (struct _GSEvent *)event {

CGPoint point = GSEventGetLocationlnWindow(event); int i;

dragLeft = -1;

-   (void)mouseDragged: (struct _GSEvent *)event {

CGPoint point = GSEventGetLocationlnWindow(event); CGRect old; int i;

if (dragLeft != -1) {

old = positions[dragLeft];

positions[dragLeft].origin.x = point.x – offsets[dragLeft].x; positions[dragLeft].origin.у = point.у – offsets[dragLeft].у; [ self setNeedsDisplaylnRect: old ]; [ self setNeedsDisplaylnRect: positions[dragLeft] ];

)

}

-   (void)gestureStarted: (struct _GSEvent *)event {

CGPoint leftFinger = GSEventGetlnnerMostPathPosition(event); CGPoint rightFinger = GSEventGetOuterMostPathPosition(event); int i;

for (i=0;i<4;i++) {

if (CGRectContainsPoint(positions[i], leftFinger)) { dragLeft = i;

offsets[i] = CGPointMake(leftFinger.x – positions[i].origin.x,

leftFinger.у – positions[i].origin.у);

}

else if (CGRectContainsPoint(positions[i], rightFinger)) { dragRight = i;

offsets[i] = CGPointMake(rightFinger.x – positions[i].origin.x,

rightFinger.у – positions[i].origin.у);

}

}

}

-   (void)gestureEnded: (struct _GSEvent *)event {

CGPoint leftFinger = GSEventGetlnnerMostPathPosition(event);

CGPoint rightFinger = GSEventGetOuterMostPathPosition(event); int i;

dragLeft = dragRight = -1;

for (i=0;i<4;i++) {

if (CGRectContainsPoint(positions[i], leftFinger)) dragLeft = i;

else if (CGRectContainsPoint(positions[i], rightFinger)) dragRight = i;

f

}

- (void)gestureChanged: (struct _GSEvent *)event {

CGPoint leftFinger = GSEventGetlnnerMostPathPosition(event); CGPoint rightFinger = GSEventGetOuterMostPathPosition(event); CGRect old; int i;

if (dragLeft != -1) {

old = positions[dragLeft];

positions[dragLeft].origin.x=leftFinger.x – offsets[dragLeft].x; positions[dragLeft].origin.y=leftFinger.у – offsets[dragLeft].y; [ self setNeedsDisplaylnRect: old ]; [ self setNeedsDisplaylnRect: positions[dragLeft] ];

}

if (dragRight != -1) {

old = positions[dragRight]; positions[dragRight].origin.x

= rightFinger.x – offsets[dragRight].x; positions[dragRight].origin.у

= rightFinger.у – offsets[dragRight].у; [ self setNeedsDisplaylnRect: old ];

( self setNeedsDisplaylnRect: positions[dragRight] ];

}

}

- (BOOL)canHandleGestures { return YES;

}

@end

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

Вот как работает перемещение значков:

1.     При порождении приложения создается объект MainView, являющийся производным от uiview, и вызывается его метод initwithFrame. При этом инициализируются изображения и положения на экране четырех значков: Phone, Mail, Safari и iPod. Затем классу вида приказывается отобразить себя.

2.     Когда класс вида отобразится, вызывается метод drawRect этого класса. Это приводит к прорисовке на пустом поле экрана черного прямоугольника. Затем на экране по отдельности прорисовывается каждый значок с помощью методов класса Ullmage (более подробно обсуждается в главе 7).

3.     Когда для перемещения значка используется один палец, то первым вызывается метод mouseDown. Он проверяет, на какой значок нажал пользователь, и устанавливает его в переменной dragLeft объекта как перемещаемый значок. Дельта между тем, где пользователь нажал на значок, и левым верхним (исходным) углом значка, сохраняется, чтобы пример мог четко отследить ту часть значка, которую пользователь нажал пальцем.

4.      Когда палец пользователя перемещается, вызывается метод mouseDragged, который устанавливает положение значка в текущее положение пальца в соответствии с тем, в каком именно месте пользователь нажал на значок. Таким образом, если пользователь нажал в центр значка, значок перемещается так, что его центр следует за пальцем пользователя. Метод setNeedsDisplaylnRect вызывается, чтобы снова вызвать метод класса вида drawRect.

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

6. Если используются два пальца, методы жеста выполняют те же самые задачи, но обрабатывают положения обоих пальцев, позволяя тем самым двум значкам следовать за пальцами пользователя. Поскольку вы не знаете, будут ли пальцы опущены и подняты в том же самом порядке, то информация для левого и правого пальцев должна храниться отдельно. Обратите внимание, что опускание второго пальца заставляет отбросить информацию, сохраненную методом mouseDown, и заменить ее информацией, возвращаемой методом gesturestarted. Аналогично поднятие второго пальца заставляет отбросить информацию, сохраненную методом gesturechanged, и заменить ее информацией, возвращаемой методом mouseDragged.

Для дальнейшего изучения

Было бы неплохо изучить все различные методы, поддерживаемые в этих низкоуровневых классах. Проверьте следующие прототипы в папке include вашего пакета инструментов. Они могут находиться в папке /toolchain/sys/usr/ include: UIKit/UIResponder.h, UIKit/UIView.h, GraphicsServices/GraphicsServices.h и CoreGraphics/CGGeometry.h.

Источник: Здзиарски Дж. iPhone. Разработка приложений с открытым кодом: Пер„с англ. — 2-е изд., перераб. и доп. — СПб.: БХВ-Петербург, 2009. — 368 е.: ил.

По теме:

  • Комментарии