wake-up-neo.com

Gestaltung der Abbrechen-Schaltfläche in einer UISearchBar

Ich habe eine UISearchBar, die über eine Schaltfläche zum Abbrechen verfügt (diese wird mit -(void)setShowsCancelButton:animated angezeigt). Ich habe die Variable tintColor der Suchleiste folgendermaßen geändert, um eine gräuliche Suchleiste zu erhalten:

UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 40)];
searchBar.tintColor = [UIColor colorWithWhite:0.8 alpha:1.0];

So sieht es jetzt aus - Beachten Sie, dass der Abbrechen-Button ebenfalls grau ist: http://twitpic.com/c0hte

Gibt es eine Möglichkeit, die Farbe der Abbrechen-Schaltfläche separat einzustellen, so dass sie eher wie folgt aussieht: http://twitpic.com/c0i6q

26
Chu Yeow

Was Sie tun wollen, ist ziemlich hart. Es gibt keinen eingebauten Haken, um an die Abbrechen-Schaltfläche zu gelangen.

Es gibt jedoch ein paar Optionen, wenn Sie bereit sind, die Motorhaube zu öffnen.

Zunächst einmal ist UISearchBar eine UIView, und die Schaltfläche Abbrechen ist auch eine Ansicht, die der Suchleiste als Unteransicht hinzugefügt wird, so wie Sie es erwarten.

Ich habe ein wenig experimentiert und kann Ihnen sagen, dass die Schaltfläche eine Größe von 48,30 hat, wenn der Button angezeigt wird.

In viewWillAppear können Sie also Folgendes tun:

  1. Suchen Sie nach der Ansicht der Schaltfläche "Abbrechen" in [searchBar-Unteransichten], indem Sie nach einer Ansicht mit der Größe 48,30 suchen. (Es scheint nur eine zu geben - das könnte sich ändern ...) Sie könnten doppelt vorsichtig sein und nach einer suchen, die sich ungefähr in der richtigen Position befindet (in Landschaft und Porträt unterschiedlich).

  2. Fügen Sie der Abbruchschaltfläche eine Unteransicht hinzu. 

  3. Die Unteransicht sollte eine UIControl sein (damit Sie aktivieren = NEIN setzen können, um sicherzustellen, dass Berührungsereignisse auf die Schaltfläche "Abbrechen" gelangen).

  4. Es muss die richtige Farbe und abgerundete Ecken haben. Sie müssen die Größe aus Gründen ändern, die ich noch nicht verstehe (55,30 scheint zu funktionieren)

  5. Dies funktioniert, wenn searchBar.showsCancelButton immer YES ist. Wenn Sie möchten, dass die Suchzeichenfolge nicht bearbeitet wird, müssen Sie bei jedem Abbruch der Schaltfläche "Abbrechen" einen Haken finden, um die Überlagerung hinzuzufügen.

  6. Wie Sie sehen können, ist dies ein hässliches Basteln. Mach es mit offenen Augen.

14
Amagrammer

Sie können UIAppearance verwenden, um die Schaltfläche "Abbrechen" zu formatieren, ohne die Unteransichten der UISearchBar zu durchlaufen, aber der UIButton-Header verfügt derzeit über keine mit UI_APPEARANCE_SELECTOR kommentierten Methoden .

BEARBEITEN: Drilldown auf die Subviews bis zum Abbruch-Button

Dies gibt jedoch normalerweise nichts zurück, bis searchBar.setShowsCancelButton(true, animated: true) aufgerufen wird.

extension UISearchBar {

var cancelButton : UIButton? {
    if let view = self.subviews.first {
        for subView in view.subviews {
            if let cancelButton = subView as? UIButton {
                return cancelButton
            }
        }
    }
    return nil
}
}
25
lemnar

In iOS 5.0 und höher können Sie den Proxy appearnce verwenden.

Bevor die Suchleiste angezeigt wird:

