【问题标题】:Custom UIButton drawing - stays depressed after touchesEnded自定义 UIButton 绘图 - touchesEnded 后保持郁闷
【发布时间】:2011-09-20 08:11:06
【问题描述】:

我已经基于Ray Wenderlich's Tutorial 制作了一个自定义的零图像、Core Graphics 绘制的 UIButton(唯一的修改是 CoolButton 的 drawRect: 方法,更改了绘图代码),它在大多数情况下都很好用。但是,有时当我点击它很短的时间时,它会一直处于沮丧状态,并且不会恢复正常。

从这里开始,让它恢复正常状态的唯一方法是长按。简单的点击意味着它一直处于压抑状态。

要注意的另一件事是,我已将 Touch Up Inside 与一系列长方法挂钩 - 我认为完成所需的时间不会超过 0.1 秒。我什至在连接到 Touch Up Inside 的 @selector 中使用了 dispatch_async,所以我认为 UI 更新不应该有延迟。


我在drawRect: 中添加了一个NSLog,通常每次按下按钮都会触发 3 次,每次按下按钮都会改变UIControlState 的位置:

  • 对于某些短按,它会变为突出显示、突出显示、正常
  • 对于长按,它是高亮显示、正常、正常

但是,对于非常短的按下,它只会触发两次,突出显示 -> 突出显示。

当长按恢复正常时,它会变为 H、N、N。


这让我困惑了一段时间,我无法弄清楚为什么短按只会触发两次drawRect:,或者为什么touchesEnded: 似乎没有调用drawRect:。也许touchesEnded: 没有开火?

我真的希望有人可以提供帮助。

【问题讨论】:

  • 不使用 GCD 时是否有效?
  • 无法评论为什么它没有发生,但每次从头开始重新绘制以进行修饰/触地得分可能不是一个好主意。为什么不生成一个 UIImage,缓存它并使用它呢?从性能的角度来看要好得多,就像一开始就使用图像一样。
  • 一个按下的按钮 :)) 这应该是一个模因:P

标签: iphone objective-c uibutton core-graphics


【解决方案1】:

如果您真的想在运行时生成按钮图像,请在加载按钮时生成它们。然后使用

将它们添加到不同的状态
[button setImage:btnImage forState:UIControlStateNormal];

您始终可以使用以下命令将视图转换为图像:http://pastie.org/244916

不过,我确实建议您事先制作图像。如果您不想使用 Photoshop,还有很多选择。即将到来的pixelmator 更新看起来很温文尔雅,而且价格便宜得离谱!

【讨论】:

  • 谢谢。我一直在等待 Pixelmator 2,我同意,看起来很棒。我会试试看,看看效果如何。
  • 如果无法找到以前存储的生成图像,您认为是否可以仅在运行时绘制?这样,当我希望它每次生成时,我都可以设置一个BOOL,但是当我完成对绘图代码的更改时,我可以将它重新设置并让它每次都查找图像。如果这是有道理的:)
  • 当然可以。要检查是否可以找到图像,请使用以下命令:
  • NSString * appPath = [[NSBundle mainBundle] resourcePath]; NSString * file = [appPath stringByAppendingPathComponent:@"filename.png"]; BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:file];
  • 哦,我明白你在说什么了!是的好主意,我认为用“documentsPath”替换“resourcePath”(我不记得了)。网上应该有很多关于如何保存/读取/检查文件目录中是否存在文件的教程:)
【解决方案2】:

嗯,嗯,这很容易。 0.15 秒延迟有效,0.1 无效。

【讨论】:

  • 这不是一个很好的解决方案。时间取决于处理器速度等 - 因此此“修复”仅在某些情况下有效。如果我是你,我会找到一个与等待一定时间无关的解决方案:)
【解决方案3】:

正如其他人所说,您可以简单地生成图像并将其用作背景(如果图像是静态的)。无需 Photoshop,您只需生成一次图像,然后拍摄快照,然后将图像剪切(使用 Anteprima)并将其保存为 png 文件 :)

但是,由于您说按钮连接到一些长方法,这可能是按钮保持按下状态的原因:如果您没有在后台调用这些方法,那么按钮将保持按下状态,因为所有任务都已结束。尝试(进行测试)用一种简单的方法(比如NSLog 某事)连接按钮并检查它是否保持按下状态。如果没有,我建议在后台分离您的方法。

【讨论】:

    【解决方案4】:

    我也遇到了类似的问题,当我自定义 drawRect 方法时,UIButton 似乎停留在一个状态。我的预感是按钮的状态在调用 drawRect 之前不止一次改变。所以我只是添加了一个自定义属性,该属性只能由在 touchDown 和 touchUpInside 事件期间调用的方法设置。由于其他操作阻塞了主线程,我不得不调度线程来执行此操作,从而导致 redrawHighlighted 方法出现延迟。

    这可能有点混乱,但这对我有用:

    // CustomButton.h
    @interface CustomButton : UIButton
    @property (atomic) BOOL drawHighlighted;    
    
    // CustomButton.m
    @implementation CustomButton
    @synthesize drawHighlighted = _drawHighlighted;
    
    - (id)initWithFrame:(CGRect)frame
    {
        if ((self = [super initWithFrame:frame]))
        {
            _drawHighlighted = NO;
    
            [self addTarget:self action:@selector(redrawHighlighted) forControlEvents:UIControlEventTouchDown];
            [self addTarget:self action:@selector(redrawNormal) forControlEvents:UIControlEventTouchUpInside];
            [self addTarget:self action:@selector(redrawNormal) forControlEvents:UIControlEventTouchDragExit];  
        }
        return self;
    }
    
    - (void)drawRect:(CGRect)frame
    {
        // draw button here
    }
    
    - (void)redrawNormal
    {
        [NSThread detachNewThreadSelector:@selector(redrawRectForNormal) toTarget:self withObject:nil];
    }
    
    - (void)redrawHighlighted
    {
        [NSThread detachNewThreadSelector:@selector(redrawRectForHighlighted) toTarget:self withObject:nil];
    }
    
    - (void)redrawRectForNormal
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        _drawHighlighted = NO;  
        [self setNeedsDisplay];
    
        [pool release];
    }
    
    - (void)redrawRectForHighlighted
    {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        _drawHighlighted = YES; 
        [self setNeedsDisplay];
    
        [pool release];
    }
    

    【讨论】:

    • 我很好奇为什么这没有解释就被否决了。
    【解决方案5】:

    我发现的另一个便宜但有效的替代方法是创建一个drawRect:它不做任何突出显示,并且在用户与按钮交互时简单地改变按钮子类的 alpha 属性。

    例如:

    - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
    {
        self.alpha = 0.3f;
        return [super beginTrackingWithTouch:touch withEvent:event];
    }
    
    - (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
    {
        self.alpha = 1.0f;
        [super endTrackingWithTouch:touch withEvent:event];
    }
    
    - (void)cancelTrackingWithEvent:(UIEvent *)event
    {
        self.alpha = 0.3f;
        [super cancelTrackingWithEvent:event];
    }
    
    - (void)drawRect:(CGRect)rect
    {
        // Your drawing code here sans highlighting
    }
    

    【讨论】:

      猜你喜欢
      • 2023-01-13
      • 2015-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-15
      • 2012-05-31
      • 2015-09-22
      • 2012-07-08
      相关资源
      最近更新 更多