【问题标题】:Creating a custom slider using Sprite Kit - how do I pass a @selector?使用 Sprite Kit 创建自定义滑块 - 如何传递 @selector?
【发布时间】:2014-03-06 09:24:01
【问题描述】:

我正在开发的一个 Sprite Kit 游戏使用自定义滑块作为颜色选择器(颜色是从滑块轨迹图形中选择的,这是一个包含渐变的 UIImage)。

我研究过使用定制的UISlider,但标准的 IOS UI 控件不能很好地与 Sprite Kit 的场景配合使用:它们很难相对于场景的其余部分进行定位(因为它们作为主视图而不是作为SKScene 的一部分),它们会突然出现(而不是与场景的其余部分一起过渡),并且必须在退出场景时手动删除。简而言之,实施它们很痛苦,而且它们不能无缝集成。

我已经开始使用SKSpriteNodes 实现一个自定义滑块,以Grafexcellent SKButton class 为基础,并设置了滑块轨道和手柄。手柄沿着轨道左右滑动,并设置一个介于 0 和 1 之间的值(就像UISlider)。我已将此类称为SKSlider

我想做的是将SKSlider 传递给@selector,就像传递UISlider 一样,所以我可以在SKScene 中定义一个函数来执行滑块:

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

当滑块改变时我试图调用的函数如下所示:

-(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;        
}

(代码找到here,有兴趣的人。)

但我不确定应该如何在SKSlider 的界面中进行设置。有人能指出我正确的方向吗?

【问题讨论】:

    标签: ios objective-c selector sprite-kit


    【解决方案1】:

    选择器的变量类型是SEL。下面介绍如何声明属性以跟踪目标和操作。 (请注意,SEL 是指向结构的指针,而不是指向对象的指针,因此指定 strongweak 会扰乱编译器。)

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

    这是一个更新目标和动作的示例方法

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

    这就是你在目标上调用 action 方法的方式

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

    注意self是作为参数传递给方法的,所以target中的方法签名应该是

    - (void)someAction:(id)sender
    

    【讨论】:

    • reecon 打败了你(只是),但你的回答也很有用:赞成。
    【解决方案2】:

    只需在您的自定义滑块中实现缺少的方法。在界面中添加这个:

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

    并在实现中存储 targetaction 作为属性。

    @property (nonatomic, strong) id target;
    @property (nonatomic) SEL action;
    
    - (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
    {
        _target = target;
        _action = action;
    }
    

    然后在值更改时在target 上调用action

    objc_msgSend(_target, _action);
    

    记得导入:

    #import <objc/message.h>
    

    然后从滑块获取更新创建一个valueChanged 方法并添加它:

    - (void)valueChanged
    {
        CGFloat value = _yourSlider.value;
        // Do something with the value.
    }
    
    [_yourSlider addTarget:self action:@selector(valueChanged) forControlEvents: UIControlEventValueChanged];
    

    【讨论】:

    • 嗯,到了我想...但现在出现错误:Implicit conversion of an Objective-C pointer to 'SEL' (aka 'SEL *') is disallowed with ARCPerformSelector may cause a leak because its selector is unknown...
    • 我仍然收到 ARC 限制警告说不允许隐式转换:(
    • 非常接近了,我想!据我了解,我这样称呼它:[skinSlider addTarget:self action:@selector(getRGBAFromImage:atX:atY:) withObject:skinGradient withObject: skinSlider.value withObject: 0 forControlEvents:UIControlEventValueChanged];(传入变量),那我应该怎么改接口呢?
    • 不要将不应该在滑块中的逻辑放入其中。滑块是一个控件。它应该只是滑动并通知目标。然后,目标对象(可能是您的视图控制器或场景)应该处理该值并对其进行处理。我更新了我的答案。
    • 太棒了。这非常有效,而且你告诉了我很多新事物。一千个谢谢,赞成,接受等。
    猜你喜欢
    • 1970-01-01
    • 2020-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-21
    • 1970-01-01
    • 2014-04-01
    • 1970-01-01
    相关资源
    最近更新 更多