UIBarButtonItem *searchBarButton = [UIBarButtonItem appearanceWhenContainedIn:[UISearchBar class], nil];
[searchBarButton setBackgroundImage:myCancelButtonImageNormal forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[searchBarButton setBackgroundImage:myCancelButtonImageHighlighted forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
[searchBarButton setTitleTextAttributes:barButtonTitleTextAttributesNormal forState:UIControlStateNormal];
[searchBarButton setTitleTextAttributes:barButtonTitleTextAttributesHighlighted forState:UIControlStateHighlighted];

Wenn Sie [UIButton appearanceWhenContainedIn:[UISearchBar class], nil] verwenden, hat dies Auswirkungen auf andere Schaltflächen (z. B. die Schaltfläche "Löschen"). Sie sollten also lieber UIButtons Erscheinung nicht verwenden. Versuchen Sie UIBarButtonItem.

20
Yiming Tang

Ändern Sie den Titel der Schaltfläche "Abbrechen":

[[UIButton appearanceWhenContainedIn:[UISearchBar class], nil] setTitle:@"newTitle" forState:UIControlStateNormal];

Schnelles Äquivalent:

   let cancelButton = UIButton.appearance(whenContainedInInstancesOf: [UISearchBar.self])
   cancelButton?.setTitle("cancel".localized, for: .normal)
19
Neru-J

Auch wenn dies für die ursprüngliche Frage möglicherweise nicht genau relevant ist, ist die Lösung immer noch anwendbar, wenn man versucht, die Schaltfläche "Abbrechen" in der UISearchBar anzupassen. Dies wird anderen helfen, die in einem solchen Szenario festsitzen.

Meine Situation bestand darin, den Titel der Abbruchschaltfläche zu ändern, jedoch mit einer Drehung, wobei ich die Abbruchschaltfläche standardmäßig nicht anzeigen wollte, sondern nur wollte, wenn der Benutzer in den Suchmodus wechselt (durch Klicken in das Suchtextfeld) ). Zu diesem Zeitpunkt wollte ich, dass der Abbruch-Button die Überschrift "Fertig" trug ("Abbruch" gab meinem Bildschirm eine andere Bedeutung, daher die Anpassung). 

Dennoch habe ich Folgendes getan (eine Kombination aus den Lösungen von Caelavel und Arenim):

Unterklasse UISearchBar als MyUISearchBar mit diesen beiden Methoden:

-(void) setCloseButtonTitle: (NSString *) title forState: (UIControlState)state
{
    [self setTitle: title forState: state forView:self];
}

-(void) setTitle: (NSString *) title forState: (UIControlState)state forView: (UIView *)view
{
    UIButton *cancelButton = nil;
    for(UIView *subView in view.subviews){
        if([subView isKindOfClass:UIButton.class])
        {
            cancelButton = (UIButton*)subView;
        }
        else
        {
            [self setTitle:title forState:state forView:subView];
        }
    }

    if (cancelButton)
        [cancelButton setTitle:title forState:state];

}

Im Viewcontroller, der diese Suchleiste verwendet, sorgt der folgende Code dafür, dass die Schaltfläche "Abbrechen" angezeigt und der Titel angepasst wird:

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
    MyUISearchBar *sBar = (MyUISearchBar *)searchBar;
    [sBar setShowsCancelButton:YES];
    [sBar setCloseButtonTitle:@"Done" forState:UIControlStateNormal];   
}

Seltsamerweise musste ich den Abbruch-Button nicht ausblenden, da er standardmäßig ausgeblendet ist, wenn der Suchmodus beendet wird.

17
Sara

Wenn Sie Ihre Abbrechen-Schaltfläche für UISearchBar konfigurieren möchten, sollten Sie das UIButton-Objekt von Ihrem UISearchBar-Objekt erhalten. Beispiel unten

UISearchBar *s_bar = [[UISearchBar alloc] initWithFrame:CGRectMake(50,20,300,30)];
s_bar.delegate = self;
s_bar.barStyle = UIBarStyleDefault;
s_bar.showsCancelButton = YES;
UIButton *cancelButton;
for (id button in s_bar.subviews)
{
    if ([button isKindOfClass:[UIButton class]])
    {
        cancelButton=(UIButton*)button;
        break;
    }
}
7
dpart

