it-swarm.com.de

Wie kann ich die Schaltfläche "Abbrechen" mit UISearchBar aktivieren?

Wenn Sie in der Kontakte-App auf dem iPhone einen Suchbegriff eingeben, tippen Sie auf die Schaltfläche "Suchen". Die Tastatur ist ausgeblendet. ABER die Schaltfläche "Abbrechen" ist noch aktiviert. In meiner App wird die Abbrechen-Schaltfläche deaktiviert, wenn ich den resignFirstResponder anrufe.

Weiß jemand, wie die Tastatur ausgeblendet wird, während die Abbruchtaste in einem aktivierten Zustand bleibt?

Ich verwende den folgenden Code:

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
    [searchBar resignFirstResponder];
}

Die Tastatur wird nicht angezeigt, aber die Schaltfläche "Abbrechen" rechts neben dem Suchtextfeld ist deaktiviert, sodass ich die Suche nicht abbrechen kann. Die Kontakte-App behält die Schaltfläche "Abbrechen" in einem aktivierten Status.

Ich denke, eine Lösung besteht darin, in das searchBar-Objekt einzutauchen und resignFirstResponder für das eigentliche Textfeld und nicht für die Suchleiste selbst aufzurufen.

Jede Eingabe wird geschätzt.

49
Christopher

versuche dies

for(id subview in [yourSearchBar subviews])
{
    if ([subview isKindOfClass:[UIButton class]]) {
        [subview setEnabled:YES];
    }
}
21
Malek_Jundi

Diese Methode hat in iOS7 funktioniert. 

- (void)enableCancelButton:(UISearchBar *)searchBar
{
    for (UIView *view in searchBar.subviews)
    {
        for (id subview in view.subviews)
        {
            if ( [subview isKindOfClass:[UIButton class]] )
            {
                [subview setEnabled:YES];
                NSLog(@"enableCancelButton");
                return;
            }
        }
    }
}

(Denken Sie auch daran, es nach der Verwendung von [_searchBar resignFirstResponder] überall aufzurufen.)

29
David Douglas

Die akzeptierte Lösung funktioniert nicht, wenn Sie mit dem Scrollen der Tabelle beginnen, anstatt auf die Schaltfläche "Suchen" zu tippen. In diesem Fall wird die Schaltfläche "Abbrechen" deaktiviert.

Dies ist meine Lösung, die die Schaltfläche "Abbrechen" jedes Mal wieder aktiviert, wenn sie mithilfe von KVO deaktiviert wird.

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    // Search for Cancel button in searchbar, enable it and add key-value observer.
    for (id subview in [self.searchBar subviews]) {
        if ([subview isKindOfClass:[UIButton class]]) {
            [subview setEnabled:YES];
            [subview addObserver:self forKeyPath:@"enabled" options:NSKeyValueObservingOptionNew context:nil];
        }
    }
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    // Remove observer for the Cancel button in searchBar.
    for (id subview in [self.searchBar subviews]) {
        if ([subview isKindOfClass:[UIButton class]])
            [subview removeObserver:self forKeyPath:@"enabled"];
    }
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    // Re-enable the Cancel button in searchBar.
    if ([object isKindOfClass:[UIButton class]] && [keyPath isEqualToString:@"enabled"]) {
        UIButton *button = object;
        if (!button.enabled)
            button.enabled = YES;
    }
}
10
Marián Černý

Seit iOS 6 scheint die Schaltfläche eine UINavigationButton (private Klasse) anstelle eines UIButton zu sein. 

Ich habe das obige Beispiel so angepasst, dass es so aussieht.

for (UIView *v in searchBar.subviews) {
    if ([v isKindOfClass:[UIControl class]]) {
        ((UIControl *)v).enabled = YES;
    }
}

Dies ist jedoch offensichtlich spröde, da wir mit den inneren Elementen herumspielen. Es kann auch mehr als die Schaltfläche aktivieren, aber es funktioniert für mich, bis eine bessere Lösung gefunden wird. 

Wir sollten Apple bitten, dies herauszustellen. 

9
Ben L.

Das schien für mich zu funktionieren (in viewDidLoad):

__unused UISearchDisplayController* searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self];

Ich stelle fest, dass ich den UISearchDisplayController wahrscheinlich richtig verwenden sollte, aber dies war eine einfache Lösung für meine aktuelle Implementierung.

8
n8chur

