Jakiegoś specjalnego szału nie ma, generalnie koncepcje wydają się jakby skądś znajome. Więcej nieco mojej uwagi przykuły behaviory w podstawowym API np. do grawitacji, które mogą się podobać.
UITouch
właściwości
- faza (UITouchPhaseBegan, UITouchPhaseMoved, UITouchPhaseStationary, UITouchPhaseEnded – wyszliśmy poza ekran, UITouchPhaseCancelled – anulowane przez system np. alert)
- widok
- główny promień
- ilość naciśnięć
- timestamp
- tolerancja głównego promienia
- okno
- detektory gestów
metody
- locationInView
- previousLocationInView
UIEvent
właściwości
- typ zdarzenia
- podtyp
- timestamp
metody
- allTouches
- touchesForView (view | window | gestureRecognizer)
Hit Testing
UIView
- hitTest: touches withEvent: event
- pointInside: point withEvent: event
podklasy UIResponder:
- UIApplication
- UIWindow
- UIViewController
- UIView
- UIControl
UIResponder - metody łańcucha reponderów:
- canBecomeFirstResponder
- becomeFirstResponder
- canResignFirstResponder
- resignFirstResponder
- nextResponder
Application –> Window –> Hit-test View –> Superview –> ViewController –> Window –> Application
zdarzenie dotykowe: hit-test view ich nie przechwytuje
zdarzenia ruchu: zdarzenia “Motion Began” i “Motion Ended” nie są zaimplementowane
zdarzenia zdalnej kontroli: “Remote Control Received With Event” niezaimplementowane
komnikaty akcji: nil celem metody akcji
komunikaty menu edycyjnego: znajdują obiekt wykonujący metody
edycja tekstu: pierwszy responder
Zdarzenia dotykowe
handlery w UIResponder:
- touchesBegan: touches withEvent: event
- tochesMoved: touches withEvent: event
- touchesEnded: touches withEvent: event
- touchesCancelled: touches withEvent: event
Wyłączenie zdarzeń dotykowych:
UIView
- usunięcie z nadwidoku
- ustawienie opcji interakcji usera na “NO” (domyślnie niektóre kontrolki tak mają np. UIImageView) zakładka boczna, sekcja View –> User Interaction Enabled
- ustawienie propercji hidden na “YES”
- ustawienie Opaque na “NO” i Alpha na zero
- (void)touchesBegan: (NSSet *)touches withEvent: (UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView: _imageView];
if (CGRectContainsPoint(_imageView.bounds, touchLocation)) {
_moveImageView = YES;
_touchOffset = CGPointMake(touchLocation.x, touchLocation.y);
}
}
- (void) touchesMoved: (NSSet *)touches withEvent: (UIEvent *) event {
if (_movedImageView) {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView: _imageView];
CGPoint offsetLocation = CGPointMake(touchLocation.x – _touchOffset.x, touchLocation.y – _touchOffset.y);
CGPoint center = _imageView.center;
center.x += offsetLocation.x;
center.y += offsetLocation.y;
_imageView.center = center;
}
}
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *)event {
_moveImageView = NO;
}
- (void) touchesCancelled: (NSSet *)touches withEvent: (UIEvent *)event {
[self touchesEnded: touches withEvent: event];
}
Gesture recognizers
- Pan
- Rotate
- Tap
- Pinch
- LongPress (“touch and hold” powiedziałbym językiem MS)
- Custom
UIGestureRecognizer
- UIView* view
- UIGestureRecognizerState state
- BOOL enabled
- numberOfTouches
- locationInView: view
- locationOfTouchIndex: touchIndex inView: view
UIPanGestureRecognizer
- NSUInteger minimumNumberOfTouches
- NSUInteger maximumNumberOfTouches
- velocityInView: view
- translationInView: view
- setTranslation: translation inView: view
gesture recognizer – stan:
- discrete gestures (szybkie) np. tap
- Recognized <- Possible –> Failed
- continuous gestures (więcej ruchu) np. pan, pinch, rotation
- Possible –> Began –> Changed (x n)
- Began, Changed –> Ended, Cancelled
- Possible –> Failed
- (IBAction)pan: (UIPanGestureRecognizer*)pan { /*pan.state */ }
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(myPanGesture:)];
[_imageView addGestureRecognizer:panGesture];
- (void)myPanGesture: (UIPanGestureRecognizer*)pan {
switch (pan.state) {
can UIGestureRecognizerStateChanged: {
CGPoint offset = [pan translationInView: pan.view];
CGPoint center = pan.view.center;
center.x += offset.x;
center.y += offset.y;
pan.view.center = center;
[pan setTranslation: CGPointZero inView: pan.view];
}
break;
default:
break;
}
}
zoom-in & zoom-out:
- (IBAction)scaleView: (UIPinchGestureRecognizer*)pinch {
switch (pinch.state) {
case UIGestureRecognizerStateChanged: {
CGAffineTransform currentTransform = pinch.view.superview.transform;
CGAffineTransform scale = CGAffineTransformScale(currentTransform, pinch.scale, pinch.scale)
pinch.view.superview.transform = scale;
pinch.scale = 1;
}
break;
default:
break;
}
}
wyszukiwarka kontrolek: Pinch Gesture Recognizer, przeciągamy np na ImageView, przeciągamy w View Controller Scene na View Controller, zaznaczamy scaleView:
obrót:
- (void)rotateView: (UIRotationGestureRecognizer*)rotate {
switch (rotate.state) {
case UIGestureRecognizerStateChanged: {
rotate.view.superview.transform = CGAffineTransformRotate(rotate.view.superview.transform, rotate.rotation);
rotate.rotation = 0;
}
break;
default:
break;
}
}
tap:
tapGesture.numberOfTapsRequired = 2;
…
- (void) resetView: (UITapGestureRecognizer*) tap {
if (tap.state == UIGestureRecognizerStateRecognized] {
[UIView animateDuration: 0.25 animations: ^{
tap.view.superview.transform = CGAffineTransformIdentity;
tap.view.center = self.view.center;
}]
}
}
poprawka: obrazek w storyboard: Editor –> Embed In View
UIGestureRecognizer Delegate
gestureRecognizer: recognizer shouldRecognizeSimultaneouslyWithGestureRecognizer: otherRecognizer /* return YES */
gestureRecognizerShouldBegin: recognizer
gestureRecognizer: recognizer shouldReceiveTouch: touch
gestureRecognizer: recognizer shouldRequireFailureOfGestureRecognizer: otherRecognizer
gestureRecognizer: recognizer shouldRequiredToFailByGestureRecognizer: otherRecognizer
multi-touch
różne kontrolki & gesture recognizers
- jeden palec, jeden tap – np. button
- jeden pan jednocześnie ze swipe – np. slider
mozna to nadpisać w klasie pochodnej
obsługa gestów z animacjami
Zdarzenia ruchu
Sensory:
- żyroskop
- akcelerometr
- magnetometr
UIResponder:
- motionBegan: motion withEvent: event
- motionEnded: motion withEvent: event
- motionCancelled: motion withEvent: event
- (void) motionEnded: (UIEventSubtype) motion withEvent: (UIEvent *) event {
if (motion == UIEventSubtypeMotionShake) {
…
}
}
Core Motion
- CMMotionManager
- CMAccelerometerData
- CMGyroData
- CMMagnetometerData
- CMDeviceMotion
behaviory (grawitacja, kolizje itp.)
//setup
self.motionManager = [[CMMotionManager alloc] init];
if (self.motionManager.deviceMotionAvailable) {
…
}
//stop
if (self.motionManager.deviceMotionActive) {
[self.motionManager.stopDeviceMotionUpdates]
}
self.motionManager = nil
CMDeviceMotion
- userAcceleration (G - przysp. ziemskie)
- gravity (G)
- rotationRate (radiany / s)
- magneticField (uT)
- attitude (kąty Euler’a: Roll, Pitch, Yaw / matryca rotacji / quaterniony)
Push
- specjalizowane aplikacje
- zbieranie danych
//setup
self.motionManager.deviceMotionUpdateInterval = 1.0 / 60.0;
[self.motionManager startDeviceMotionUpdatesToQueue: [NSOperationQueue mainQueue] withHandler: ^(CMDeviceMotion *motion, NSError *error) { … }
Pull
- aktualizacja UI
- gry
- rozszerzona rzeczywistość
CADisplayLink – synchronizuje
//viewDidLoad
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector(update:)];
[displayLink addToRunLoop: [NSRunLoop mainRunLoop] forMode: NSDefaultRunLoopMode];
- (void) update: (CADisplayLink*) displayLink {
if (self.motionManager.deviceMotionActive) {
CMDeviceMotion *motion = self.motionManager.deviceMotion;
if (motion != nil) {
CGVector *newGravityVector = CGVectorMake(motion.gravity.x * 5, -motion.gravity.y * 5);
self.gravityBehavior.gravityDirection = newGravityVector;
[self.itemBehavior addLinearVelocity: CGPointMake(motion.userAcceleration.x * 200,
motion.userAcceleration.y * 200) forItem: self.imageView];
}
}
}
//setup
[self.motionManager startDeviceMotionUpdates] //zamiast startDeviceMotionUpdatesToQueue
Brak komentarzy:
Prześlij komentarz