Sie finden die Schaltfläche "Abbrechen", indem Sie die Unteransichten der Suchleiste durchlaufen und nach dem Klassentyp (anstelle der Größe) suchen:

UIButton *cancelButton = nil;
for(UIView *subView in yourSearchBar.subviews){
    if([subView isKindOfClass:UIButton.class]){
    cancelButton = (UIButton*)subView;
    }
}

Und dann die Farbtonfarbe ändern:

[cancelButton setTintColor:[UIColor colorWithRed:145.0/255.0 green:159.0/255.0 blue:179.0/255.0 alpha:1.0]];
7
Andrew Homeyer

Ich werde eine detaillierte Antwort auf die UIAppearance-Technik geben. Zunächst müssen Sie verstehen, dass es sich bei der Abbrechen-Schaltfläche um einen privaten UINavigationButton handelt: UIButton. Nach einiger Prüfung scheint UINavigationButton auf diese UIAppearance-Selektoren zu reagieren:

// inherited from UINavigationButton
@selector(setTintColor:)
@selector(setBackgroundImage:forState:style:barMetrics:)
@selector(setBackgroundImage:forState:barMetrics:)
@selector(setTitleTextAttributes:forState:)
@selector(setBackgroundVerticalPositionAdjustment:forBarMetrics:)
@selector(setTitlePositionAdjustment:forBarMetrics:)
@selector(setBackButtonBackgroundImage:forState:barMetrics:)
@selector(setBackButtonTitlePositionAdjustment:forBarMetrics:)
@selector(setBackButtonBackgroundVerticalPositionAdjustment:forBarMetrics:)

// inherited from UIButton
@selector(setTitle:forState:)

Zufällig stimmen diese Selektoren mit denen eines UIBarButtonItem überein. Der Trick bedeutet, zwei getrennte UIAppearance-Werte für die private Klasse UINavigationButton zu verwenden.

/* dual appearance technique by Cœur to customize a UINavigationButton */
Class barClass = [UISearchBar self];

UIBarButtonItem<UIAppearance> *barButtonItemAppearanceInBar = [UIBarButtonItem appearanceWhenContainedIn:barClass, nil];
[barButtonItemAppearanceInBar setTintColor:...];
[barButtonItemAppearanceInBar setBackgroundImage:... forState:... style:... barMetrics:...];
[barButtonItemAppearanceInBar setBackgroundImage:... forState:... barMetrics:...];
[barButtonItemAppearanceInBar setTitleTextAttributes:... forState:...];
[barButtonItemAppearanceInBar setBackgroundVerticalPositionAdjustment:... forBarMetrics:...];
[barButtonItemAppearanceInBar setTitlePositionAdjustment:... forBarMetrics:...];
// only for a backButton in an UINavigationBar, not for a cancelButton in an UISearchBar
//[barButtonItemAppearanceInBar setBackButtonBackgroundImage:... forState:... barMetrics:...];
//[barButtonItemAppearanceInBar setBackButtonTitlePositionAdjustment:... forBarMetrics:...];
//[barButtonItemAppearanceInBar setBackButtonBackgroundVerticalPositionAdjustment:... forBarMetrics:...];

UIButton<UIAppearance> *buttonAppearanceInBar = [UIButton appearanceWhenContainedIn:barClass, nil];
// warning: doesn't work for iOS7+
[buttonAppearanceInBar setTitle:... forState:...];

Auf diese Weise können Sie die Abbrechen-Schaltfläche beliebig anpassen.

4
Cœur

Benutzerdefinierte UISearchBar- und Überschreibungsmethode -addSubview: 

