wake-up-neo.net

UIButton wird in iOS7 nicht hervorgehoben

Ich habe mir eine Menge Posts zu ähnlichen Dingen angeschaut, aber keines davon passt oder behebt dieses Problem. Seit iOS 7 funktioniert jedes Mal, wenn ich eine UIButton zu einer UITableViewCell oder sogar zur Fußansicht hinzufüge, "fein". Dies bedeutet, dass die Zielaktion empfangen wird. Es wird jedoch nicht das kleine Highlight angezeigt, das normalerweise beim Tippen auf eine UIButton auftritt. Dadurch wirkt die Benutzeroberfläche funky, wenn die Schaltfläche nicht auf Berührung reagiert.

Ich bin mir ziemlich sicher, dass dies als Fehler in iOS7 zählt, aber jemand hat eine Lösung gefunden oder könnte mir helfen, eine zu finden :)

Edit: Ich habe vergessen zu erwähnen, dass es hervorgehoben wird, wenn ich die Taste lange gedrückt halte, nicht aber ein schnelles Tippen, wenn es nur zu einer Standardansicht hinzugefügt wird.

Code:

Schaltfläche erstellen:

UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    button.titleLabel.font = [UIFont systemFontOfSize:14];
    button.titleLabel.textColor = [UIColor blueColor];
    [button setTitle:@"Testing" forState:UIControlStateNormal];
    [button addTarget:self action:@selector(buttonPressed:) forControlEvents: UIControlEventTouchDown];
    button.frame = CGRectMake(0, 0, self.view.frame.size.width/2, 40);

Dinge, die ich getestet habe:

// Gestenerkenner von UITableView entfernen, falls sie im Weg sind.

for (UIGestureRecognizer *recognizer in self.tableView.gestureRecognizers) {
   recognizer.enabled = NO;
}

// Entfernen von Gesten aus der Zelle

for (UIGestureRecognizer *recognizer in self.contentView.gestureRecognizers) {
       recognizer.enabled = NO;
    }

// Dies zeigt die kleine leichte Berührung, aber dies ist nicht das gewünschte Aussehen

button.showsTouchWhenHighlighted = YES;
68
Eric

In dieser Tabellenansicht fügen Sie einfach diese Eigenschaft hinzu.

tableview.delaysContentTouches = NO;

Fügen Sie in cellForRowAtIndexPath hinzu, nachdem Sie die Zelle initiiert haben, die Sie unter dem Code hinzufügen. Die Struktur der Zelle ist in iOS 6 und iOS 7 offensichtlich unterschiedlich.
iOS 7 haben wir ein Steuerelement UITableViewCellScrollView zwischen UITableViewCell und Inhaltsansicht.

for (id obj in cell.subviews)
{
    if ([NSStringFromClass([obj class]) isEqualToString:@"UITableViewCellScrollView"])
    {
        UIScrollView *scroll = (UIScrollView *) obj;
        scroll.delaysContentTouches = NO;
        break;
    }
}
87
subramani

Seit iOS 8 müssen wir dieselbe Technik auf UITableView-Subviews anwenden (Tabelle enthält eine verborgene UITableViewWrapperView-Bildlaufansicht). UITableViewCell-Unteransichten müssen nicht mehr wiederholt werden.

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

Diese Antwort sollte mit dieser Frage verknüpft werden.

40
Roman B.

Ich habe versucht, dies der akzeptierten Antwort hinzuzufügen, aber es ging nie durch. Dies ist eine viel sicherere Methode, um die DelaysContentTouches-Eigenschaft der Zellen zu deaktivieren, da sie nicht nach einer bestimmten Klasse sucht, sondern nach etwas, das auf den Selektor reagiert.

In der Zelle:

for (id obj in self.subviews) {
     if ([obj respondsToSelector:@selector(setDelaysContentTouches:)]) {
          [obj setDelaysContentTouches:NO];
     }
}

In TableView:

self.tableView.delaysContentTouches = NO;
27
Eric

