造型在一个UISearchBar取消按钮(Styling the cancel button in

2019-06-17 18:55发布

我有了一个取消按钮(它的使用显示一个UISearchBar -(void)setShowsCancelButton:animated )。 我已经改变了tintColor这样的搜索栏,试图得到一个浅灰色的搜索栏:

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

这是它看起来像现在-注意如何取消按钮也是灰色: http://twitpic.com/c0hte

有没有办法单独设置取消按钮的颜色,所以它看起来更像是这样的: http://twitpic.com/c0i6q

Answer 1:

你想要做什么是非常艰难的。 有没有内置的钩来获得在取消按钮。

然而,有一对夫妇的选择,如果你愿意吉米打开引擎盖。

首先,是的UISearchBar一个UIView和取消按钮也是一种视图,通过添加到作为一个子视图的搜索栏中,正如你所期望的。

我已经试验了一下,可以告诉你,当按钮是屏幕上它的大小为48,30。

因此,在viewWillAppear中,你可以做这样的事情:

  1. 查找[搜索栏子视图]取消按钮视图通过用大小48,30寻找一个。 (有只似乎是一个 - 这可能改变...),你可以加倍小心并寻找一个是在大约正确的位置(横向和纵向不同)。

  2. 一个子视图添加到取消按钮。

  3. 该子视图应该是一个UIControl(使您可以设置启用= NO,以确保触摸事件获得实际的取消按钮)

  4. 它需要有正确的颜色和圆角; 你将需要捏造大小的原因,我还不知道(55,30似乎工作)

  5. 这将工作,如果searchBar.showsCancelButton永远是YES; 如果你想让它在不编辑搜索字符串消失,你需要找到一个钩子添加每个取消时间出现按钮覆盖。

  6. 正如你所看到的,这是一些丑陋的修补。 睁大眼睛做到这一点。



Answer 2:

您可以使用UIAppearance样式不反复的子视图取消按钮UISearchBar ,但在UIButton头目前没有带注释的任何方法UI_APPEARANCE_SELECTOR

编辑:直到你得到的是取消按钮下钻子视图

但是,这通常返回零,直到searchBar.setShowsCancelButton(true, animated: true)被调用。

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
}
}


Answer 3:

在iOS 5.0及,您可以使用appearnce代理。

之前的搜索栏显示:

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];

如果您使用[UIButton appearanceWhenContainedIn:[UISearchBar class], nil] ,它会影响到其他按钮(如清除按钮)。 所以,你最好不要使用UIButton的appearnce。 尝试UIBarButtonItem



Answer 4:

更改“取消”按钮的标题:

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

斯威夫特相当于:

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


Answer 5:

虽然这可能不是原来的问题正好相应的解决方案仍然是适用于试图定制的的UISearchBar取消按钮的更大意义。 认为这将有助于其他人谁是停留在这样的场景。

我的情况是改变取消按钮的标题,但与一捻,其中我不想默认显示的取消按钮,但只希望它显示出来,当用户输入搜索模式(通过点击搜索文本字段内)。 在这一时刻,我想取消按钮,执行标题“完成”(“取消”被赋予了不同的含义,以我的屏幕,因此定制)。

不过,这是我做了什么(caelavel的和Arenim的解决方案的组合):

子类的UISearchBar作为MyUISearchBar这两种方法:

-(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];

}

而在使用这个搜索栏的视图 - 控制,下面这段代码负责显示取消按钮和定制其名称:

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

奇怪的是,我没有做任何事情来隐藏取消按钮,因为它默认是隐藏的,当退出搜索模式。



Answer 6:

您可以通过搜索栏的子视图循环,并检查类的类型(而不是大小)的取消按钮:

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

然后更改色调颜色:

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


Answer 7:

如果你想配置你的取消按钮UISearchBar你应该得到UIButton从对象UISearchBar对象。 下面的示例

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;
    }
}


Answer 8:

自定义的UISearchBar和覆盖方法-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];
    }
}


Answer 9:

我给一个详细的关于UIAppearance技术回答。 首先,你需要了解的是,取消按钮是一个私人UINavigationButton:UIButton的。 一些检查后,似乎UINavigationButton将这些UIAppearance选择回应:

// 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:)

巧合的是,那些选择匹配的UIBarButtonItem一个的。 这意味着诀窍是使用两个单独的UIAppearance处理私有类UINavigationButton。

/* 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:...];

这将让你自定义您的取消按钮就像你想要的。



Answer 10:

你初始化你的UISearchBar后,您可以探测到它的子视图和自定义它们。 例:

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

    }

}

制定了非常适合我! 特别是梯度:)



Answer 11:

斯威夫特2.1.1:

有没有简单的方法来钩和风格的搜索栏,您需要从搜索栏手动抢子视图,然后应用更改。

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
   }
}


Answer 12:

首先我想从这个感谢@Eliott https://stackoverflow.com/a/37381821/1473144

我不得不做出一些调整,他的回答在我的规格低于去工作。 拜托,我问OP更新接受的答案,因为它是非常过时。

迅速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)
        }
    }

}


Answer 13:

嗯,这里是功能,它可以改变取消的按钮标签。 修改它,如果你想要的。 使用方法是:

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];
  }
 }
}


Answer 14:

- (void) searchBarTextDidBeginEditing:(UISearchBar *)theSearchBar 
{        
    NSArray *arr = [theSearchBar subviews];
    UIButton *cancelButton = [arr objectAtIndex:3];
    [cancelButton setTitle:@"yourtitle" forState:UIControlStateNormal];    
}

只要看看日志的ARR AMD看到该指标控制的谎言。 以同样的方式ü可以设置UITextField属性:

    NSArray *arr = [searchbar subviews];
    UITextField *searchfield = [arr objectAtIndex:2];
    [searchfield setTextAlignment:UITextAlignmentRight];


Answer 15:

我有我的整个应用程序许多的UISearchBar项目,所以我写了这个类来添加属性,以便您可以访问mySearchBar.cancelButton 。 (如果你是新来的类别, 此处详细了解与分类扩展对象 。)

请记住,你只能访问此当取消按钮是可见的 ,因为似乎的UISearchBar创建一个新的按钮对象每次显示的时间。 不要保存指针cancelButton,在需要的时候只得到它:

@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


Answer 16:

笨的方法

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


Answer 17:

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
}
}


Answer 18:

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];


Answer 19:

对于iOS 11和斯威夫特4.创建UISearchController的子类。 覆盖方法:

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)
        }
}


文章来源: Styling the cancel button in a UISearchBar