- (void) addSubview:(UIView *)view {
    [super addSubview:view];

    if ([view isKindOfClass:UIButton.class]) {
        UIButton *cancelButton = (UIButton *)view;
        [cancelButton setBackgroundImage:[UIImage imageNamed:@"xxxx.png"] forState:UIControlStateNormal];
        [cancelButton setBackgroundImage:[UIImage imageNamed:@"yyyy.png"] forState:UIControlStateHighlighted];
    }
}
4
iwill

Nachdem Sie Ihre UISearchBar initialisiert haben, können Sie ihre Unteransichten untersuchen und jede davon anpassen. Beispiel:

for (UIView *view in searchBar.subviews) {

    //if subview is the button
    if ([[view.class description] isEqualToString:@"UINavigationButton"]) {

        //change the button images and text for different states
        [((UIButton *)view) setEnabled:YES];
        [((UIButton *)view) setTitle:nil forState:UIControlStateNormal];
        [((UIButton *)view) setImage:[UIImage imageNamed:@"button image"] forState:UIControlStateNormal];
        [((UIButton *)view) setBackgroundImage:[UIImage imageNamed:@"button"] forState:UIControlStateNormal];
        [((UIButton *)view) setBackgroundImage:[UIImage imageNamed:@"button_pressed"] forState:UIControlStateSelected];
        [((UIButton *)view) setBackgroundImage:[UIImage imageNamed:@"button_pressed"] forState:UIControlStateHighlighted];

    //if the subview is the background
    }else if([[view.class description] isEqualToString:@"UISearchBarBackground"]) {

        //put a custom gradient overtop the background
        CAGradientLayer *gradient = [CAGradientLayer layer];
        gradient.frame = view.bounds;
        gradient.colors = [NSArray arrayWithObjects:(id)[[some uicolor] CGColor], (id)[[another uicolor] CGColor], nil];
        [view.layer insertSublayer:gradient atIndex:0];

    //if the subview is the textfield
    }else if([[view.class description] isEqualToString:@"UISearchBarTextField"]){

        //change the text field if you wish

    }

}

Ging großartig für mich! Vor allem die Steigung :)

Swift 2.1.1:

Es gibt keine einfache Möglichkeit, die Suchleiste einzuhaken und zu gestalten. Sie müssen die Unteransicht manuell von der Suchleiste aus übernehmen und dann Ihre Änderungen anwenden.

var cancelButton: UIButton
let topView: UIView = self.customSearchController.customSearchBar.subviews[0] as UIView
for subView in topView.subviews {
 if subView.isKindOfClass(NSClassFromString("UINavigationButton")!) {
    cancelButton = subView as! UIButton
    cancelButton.enabled = true
    cancelButton.setTitle("TestTitle", forState: UIControlState.Normal) // Change to set the title
    cancelButton.setBackgroundImage(UIImage(named: "ImageName"), forState: .Normal) // Change this to set a custom cancel button image, set the title to "" to remove 'Cancel' text
   }
}
1
Elliott Davies

Zuallererst möchte ich @Eliott von hier aus danken https://stackoverflow.com/a/37381821/1473144

Ich musste ein paar Anpassungen vornehmen, damit er mit meinen Angaben arbeiten konnte. Bitte, ich bitte das OP, die akzeptierte Antwort zu aktualisieren, da sie sehr veraltet ist.

Swift 3, iOS 10 & Xcode 8.2.1