Erstellen Sie für eine Lösung, die unter iOS7 und iOS8 funktioniert, eine benutzerdefinierte Unterklasse UITableView und eine benutzerdefinierte Unterklasse UITableViewCell.

Verwenden Sie dieses Beispiel UITableViews initWithFrame:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    if (self)
    {
        // iterate over all the UITableView's subviews
        for (id view in self.subviews)
        {
            // looking for a UITableViewWrapperView
            if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewWrapperView"])
            {
                // this test is necessary for safety and because a "UITableViewWrapperView" is NOT a UIScrollView in iOS7
                if([view isKindOfClass:[UIScrollView class]])
                {
                    // turn OFF delaysContentTouches in the hidden subview
                    UIScrollView *scroll = (UIScrollView *) view;
                    scroll.delaysContentTouches = NO;
                }
                break;
            }
        }
    }
    return self;
}

Verwenden Sie dieses Beispiel UITableViewCells initWithStyle:reuseIdentifier:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    if (self)
    {
        // iterate over all the UITableViewCell's subviews
        for (id view in self.subviews)
        {
            // looking for a UITableViewCellScrollView
            if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewCellScrollView"])
            {
                // this test is here for safety only, also there is no UITableViewCellScrollView in iOS8
                if([view isKindOfClass:[UIScrollView class]])
                {
                    // turn OFF delaysContentTouches in the hidden subview
                    UIScrollView *scroll = (UIScrollView *) view;
                    scroll.delaysContentTouches = NO;
                }
                break;
            }
        }
    }

    return self;
}
18
Quentin

Was ich getan habe, um das Problem zu lösen, war eine UIButton-Kategorie, die den folgenden Code verwendet:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];


    [NSOperationQueue.mainQueue addOperationWithBlock:^{ self.highlighted = YES; }];
}


- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];

    [self performSelector:@selector(setDefault) withObject:nil afterDelay:0.1];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];

    [self performSelector:@selector(setDefault) withObject:nil afterDelay:0.1];
}


- (void)setDefault
{
    [NSOperationQueue.mainQueue addOperationWithBlock:^{ self.highlighted = NO; }];
}

die Schaltfläche reagiert korrekt, wenn ich in einer UITableViewCell darauf drücke, und mein UITableView verhält sich normal, da die Variable delaysContentTouches nicht erzwungen wird.

16
Raphaël Pinto

Hier ist die Antwort von Roman B. in Swift 2:

for view in tableView.subviews {
    if view is UIScrollView {
        (view as? UIScrollView)!.delaysContentTouches = false
        break
    }
}
10
brandonscript
    - (void)viewDidLoad
{

    [super viewDidLoad];


    for (id view in self.tableView.subviews)
    {
        // looking for a UITableViewWrapperView
        if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewWrapperView"])
        {
            // this test is necessary for safety and because a "UITableViewWrapperView" is NOT a UIScrollView in iOS7
            if([view isKindOfClass:[UIScrollView class]])
            {
                // turn OFF delaysContentTouches in the hidden subview
                UIScrollView *scroll = (UIScrollView *) view;
                scroll.delaysContentTouches = NO;
            }
            break;
        }
    }
}

enter image description here

5
Gank

Ich hatte ähnliche Probleme mit einem Nur-Text-UIButton in einer UITableViewCell, der bei Berührung nicht hervorgehoben wurde. Für mich war das Ändern des buttonType von Custom zurück in System.

Das Festlegen von delay_ContentTouches auf NO hat den Trick für das UIButton nur für Bilder in derselben UITableViewCell-Funktion bewirkt.

self.tableView.delaysContentTouches = NO;

 enter image description here

4
skg

Lösung in Swift, nur iOS8 (erfordert zusätzliche Arbeit an jeder Zelle für iOS7):

//
//  NoDelayTableView.Swift
//  DivineBiblePhone
//
//  Created by Chris Hulbert on 30/03/2015.
//  Copyright (c) 2015 Chris Hulbert. All rights reserved.
//
//  This solves the delayed-tap issue on buttons on cells.

import UIKit

class NoDelayTableView: UITableView {

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        delaysContentTouches = false

        // This solves the iOS8 delayed-tap issue.
        // http://stackoverflow.com/questions/19256996/uibutton-not-showing-highlight-on-tap-in-ios7
        for view in subviews {
            if let scroll = view as? UIScrollView {
                scroll.delaysContentTouches = false
            }
        }
    }

    override func touchesShouldCancelInContentView(view: UIView!) -> Bool {
        // So that if you tap and drag, it cancels the tap.
        return true
    }

}

Zur Verwendung müssen Sie lediglich die Klasse in Ihrem Storyboard in NoDelayTableView ändern.

Ich kann bestätigen, dass in iOS8 jetzt Schaltflächen, die in einer Inhaltsansicht in einer Zelle platziert sind, sofort hervorgehoben werden.

3
Chris

Dies ist eine Swift -Version von Raphaël Pintos Antwort oben. Vergiss nicht, ihn auch zu verteidigen :)

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    super.touchesBegan(touches, withEvent: event)
    NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in self.highlighted = true }
}

override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
    super.touchesCancelled(touches, withEvent: event)
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC)))
    dispatch_after(time, dispatch_get_main_queue()) {
        self.setDefault()
    }
}

override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
    super.touchesEnded(touches, withEvent: event)
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC)))
    dispatch_after(time, dispatch_get_main_queue()) {
        self.setDefault()
    }
}

func setDefault() {
    NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in self.highlighted = false }
}
3
Chris Harrison

Leicht modifizierte Version von Chris Harrisons Antwort . Swift 2.3:

class HighlightButton: UIButton {
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        super.touchesBegan(touches, withEvent: event)
        NSOperationQueue.mainQueue().addOperationWithBlock { _ in self.highlighted = true }
    }

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

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

    private func setDefault() {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
            NSOperationQueue.mainQueue().addOperationWithBlock { _ in self.highlighted = false }
        }
    }
}
2
SoftDesigner

Ich habe eine Kategorieerweiterung zu UITableViewCell geschrieben, um das Problem einfach zu lösen. Es macht im Grunde dasselbe wie die akzeptierte Antwort, außer ich gehe die Ansichtshierarchie (im Gegensatz zu unten) vom UITableViewCell contentView aus hoch.

Ich habe eine vollständig "automagische" Lösung in Betracht gezogen, bei der alle Zellen, die einer UITableView hinzugefügt wurden, ihren delaysContentTouches-Zustand so einstellen, dass sie dem UITableView-Zustand des besitzenden delaysContentTouches entsprechen. Um dies zu erreichen, muss ich entweder UITableView wechseln oder vom Entwickler die Verwendung einer UITableView-Unterklasse verlangen. Ich wollte es auch nicht. Ich entschied mich für diese Lösung, die meiner Meinung nach einfacher und flexibler ist. 

Kategorienerweiterung und Musterkabelbaum hier: 

https://github.com/TomSwift/UITableViewCell-TS_delaysContentTouches

Es ist kinderleicht zu benutzen:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // using static cells from storyboard...
    UITableViewCell* cell = [super tableView: tableView cellForRowAtIndexPath: indexPath];

    cell.ts_delaysContentTouches = NO;

    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    return cell;
}

Hier ist der Code für die Kategorie:

@interface UITableViewCell (TS_delaysContentTouches)

@property (nonatomic, assign) BOOL ts_delaysContentTouches;

@end

@implementation UITableViewCell (TS_delaysContentTouches)

- (UIScrollView*) ts_scrollView
{
    id sv = self.contentView.superview;
    while ( ![sv isKindOfClass: [UIScrollView class]] && sv != self )
    {
        sv = [sv superview];
    }

    return sv == self ? nil : sv;
}

- (void) setTs_delaysContentTouches:(BOOL)delaysContentTouches
{
    [self willChangeValueForKey: @"ts_delaysContentTouches"];

    [[self ts_scrollView] setDelaysContentTouches: delaysContentTouches];

    [self didChangeValueForKey: @"ts_delaysContentTouches"];
}

