C4: Add panning to an object other than “self”

2019-05-15 12:07发布

问题:

I watched the C4 tutorial on adding a pan gesture to an object and animating it to return to its original position when the panning is finished. I'm trying to add this to three individual objects. I have it working with one object so far to move it and reset it to a CGPoint, but for it to work, I have to add the pan gesture to "self", not the object. For reference, I'm pretty much using the code from here:

http://www.c4ios.com/tutorials/interactionPanning

If I add the gesture to the object itself, sure, it pans around, but then it just leaves itself at the last touch location. However, I'm assuming that leaving the gesture on "self" will affect more than just the object I want to move, and I want to be able to move the three objects individually.


I'm using roughly the same modification to the "move" method that's used in the example:

-(void)move:(UIPanGestureRecognizer *)recognizer { 
    [character move:recognizer]; 
    if (recognizer.state == UIGestureRecognizerStateEnded) { 
        [character setCenter: charStartOrigin]; 
    } 
} 

And then a new method to spawn the object:

-(void)createCharacters { 
    character = [C4Shape ellipse:charStart]; 
    [character addGesture:PAN name:@"pan" action:@"move:"]; 
    [self.canvas addShape:character]; 
}

回答1:

The example link you are working from is sneaky. Since I knew that there was only going to be one object on the canvas I knew I could make it look like I was panning the label. This won't work for multiple objects, as you have already figured out.

To get different objects to move independently, and recognize when they are done being dragged, you need to subclass the objects and give them their own "abilities".

To do this I:

  1. Subclass C4Shape
  2. Add custom behaviour to the new class
  3. Create subclassed objects on the canvas

The code for each step looks like the following:

subclassing

You have to create a subclass that gives itself some behaviour. Since you're working with shapes I have done it this way as well. I call my subclass Character, its files look like this:

Character.h

#import "C4Shape.h"

@interface Character : C4Shape
@property (readwrite, atomic) CGPoint startOrigin;
@end

I have added a property to the shape so that I can set its start origin (i.e. the point to which it will return).

Character.m

#import "Character.h"

@implementation Character

-(void)setup {
    [self addGesture:PAN name:@"pan" action:@"move:"];
}

-(void)move:(UIGestureRecognizer *)sender {
    if(sender.state == UIGestureRecognizerStateEnded) {
        self.center = self.startOrigin;
    } else {
        [super move:sender];
    }
}

@end

In a subclass of a C4 object, setup gets called in the same way as it does for the canvas... So, this is where I add the gesture for this object. Setup gets run after new or alloc/init are called.

The move: method is where I want to override with custom behaviour. In this method I catch the gesture recognizer, and if it's state is UIGestureRecognizerStateEnded then I want to animate back to the start origin. Otherwise, I want it to move: like it should so I simply call [super move:sender] which runs the default move: method.

That's it for the subclass.

Creating Subclassed Objects

My workspace then looks like the following:

#import "C4WorkSpace.h"
//1
#import "Character.h"

@implementation C4WorkSpace {
    //2
    Character *charA, *charB, *charC;
}

-(void)setup {
    //3
    CGRect frame = CGRectMake(0, 0, 100, 100);

    //4
    frame.origin = CGPointMake(self.canvas.width / 4 - 50, self.canvas.center.y - 50);
    charA = [self createCharacter:frame];
    frame.origin.x += self.canvas.width / 4.0f;
    charB = [self createCharacter:frame];
    frame.origin.x += self.canvas.width / 4.0f;
    charC = [self createCharacter:frame];

    //5
    [self.canvas addObjects:@[charA,charB,charC]];
}

-(Character *)createCharacter:(CGRect)frame {
    Character *c = [Character new];
    [c ellipse:frame];
    c.startOrigin = c.center;
    c.animationDuration = 0.25f;
    return c;
}

@end

I have added a method to my workspace that creates a Character object and adds it to the screen. This method creates a Character object by calling its new method (I have to do it this way because it is a subclass of C4Shape), turns it into an ellipse with the frame I gave it, sets its startOrigin, changes its animationDuration.

What's going on with the rest of the workspace is this (NOTE: the steps are marked in the code above):

  1. I #import the subclass so that I can create objects with it
  2. I create 3 references to Character objects.
  3. I create a frame that I will use to build each of the new objects
  4. For each object, I reposition frameby changing its origin and then use it to create a new object with the createCharacter: method I wrote.
  5. I add all of my new objects to the canvas.

NOTE: Because I created my subclass with a startOrigin property, I am able within that class to always animate back to that point. I am also able to set that point from the canvas whenever I want.



标签: panning c4