searchBar.showsCancelButton = true
var cancelButton: UIButton
let topView: UIView = self.searchBar.subviews[0] as UIView
for subView in topView.subviews {
    if let pvtClass = NSClassFromString("UINavigationButton") {
        if subView.isKind(of: pvtClass) {
            cancelButton = subView as! UIButton

            cancelButton.setTitle("", for: .normal)
            cancelButton.tintColor = UIColor.black
            cancelButton.setImage(#imageLiteral(resourceName: "searchX"), for: .normal)
        }
    }

}
1
gaskbr

Ich habe in meiner App viele UISearchBar-Elemente, also habe ich diese Kategorie geschrieben, um eine Eigenschaft hinzuzufügen, damit Sie auf mySearchBar.cancelButton zugreifen können. (Wenn Sie Kategorien noch nicht kennen, lesen Sie lesen Sie hier mehr über das Erweitern von Objekten mit Kategorien .)

Denken Sie daran, Sie sollten nur dann aufrufen, wenn die Schaltfläche "Abbrechen" sichtbar ist, weil UISearchBar bei jeder Anzeige ein neues Schaltflächenobjekt zu erstellen scheint. Speichern Sie den Zeiger nicht auf die CancelButton-Schaltfläche, sondern rufen Sie ihn bei Bedarf auf:

@interface UISearchBar (cancelButton)

@property (readonly) UIButton* cancelButton;

- (UIButton *) cancelButton;

@end

@implementation UISearchBar (cancelButton)

- (UIButton *) cancelButton {
    for (UIView *subView in self.subviews) {
        //Find the button
        if([subView isKindOfClass:[UIButton class]])
        {
            return (UIButton *)subView;
        }
    }

    NSLog(@"Error: no cancel button found on %@", self);

    return nil;
}

@end
0
Aaron Brager

Nun, hier ist eine Funktion, die die Tastenbeschriftung von Cancel ändern kann. Ändern Sie es, wenn Sie möchten. Verwendung ist:

nStaticReplaceStringInView(mySearchBar, @"Cancel", @"NewCancelButtonLabel");

void nStaticReplaceStringInView(UIView * view, NSString * haystack, NSString * needle)
{
 for(int i=0; i<[view.subviews count]; i++)
 {
  nStaticReplaceStringInView([view.subviews objectAtIndex:i], haystack,needle);
 }
 if([view respondsToSelector:@selector(titleForState:)])
 {
  //NSLog(@"%@ || %@",[view titleForState:UIControlStateNormal], haystack);
  if(NSStrEq([view titleForState:UIControlStateNormal] , haystack))
  {
   [view setTitle: needle forState: UIControlStateNormal];
  }
 }
}
0
Arenim
- (void) searchBarTextDidBeginEditing:(UISearchBar *)theSearchBar 
{        
    NSArray *arr = [theSearchBar subviews];
    UIButton *cancelButton = [arr objectAtIndex:3];
    [cancelButton setTitle:@"yourtitle" forState:UIControlStateNormal];    
}

Machen Sie einfach ein Protokoll von arr AMD und sehen Sie, an welcher Index-Kontrolle es liegt. Auf dieselbe Weise können Sie UITextField -Eigenschaften festlegen:

    NSArray *arr = [searchbar subviews];
    UITextField *searchfield = [arr objectAtIndex:2];
    [searchfield setTextAlignment:UITextAlignmentRight];
0
Abhishek Singh
UISearchBar *searchBar;
[searchBar setShowsCancelButton:YES animated:YES];

UIButton *cancelButton = 
YES == [searchBar respondsToSelector:NSSelectorFromString(@"cancelButton")] ? 
[searchBar valueForKeyPath:@"_cancelButton"] : nil;

cancelButton.titleEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 10);
[cancelButton setTitle:@"New :)" forState:UIControlStateNormal];
0

Für iOS 11 und Swift 4. Erstellen Sie eine Unterklasse von UISearchController. Überschreibungsmethode:

override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        print("layout")
        if let btn = searchBar.subviews[0].subviews[2] as? UIButton {
            btn.frame = CGRect(x: 306, y: 20, width: 53, height: 30)
        }
}
0
Mazorati
extension UISearchBar {
var cancelButton : UIButton? {
    let topView: UIView = self.subviews[0] as UIView

    if let pvtClass = NSClassFromString("UINavigationButton") {
        for v in topView.subviews {
            if v.isKind(of: pvtClass) {
                return v as? UIButton
            }
        }
    }

    return nil
}
}
0
Abhishek Bedi

dummer Weg 

for(id cc in [SearchBar subviews])
{
    if([cc isKindOfClass:[UIButton class]])
    {
        UIButton *btn = (UIButton *)cc;
        ......
        Do whatever you want
        .......        
    }
}
0
LucKy_one