Frage

A Sprite Kit game I'm working on uses a custom slider to act as a color picker (the color is picked from the slider track graphic, which is a UIImage containing a gradient).

I looked into using a customised UISlider, but standard IOS UI controls don't play well with Sprite Kit's Scenes: they're difficult to position relative to the rest of the Scene (as they exist as a subview of the main View rather than as a part of a SKScene), they pop into existence (rather than transitioning with the rest of the Scene) and must be manually removed when exiting the scene. In short, implementing them is a pain, and they don't integrate seamlessly.

I've started implementing a custom slider using SKSpriteNodes, building on Graf's excellent SKButton class, and have the slider track and handle in place. The handle is sliding left and right along the track, and is setting a value between 0 and 1 (just like a UISlider). I've called this class SKSlider.

What I would like to do is pass the SKSlider a @selector, in much the same way as you would a UISlider, so I can define a function inside the SKScene for the slider to execute:

[mySlider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];

The function I'm trying to invoke when the slider's changed looks like this:

-(UIColor*)getRGBAFromImage:(UIImage*)image atX:(float)xp atY:(float)yp
{
    NSMutableArray *resultColor = [NSMutableArray array];   
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));

    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;

    CGContextRef context = CGBitmapContextCreate(rawData, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGColorSpaceRelease(colorSpace);



    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);

    CGContextRelease(context);

    // Now your rawData contains the image data in the RGBA8888 pixel format.

    int byteIndex = (bytesPerRow * yp) + xp * bytesPerPixel;
    CGFloat red   = (rawData[byteIndex]     * 1.0) /255.0;
    CGFloat green = (rawData[byteIndex + 1] * 1.0)/255.0 ;
    CGFloat blue  = (rawData[byteIndex + 2] * 1.0)/255.0 ;
    CGFloat alpha = (rawData[byteIndex + 3] * 1.0) /255.0;

    byteIndex += 4;

    UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];

    [resultColor addObject:color];

    NSLog(@"width:%i hight:%i Color:%@",width,height,[color description]);

    free(rawData);

    return color;        
}

(Code was found here, for those interested.)

But I'm not sure how I should set this up in the SKSlider's interface. Could someone point me in the right direction?

War es hilfreich?

Lösung 2

Just implement the missing method in your custom slider. Add this in the interface:

- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;

And in implementation store target and action as a properties.

@property (nonatomic, strong) id target;
@property (nonatomic) SEL action;

- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
{
    _target = target;
    _action = action;
}

Then call an action on a target when value changes:

objc_msgSend(_target, _action);

Remember to import:

#import <objc/message.h>

Then to get the updates from the slider create a valueChanged method and add it:

- (void)valueChanged
{
    CGFloat value = _yourSlider.value;
    // Do something with the value.
}

[_yourSlider addTarget:self action:@selector(valueChanged) forControlEvents: UIControlEventValueChanged];

Andere Tipps

The variable type for a selector is SEL. Here's how you would declare properties to keep track of the target and action. (Note that SEL is a pointer to a structure, not a pointer to an object, so specifying strong or weak will upset the compiler.)

@property (nonatomic, strong) id target;
@property (nonatomic) SEL action;

Here's a sample method that updates the target and action

- (void)changeTarget:(id)target action:(SEL)action
{
    self.target = target;
    self.action = action;
}

And this is how you call the action method on the target

[self.target performSelector:self.action withObject:self afterDelay:0.0];

Note that self is passed as an argument to the method, so the method signature in the target should be

- (void)someAction:(id)sender
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top