web-dev-qa-db-ja.com

iOS-UITableViewCellのUIButtonの遅延「タッチダウン」イベント

次のように初期化されるカスタムUITableViewCellがあります。

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
        self = [nibArray objectAtIndex:0];

        [self setSelectionStyle:UITableViewCellSelectionStyleNone];

        [self.downButton setBackgroundImage:[UIImage imageNamed:@"button"] forState:UIControlStateNormal];
        [self.downButton setBackgroundImage:[UIImage imageNamed:@"buttonSelected"] forState:UIControlStateHighlighted];
    }
    return self;
}

ボタンは適切な背景画像とともに適切に表示されますが、強調表示された画像はボタンが押された/クリックされたときに瞬時に表示されません。代わりに、変更が発生する前に1〜2秒間押し続ける必要があります。一方、ボタンを離すと、元の背景画像に戻るinstant変更が行われます。

強調表示された画像に切り替えるときに遅刻の変化を緩和しようとして、次の方法で変更を加えました。

- (IBAction)downDown:(id)sender {
    [self.downButton setBackgroundColor:[UIColor redColor]];
}

上記の方法は「Touch Down」(より一般的な「Touch Up Inside」とは反対)に設定されており、setBackgroundImage:forState:強調表示された状態。上記と同じ問題。色は最終的に赤に変わりますが、ボタンをクリックして1、2秒間押した後のみです。

「Touch Up Inside」が発生したときに呼び出されるボタンのメソッドがあり、そのメソッドは問題なく実行されます-ボタンをすばやくタップするか、リリースする前にしばらくクリックして長押しするかに関わらず。

それでは、なぜ「タッチダウン」またはUIControlStateHighlightedの遅延なのでしょうか?ボタンが押されたことを示すために、ユーザーに即座にフィードバックを提供しようとしています。

必要に応じてより多くのコードを提供できますが、これらは背景の外観に関係する唯一のビットです。

39
Birrel

これは、UIScrollViewプロパティdelaysContentTouchesが原因です。

NO自体のプロパティをUITableViewに設定するだけで十分でしたが、別のUIScrollViewに含まれていないテーブルのサブビューでのみ機能します。

UITableViewCellsにはiOS 7の内部スクロールビューが含まれているため、ボタンが含まれるすべてのセルのセルレベルでこのプロパティの値を変更する必要があります。

ここにあなたがする必要があるものがあります:

1.in viewDidLoadまたはUITableViewが初期化されたらどこかに似た場所に、これを入れます:

self.tableView.delaysContentTouches = NO;

2. iOS 7サポートの場合、UITableViewCellinitWithStyle:reuseIdentifier:またはinitWithCoder:(NIBの場合)、これを最後に入力します。

for (UIView *currentView in self.subviews)
{
    if([currentView isKindOfClass:[UIScrollView class]])
    {
        ((UIScrollView *)currentView).delaysContentTouches = NO;
        break;
    }
}

Appleは将来、セル内のビュー階層を再び変更できる可能性があります(おそらく、スクロールビューを別のレイヤーに移動したり、別のループをネストする必要がある場合があります)そこにあります)、しかし、彼らが何らかの形でクラスまたは少なくともプロパティを開発者に明らかにするまで、これは私たちが持っている最高のものです。

83
Dima

Swift 3ソリューション(iOS8 +の場合):

まず、viewDidLoad()メソッド内など、正常にロードされた後のUITableViewの遅延をオフにします。

someTableView.delaysContentTouches = false

次に、UITableView内に含まれるスクロールビューの遅延をオフにします。

for case let scrollView as UIScrollView in someTableView.subviews {
    scrollView.delaysContentTouches = false
}

IOS7に関する注意:UITableViewCellの遅延を無効にする必要がある場合があります。 (ディマの答えを確認してください)。

他にもいくつかのヒントがあります こちら

26
Nitin Nain

uIButtonをサブクラス化することでコード内のこの問題を解決し、

客観的C

@interface TBButton : UIButton

@end

@implementation TBButton

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.highlighted = true;
    [super touchesBegan:touches withEvent:event];
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.highlighted = false;
    [super touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.highlighted = false;
    [super touchesCancelled:touches withEvent:event];
}

@end

Swift

class TBButton: UIButton {
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        highlighted = true
        super.touchesBegan(touches, withEvent: event)
    }

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
        highlighted = false
        super.touchesEnded(touches, withEvent: event)
    }
    override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
        highlighted = false
        super.touchesCancelled(touches, withEvent: event)
    }
}

スイフト3

class TBButton: UIButton {
    override func touchesBegan(_ touches: Set<UITouch>, with event:     UIEvent?) {
        isHighlighted = true
        super.touchesBegan(touches, with: event)
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event:     UIEvent?) {
        isHighlighted = false
        super.touchesEnded(touches, with: event)
    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        isHighlighted = false
        super.touchesCancelled(touches, with: event)
    }
}
20
Alex

Alexanswer のSwift 3バージョン:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    isHighlighted = true
    super.touchesBegan(touches, with: event)
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    isHighlighted = false
    super.touchesEnded(touches, with: event)
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
    isHighlighted = false
    super.touchesCancelled(touches, with: event)
}
4
Marc

以下は、View Controllerに追加できる再帰的なソリューションです。

+ (void)disableDelayedTouches:(UIView*)view
{
    for(UIView *currentView in view.subviews) {
        if([currentView isKindOfClass:[UIScrollView class]]) {
            ((UIScrollView *)currentView).delaysContentTouches = NO;
        }
        [self disableDelayedTouches:currentView];
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self.class disableDelayedTouches:self.view];
}
2
Sandy Chapman

それでは、なぜ「タッチダウン」またはUIControlStateHighlightedの遅延なのでしょうか?ボタンが押されたことを示すために、ユーザーに即座にフィードバックを提供しようとしています。

Appleまだ説明していませんか?

この遅延なし:

  1. ビューをスクロールしたいときに、指でハイライト可能なもの(たとえば、デフォルトの選択スタイルのテーブルセル)に触れると、点滅するアーティファクトが表示されます:

    enter image description here

    本当に、タップするかスクロールするかは、touchDownでわかりません。

  2. ビューをスクロールするときに、指がUIButton/UITextFieldに触れた場合、ビューはまったくスクロールされません! Button/TextFieldのデフォルトの動作はscrollviewの「動作よりも強い」ため、touchUpInsideイベントを待機し続けます。

1
Dmitry Isaev