- (BOOL) ts_delaysContentTouches
{
    return [[self ts_scrollView] delaysContentTouches];
}

@end
0
TomSwift

Da objc dynamisch ist und scrollView die einzige Klasse ist, die auf delay_ContentTouches reagiert, sollte dies für beide Betriebssysteme 7 und 8 funktionieren (setzen Sie es irgendwo zu Anfang in Ihren tableViewController, wie beispielsweise awakeFromNib):

for (id view in self.tableView.subviews)
    {
        if ([view respondsToSelector:@selector(delaysContentTouches)]) {
            UIScrollView *scrollView = (UIScrollView *)view;
            scrollView.delaysContentTouches = NO;
            break;
        }
}

Sie müssen möglicherweise auch "delayContentTouches" in Ihrem Storyboard oder in der Spitze deaktivieren, indem Sie die Tabelle in Ihrem viewController auswählen. Übrigens, das funktioniert unter ios 7 möglicherweise nicht, wenn Sie eine tableView in einem viewController verwenden, zumindest konnte ich es nicht zum Laufen bringen.

0
smileBot

Die akzeptierte Antwort funktionierte bei einigen "Abgriffen" für mich nicht.

Schließlich füge ich den untenstehenden Code in einer Uibutton-Kategorie (/ Unterklasse) hinzu, und er funktioniert hundertprozentig.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

self.backgroundColor = [UIColor greenColor];
[UIView animateWithDuration:0.05 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    self.backgroundColor = [UIColor clearColor];

} completion:^(BOOL finished)
 {
 }];
[super touchesBegan:touches withEvent:event];

}
0
rotoava

In Swift 3 kann diese UIView-Erweiterung auf der UITableViewCell verwendet werden. Vorzugsweise in der cellForRowAt-Methode.

func removeTouchDelayForSubviews() {
    for subview in subviews {
        if let scrollView = subview as? UIScrollView {
            scrollView.delaysContentTouches = false
        } else {
            subview.removeTouchDelayForSubviews()
        }
    }
}
0
Sunkas

Diese Lösung funktioniert für mich nicht, ich fixed Unterklasse TableView und implementiere diese beiden Methoden

- (instancetype)initWithCoder:(NSCoder *)coder{
   self = [super initWithCoder:coder];
   if (self) {
     for (id obj in self.subviews) {
      if ([obj respondsToSelector:@selector(setDelaysContentTouches:)]){
            [obj performSelector:@selector(setDelaysContentTouches:) withObject:NO];
      }
     }
   }
   return self;
}

- (BOOL)delaysContentTouches{
   return NO;
}
0
Serluca

Lösung in Swift für iOS 7 und 8:

Zuerst habe ich eine Utility-Funktion geschrieben:

class func classNameAsString(obj: AnyObject) -> String {
    return _stdlib_getDemangledTypeName(obj).componentsSeparatedByString(".").last!
}

dann Unterklasse UITableView und implementiere dies:

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    for view in self.subviews {
        if (Utility.classNameAsString(view) == "UITableViewWrapperView") {
            if view.isKindOfClass(UIScrollView) {
                var scroll = (view as UIScrollView)
                scroll.delaysContentTouches = false
            }
            break
        }
    }
}

Ich habe auch die Unterklasse UITableViewCell und implementiere diese:

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)

    for view in self.subviews {
        if (Utility.classNameAsString(view) == "UITableViewCellScrollView") {
            if view.isKindOfClass(UIScrollView) {
                var scroll = (view as UIScrollView)
                scroll.delaysContentTouches = false
            }

        }
    }
}

In meinem Fall läuft die Init (Coder :). Bitte geben Sie in Ihren init-Funktionen einen Debug-Punkt an, um zu wissen, welche init-Funktion ausgeführt wird. Verwenden Sie dann den obigen Code, damit es funktioniert.

0
grandagile