Sie können die Laufzeit-API verwenden, um auf die Schaltfläche "Abbrechen" zuzugreifen.

UIButton *btnCancel = [self.searchBar valueForKey:@"_cancelButton"];
[btnCancel setEnabled:YES];

Ich habe das, was andere hier bereits gepostet haben, erweitert, indem ich dies als einfache Kategorie in UISearchBar implementiert habe.

UISearchBar + alwaysEnableCancelButton.h

#import <UIKit/UIKit.h>

@interface UISearchBar (alwaysEnableCancelButton)

@end

UISearchBar + alwaysEnableCancelButton.m

#import "UISearchBar+alwaysEnableCancelButton.h"

@implementation UISearchBar (alwaysEnableCancelButton)

- (BOOL)resignFirstResponder
{
    for (UIView *v in self.subviews) {
        // Force the cancel button to stay enabled
        if ([v isKindOfClass:[UIControl class]]) {
            ((UIControl *)v).enabled = YES;
        }

        // Dismiss the keyboard
        if ([v isKindOfClass:[UITextField class]]) {
            [(UITextField *)v resignFirstResponder];
        }
    }

    return YES;
}
@end
5
Brains

Hier ist eine etwas robustere Lösung, die unter iOS 7 funktioniert. Sie rekursiv rekursiv alle Unteransichten der Suchleiste, um sicherzustellen, dass alle UIControls aktiviert sind (einschließlich der Schaltfläche "Abbrechen").

- (void)enableControlsInView:(UIView *)view
{
    for (id subview in view.subviews) {
        if ([subview isKindOfClass:[UIControl class]]) {
            [subview setEnabled:YES];
        }
        [self enableControlsInView:subview];
    }
}

Rufen Sie diese Methode direkt nach dem Aufruf von [self.searchBar resignFirstResponder] wie folgt auf:

[self enableControlsInView:self.searchBar];

Voila! Die Schaltfläche "Abbrechen" bleibt aktiviert.

4
smileyborg
for (UIView *firstView in searchBar.subviews) {
    for(UIView* view in firstView.subviews) {
        if([view isKindOfClass:[UIButton class]]) {
             UIButton* button = (UIButton*) view;
             [button setEnabled:YES];
        }
    }
}
3
Abdul Rehman

Ich habe einen anderen Ansatz gefunden, damit es in iOS 7 funktioniert.

Was ich versuche, ist so etwas wie die Twitter iOS App. Wenn Sie auf die Lupe auf der Registerkarte Zeitleisten klicken, wird UISearchBar mit aktivierter Schaltfläche Abbrechen angezeigt, die Tastatur wird eingeblendet und der Bildschirm für die letzten Suchen angezeigt. Blättern Sie durch den Bildschirm mit den letzten Suchen, und die Tastatur wird ausgeblendet. Die Schaltfläche Abbrechen bleibt jedoch aktiviert.

Dies ist mein Arbeitscode:

UIView *searchBarSubview = self.searchBar.subviews[0];
NSArray *subviewCache = [searchBarSubview valueForKeyPath:@"subviewCache"];
if ([subviewCache[2] respondsToSelector:@selector(setEnabled:)]) {
    [subviewCache[2] setValue:@YES forKeyPath:@"enabled"];
}

Ich bin zu dieser Lösung gekommen, indem ich am scrollViewWillBeginDragging: meiner Tabellenansicht einen Haltepunkt gesetzt habe. Ich schaute in meine UISearchBar und entblößte ihre Unteransichten. Es hat immer nur einen, der vom Typ UIView (meine Variable searchBarSubview) ist.

enter image description here

Dann enthält UIView ein NSArray mit dem Namen subviewCache und ich habe bemerkt, dass das letzte Element, das dritte Element, vom Typ UINavigationButton ist, nicht in der öffentlichen API. Also habe ich beschlossen, stattdessen die Schlüsselwert-Codierung zu verwenden. Ich habe geprüft, ob UINavigationButton auf setEnabled: antwortet, und zum Glück tut es das. Also setze ich die Eigenschaft auf @YES. Stellt sich heraus, dass UINavigationButtonist die Schaltfläche Abbrechen ist.

Dies wird zwangsläufig brechen, wenn sich Apple dazu entscheidet, die Implementierung eines UISearchBars zu ändern, aber was solls? Es funktioniert jetzt.

2
Matthew Quiros

Die meisten der veröffentlichten Lösungen sind nicht robust und lassen die Schaltfläche "Abbrechen" unter verschiedenen Umständen deaktivieren.

Ich habe versucht, eine Lösung zu implementieren, bei der die Schaltfläche "Abbrechen" immer aktiviert bleibt, selbst wenn die Suchleiste kompliziertere Aufgaben ausführt. Dies ist als benutzerdefinierte UISearchView-Unterklasse in Swift 4 implementiert. Mit dem Wert (forKey :) wird sowohl die Schaltfläche "Abbrechen" als auch das Feld "Suchtext" gesucht. Er wartet darauf, wenn das Suchfeld die Bearbeitung beendet hat, und aktiviert die Schaltfläche "Abbrechen". Es aktiviert auch die Schaltfläche zum Abbrechen, wenn das Flag showCancelButton gewechselt wird.

Es enthält eine Reihe von Aussagen, die Sie warnen, wenn sich die internen Details von UISearchBar ändern und deren Funktionieren verhindern.

import UIKit

final class CancelSearchBar: UISearchBar {
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
    }

    private func setup() {
        guard let searchField = value(forKey: "_searchField") as? UIControl else {
            assertionFailure("UISearchBar internal implementation has changed, this code needs updating")
            return
        }

        searchField.addTarget(self, action: #selector(enableSearchButton), for: .editingDidEnd)
    }

    override var showsCancelButton: Bool {
        didSet { enableSearchButton() }
    }

    @objc private func enableSearchButton() {
        guard showsCancelButton else { return }
        guard let cancelButton = value(forKey: "_cancelButton") as? UIControl else {
            assertionFailure("UISearchBar internal implementation has changed, this code needs updating")
            return
        }

        cancelButton.isEnabled = true
    }
}
2
Dag Ågren

Schnelle Version für die Antwort von David Douglas (getestet auf iOS9) 

func enableSearchCancelButton(searchBar: UISearchBar){
    for view in searchBar.subviews {
        for subview in view.subviews {
            if let button = subview as? UIButton {
                button.enabled = true
            }
        }
    }
}
2
Tal Haham

Für iOS 10, Swift 3:

for subView in self.movieSearchBar.subviews {
    for view in subView.subviews {
        if view.isKind(of:NSClassFromString("UIButton")!) {
            let cancelButton = view as! UIButton
            cancelButton.isEnabled = true
        }
    }
}
1
Saoud Rizwan

Aufbauend auf smileyborgs Antwort , fügen Sie dies einfach in Ihren searchBar-Delegierten ein:

- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{   
    dispatch_async(dispatch_get_main_queue(), ^{
        __block __weak void (^weakEnsureCancelButtonRemainsEnabled)(UIView *);
        void (^ensureCancelButtonRemainsEnabled)(UIView *);
        weakEnsureCancelButtonRemainsEnabled = ensureCancelButtonRemainsEnabled = ^(UIView *view) {
            for (UIView *subview in view.subviews) {
                if ([subview isKindOfClass:[UIControl class]]) {
                [(UIControl *)subview setEnabled:YES];
                }
                weakEnsureCancelButtonRemainsEnabled(subview);
            }
        };

        ensureCancelButtonRemainsEnabled(searchBar);
    });
 }

Diese Lösung funktioniert gut unter iOS 7 und höher.

1
followben

Für iOS 9/10 (getestet), Swift 3 (kürzer):

searchBar.subviews.flatMap({$0.subviews}).forEach({ ($0 as? UIButton)?.isEnabled = true })
0
neegra

Bessere & einfache Methode:

[(UIButton *)[self.searchBar valueForKey:@"_cancelButton"] setEnabled:YES];
0
Lal Krishna

Eine bessere Lösung ist

[UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil].enabled = YES;
0
migrant

Sie können Ihre CustomSearchBar erstellen, die von UISearchBar erbt, und diese Methode implementieren:

- (void)layoutSubviews {

    [super layoutSubviews];

    @try {
        UIView *baseView = self.subviews[0];

        for (UIView *possibleButton in baseView.subviews)
        {
            if ([possibleButton respondsToSelector:@selector(setEnabled:)]) {
                [(UIControl *)possibleButton setEnabled:YES];
            }
        }
    }
    @catch (NSException *exception) {
        NSLog(@"ERROR%@",exception);
    }
}
0
Diego Lima