sobota, 16 stycznia 2016

Dotyk i ruch w iOS

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

  1. CMMotionManager
  2. CMAccelerometerData
  3. CMGyroData
  4. CMMagnetometerData
  5. 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: