キャンセルボタンがある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
やりたいことはかなり大変です。キャンセルボタンを取得するための組み込みのフックはありません。
ただし、ジミーがフードを開けて構わない場合は、いくつかのオプションがあります。
まず、UISearchBarはUIViewであり、[キャンセル]ボタンもビューです。これは、予想どおり、サブビューとして検索バーに追加されます。
少し実験してみましたが、ボタンが画面上にあるときのサイズは48、30であることがわかります。
したがって、viewWillAppearでは、次のようなことができます。
サイズが48,30の[searchBarサブビュー]でキャンセルボタンビューを探します。 (1つしかないようです。これは変更される可能性があります...)二重に注意して、ほぼ正しい位置にあるものを探します(横向きと縦向きでは異なります)。
サブビューをキャンセルボタンに追加します。
サブビューはUIControlにする必要があります(タッチイベントが実際のキャンセルボタンに到達するようにするために、enabled = NOに設定できます)。
正しい色と丸い角が必要です。私がまだ理解していない理由でサイズを変更する必要があります(55、30は動作するようです)
これはsearchBar.showsCancelButtonが常にYESの場合に機能します。検索文字列を編集していないときに非表示にしたい場合は、キャンセルボタンが表示されるたびにオーバーレイを追加するフックを見つける必要があります。
ご覧のとおり、これは見苦しい作業です。目を大きく開いてください。
UIAppearance
を使用すると、UISearchBar
のサブビューを繰り返さなくてもキャンセルボタンのスタイルを設定できますが、現在 UIButton
ヘッダーには_UI_APPEARANCE_SELECTOR
_ 。
編集:キャンセルボタンが表示されるまでサブビューをドリルダウンします
しかし、これは通常、searchBar.setShowsCancelButton(true, animated: true)
が呼び出されるまでnilを返します。
_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
}
}
_
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
の出現を使用しない方がよいでしょう。 UIBarButtonItem
をお試しください。
[キャンセル]ボタンのタイトルを変更します。
[[UIButton appearanceWhenContainedIn:[UISearchBar class], nil] setTitle:@"newTitle" forState:UIControlStateNormal];
対応するスウィフト:
let cancelButton = UIButton.appearance(whenContainedInInstancesOf: [UISearchBar.self])
cancelButton?.setTitle("cancel".localized, for: .normal)
これは元の質問に正確に関連しているわけではないかもしれませんが、UISearchBarの[キャンセル]ボタンをカスタマイズしようとするより広い意味で、解決策は依然として適用可能です。これはそのようなシナリオで行き詰まっている他の人を助けるだろうと思った。
私の状況は、キャンセルボタンのタイトルを変更することでしたが、ユーザーが検索モードに入ったときに(検索テキストフィールド内をクリックして)キャンセルボタンをデフォルトでは表示せず、表示するだけでした。 )。この瞬間、私はキャンセルボタンに「完了」というキャプションを付けたかったのです(「キャンセル」は画面に異なる意味を与えていたため、カスタマイズされました)。
それにもかかわらず、ここに私がやったことがあります(CaelavelとArenimのソリューションの組み合わせ):
次の2つのメソッドを使用して、MyUISearchBarとしてサブクラス化されたUISearchBar:
-(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];
}
奇妙なことに、検索モードが終了したとき、デフォルトでは非表示になっているので、キャンセルボタンを非表示にするために何もする必要はありませんでした。
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;
}
}
キャンセルボタンを見つけるには、検索バーのサブビューをループして、(サイズではなく)クラスタイプを確認します。
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]];
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のセレクターと一致します。トリックの意味は、2つの個別の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:...];
これにより、[キャンセル]ボタンを好きなだけカスタマイズできます。
カスタム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];
}
}
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
}
}
私のためにうまくいきました!特に勾配:)
Swift 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
}
}
まず第一に、これから@Eliottに感謝したいと思います https://stackoverflow.com/a/37381821/1473144
以下の仕様で機能するように、彼の回答を少し調整する必要がありました。承認された回答は非常に古いため、OPに更新を依頼してください。
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)
}
}
}
アプリ全体に多くの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
さて、これがキャンセルのボタンラベルを変更できる関数です。必要に応じて変更してください。使い方は:
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];
}
}
}
- (void) searchBarTextDidBeginEditing:(UISearchBar *)theSearchBar
{
NSArray *arr = [theSearchBar subviews];
UIButton *cancelButton = [arr objectAtIndex:3];
[cancelButton setTitle:@"yourtitle" forState:UIControlStateNormal];
}
AMDのログを取得して、AMDがどのインデックスコントロールがあるかを確認します。同様に、uは
UITextField
プロパティを設定できます。
NSArray *arr = [searchbar subviews];
UITextField *searchfield = [arr objectAtIndex:2];
[searchfield setTextAlignment:UITextAlignmentRight];
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];
IOS 11およびSwift 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)
}
}
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
}
}
愚かな方法
for(id cc in [SearchBar subviews])
{
if([cc isKindOfClass:[UIButton class]])
{
UIButton *btn = (UIButton *)cc;
......
Do whatever you want
.......
}
}