Cannot set text color of Send and Cancel buttons in the mail composer when presented from the UIActivityViewController in iOS7 - ios7

I am using the UIActivityViewController to share items in iOS7. When I tap on the Mail option, it pops up the mail composer, but the Cancel and Send buttons on the navigation bar and the navigation bar itself are blue, making it very difficult to read, so I want to change their color. It's working in iOS6 but not in iOS7.
I tried
[[UIBarButtonItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIColor redColor], UITextAttributeTextColor, [UIColor clearColor], UITextAttributeTextShadowColor, nil] forState:UIControlStateNormal];
which works in iOS6, and I tried
[[UIBarButtonItem appearance] setTintColor:[UIColor redColor]];
[[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];
which causes the color to flash red the first time the app is run before immediately switching back to the blue color.

Managed to change the text color of the Send and Cancel buttons, which are on the UINavigationBar in the MFMailComposerViewController (both Send and Cancel) and MFMessageComposeViewController (only Cancel), when presented from UIActivityViewController.
Using an UIActivityViewController, tap on Messageor Mail:
You'll notice that the default text color of the Send and Cancel buttons is blue:
In order to change that, in the AppDelegate.m class, in the didFinishLaunchingWithOptions method, insert the following line:
[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil] setTintColor:[UIColor whiteColor]];
This results in:
You can also use other colors, for example:
[UIColor purpleColor];
[UIColor greenColor];
How did I test this? I noticed this solution works for the following:
with Xcode 5.1, in the iOS 7.1 simulator, building as base iOS SDK 7.1 (can be chosen from selecting the project file -> Build Settings -> Base SDK. Also, selected from General -> Deployment Target -> 7.1)
with Xcode 5.1, on an iPhone 4, building as base iOS SDK 7.0 (can be chosen from selecting the project file -> Build Settings -> Base SDK. Also, selected from General -> Deployment Target -> 7.0)
with Xcode 5.1, on an iPhone 4, building as base iOS SDK 7.1 (can be chosen from selecting the project file -> Build Settings -> Base SDK. Also, selected from General -> Deployment Target -> 7.1)
It didn't work when testing with:
with Xcode 5.1, in the iOS 7.0 simulator, building as base iOS SDK 7.0 (can be chosen from selecting the project file -> Build Settings -> Base SDK. Also, selected from General -> Deployment Target -> 7.0)
Therefore it should be safe to use, as I believe the behavior on the actual device matters more than the behavior in the iOS simulator.
If anyone knows why it doesn't work in the iOS 7.0 simulator, I would like to know. :)

Bar tint color and status bar color in UIActivityViewController.
Swift 3 solution:
extension MFMailComposeViewController {
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIApplication.shared.statusBarStyle = UIStatusBarStyle.lightContent
}
open override func viewDidLoad() {
super.viewDidLoad()
navigationBar.isTranslucent = false
navigationBar.isOpaque = false
navigationBar.barTintColor = UIColor.white
navigationBar.tintColor = UIColor.white
}
}

Here is what works on iOS 7.1 as of today.
Subclass the UIActivityViewController and override the following method:
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
{
viewControllerToPresent.view.tintColor = [UIColor whiteColor];
[super presentViewController:viewControllerToPresent animated:flag completion:^{
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
if (completion) {
completion();
}
}];
}
This will make the buttons white and the status bar white.

For Swift:
self.navigationController?.presentViewController(activityViewController, animated: true, completion: { () in
UIBarButtonItem.appearance().tintColor = UIColor.whiteColor()
UINavigationBar.appearance().barTintColor = UIColor.whiteColor() // optional to change bar backgroundColor
}
This will change Send & Cancel button color to White (tested on iOS 7,8) but am still not able to make status bar text color white.( Although I have not tried that Subclass UIActivityViewController solution to change statusbar text color )

I fixed my issue by extending the UIActivityViewController and overriding the viewWillAppear and viewWilldisapper methods:
extension UIActivityViewController {
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UINavigationBar.appearance().barTintColor = .white
}
open override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.isOpaque = false
navigationController?.navigationBar.barTintColor = UIColor(red: (247/255), green: (247/255), blue: (247/255), alpha: 1)
//navigationBar.tintColor = UIColor.white
}
open override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
UINavigationBar.appearance().barTintColor = mycustomColor
}
}

This appears to be a bug with iOS 7. I've seen other reports of this online. It also doesn't appear to be fixed in iOS 7.1.
To be specific, no matter what you do, you cannot set tint colors on navigation bars for dialogs shown from the UIActivityViewController.

I had the same problem with my app where the tintColor property of UINavigationBar is white everywhere thanks to the appearance proxy. The resulting effect is that UIBarButtonItem from the mail composer view controller navigationBar were not visible (white buttons on a white navigation bar).
I have this call in my application:didFinishLaunchingWithOptions: method:
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
As it is impossible (for now ?) to access the UINavigationBar of the mail composer view controller in the UIActivityViewController, I did the following workaround which is inspired from Alex's answer:
UIColor *normalColor = [[UINavigationBar appearance] tintColor];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:dataToShare applicationActivities:nil];
[activityViewController setCompletionHandler:^(NSString *activityType, BOOL completed) {
// back to normal color
[[UINavigationBar appearance] setTintColor:normalColor];
}];
[self presentViewController:activityViewController animated:YES completion:^{
// change color temporary
[[UINavigationBar appearance] setTintColor:[UIColor colorWithRed:232.0f/255.0f green:51.0f/255.0f blue:72.0f/255.0f alpha:1.0f]];
}];
PS: this code is intented for iOS 7, but you can use [[UIBarButtonItem appearance] setTintColor:] in iOS 6 (cf Kevin van Mierlo's answer)

Well there are reasons for why we cannot change the way that the UI in apple's code is the way it is. Mostly because it is apple's. They do not allow you to edit the way the UI in MFMailComposerViewController looks in any way. If there is a way, then I have no clue about it, but I have never seen any way to do it. MFMailComposeViewController doesn't support the appearance attribute as it was created in iOS 3.0, and appearance didn't become a thing until iOS 5.0
Here is a link to the MFMailComposeViewController apple documentation: MFMailComposeViewController
Hope this helps!

If you want to set the color of the cancel and send buttons in iOS 7 you should use this:
// Change the colours of the buttons in iOS 7
[[UINavigationBar appearance] setTintColor:[UIColor redColor]];
In iOS 6 it is indeed these and you should also leave this in your code:
// Change the colours of the buttons in iOS 6
[[UIBarButtonItem appearance] setTintColor:[UIColor redColor]];
// Change the color of the the navigation bar in iOS 6 and 7
[[UINavigationBar appearance] setBarTintColor:[UIColor redColor]];

Try this code for may be it will help you
[[mailComposer navigationBar] setTintColor:[UIColor blackColor]];

I couldn't get Alex's solution to work, however I have managed to get a variation of Paillou's answer to work although I had to set both the barTintColor and the titleTextAttributes in my situation:
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:applicationActivities];
activityViewController.excludedActivityTypes = #[UIActivityTypePrint, UIActivityTypeCopyToPasteboard, UIActivityTypeAssignToContact, UIActivityTypeSaveToCameraRoll, UIActivityTypeAddToReadingList, UIActivityTypePostToVimeo, UIActivityTypePostToFlickr, UIActivityTypeAirDrop];
[activityViewController setCompletionHandler:^(NSString *activityType, BOOL completed) {
// back to normal color
[[UINavigationBar appearance] setBarTintColor:AAColorInputBorder];
[[UINavigationBar appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"Avenir-Medium" size:18], NSFontAttributeName,
[UIColor whiteColor], NSForegroundColorAttributeName,
nil]];
}];
[self presentViewController:activityViewController animated:YES completion:^{
// change color temporary
[[UINavigationBar appearance] setBarTintColor:[UIColor whiteColor]];
[[UINavigationBar appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"Avenir-Medium" size:18], NSFontAttributeName,
AAColorInputBorder, NSForegroundColorAttributeName,
nil]];
Thanks Paillou!

This has worked for me:
in AppDelegate.m in the function:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
I've entered the following code:
//mail composer
[[UINavigationBar appearanceWhenContainedIn:[MFMailComposeViewController class], nil] setBarTintColor:myBackgroundColor];
[[UINavigationBar appearanceWhenContainedIn:[MFMailComposeViewController class], nil] setTintColor:myBarItemsColor];
It works just fine on iOS7 + iOS8, did not try on newer versions

For ios7 i think that you should go through this code
[[UINavigationBar appearance] setTintColor:[UIColor redColor]];
If it is also not working then try Mail Compose View Controller apple documentation available on the internet.

Before presenting the mail composer insert this line like this:
[mailComposer.navigationBar setTintColor:[UIColor whiteColor]];
[self presentViewController:mailComposer animated:YES completion:nil];
Even though I set the status bar style in application did finish launching I also needed to set it again in the completion block like this:
[self presentViewController:mailComposer animated:YES completion:^{[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];}];

I had enormous trouble with this, especially when MFMailComposeViewController/MFMessageViewController are themselves displayed by UIActivityViewController.
I resorted to using method swizzling on viewDidAppear/viewDidDisappear to undo and then redo my app's customisation of colors and fonts, with some help from https://github.com/rentzsch/jrswizzle:
SwizzledComposeViewControllers.h
#import <MessageUI/MessageUI.h>
#interface MFMailComposeViewController (GMSwizzling)
#end
#interface MFMessageComposeViewController (GMSwizzling)
#end
SwizzledComposeViewControllers.m
#import "SwizzledComposeViewControllers.h"
#import "AppDelegate.h"
#import "JRSwizzle.h"
#implementation MFMailComposeViewController (GMSwizzling)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self jr_swizzleMethod:#selector(init) withMethod:#selector(gmswizzled_init) error:nil];
[self jr_swizzleMethod:#selector(viewWillAppear:) withMethod:#selector(gmswizzled_viewWillAppear:) error:nil];
[self jr_swizzleMethod:#selector(viewWillDisappear:) withMethod:#selector(gmswizzled_viewWillDisappear:) error:nil];
});
}
- (instancetype)gmswizzled_init {
[(AppDelegate*)UIApplication.sharedApplication.delegate uncustomiseAppearance];
return [self gmswizzled_init];
}
- (void)gmswizzled_viewWillAppear:(BOOL)animated {
[(AppDelegate*)UIApplication.sharedApplication.delegate uncustomiseAppearance];
[self gmswizzled_viewWillAppear:animated];
}
- (void)gmswizzled_viewWillDisappear:(BOOL)animated {
[(AppDelegate*)UIApplication.sharedApplication.delegate customiseAppearance];
[self gmswizzled_viewWillDisappear:animated];
}
#end
#implementation MFMessageComposeViewController (GMSwizzling)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self jr_swizzleMethod:#selector(init) withMethod:#selector(gmswizzled_init) error:nil];
[self jr_swizzleMethod:#selector(viewWillAppear:) withMethod:#selector(gmswizzled_viewWillAppear:) error:nil];
[self jr_swizzleMethod:#selector(viewWillDisappear:) withMethod:#selector(gmswizzled_viewWillDisappear:) error:nil];
});
}
- (instancetype)gmswizzled_init {
[(AppDelegate*)UIApplication.sharedApplication.delegate uncustomiseAppearance];
return [self gmswizzled_init];
}
- (void)gmswizzled_viewWillAppear:(BOOL)animated {
[(AppDelegate*)UIApplication.sharedApplication.delegate uncustomiseAppearance];
[self gmswizzled_viewWillAppear:animated];
}
- (void)gmswizzled_viewWillDisappear:(BOOL)animated {
[(AppDelegate*)UIApplication.sharedApplication.delegate customiseAppearance];
[self gmswizzled_viewWillDisappear:animated];
}
#end
(I have to admit I can't recall why I uncustomised appearances both in init and viewWillAppear, but I'm fairly sure there was a reason ...).

In Swift I made an extension for UIViewController:
extension UIViewController {
func presentActivityViewController(viewControllerToPresent: UIViewController) {
self.presentViewController(viewControllerToPresent, animated: true) { _ in
UIBarButtonItem.appearance().tintColor = UIColor.whiteColor()
UINavigationBar.appearance().barTintColor = Config.primaryColor
}
}
}
When I need to present an UIActivityViewController I call:
let activityViewController = UIActivityViewController(activityItems: items, applicationActivities: [])
presentActivityViewController(activityViewController)

In Swift, on iOS9, setting
UINavigationBar.appearance().barTintColor = UIColor.greenColor() // eg
UINavigationBar.appearance().translucent = false
before presenting the activity view controller did the trick for me.

I tried many different methods in iOS 9 and 10, but this is the only one that worked. Note that I have a background image behind the navigationBar as well:
[UIApplication.sharedApplication setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
NSDictionary *attribs = #{NSForegroundColorAttributeName:UIColor.whiteColor};
UINavigationBar.appearance.titleTextAttributes = attribs;
UINavigationBar.appearance.tintColor = UIColor.whiteColor;
[UINavigationBar.appearance setBackgroundImage:[UIImage imageNamed:#"IOSNavigationBar"] forBarMetrics:UIBarMetricsDefault];
UIBarButtonItem.appearance.tintColor = UIColor.whiteColor;

You can set your appearance before presenting UIActivityViewController. Add resetting of appearance to completionWithItemsHandler of your activity VC:
setNavBarAppearance()
activityVC.completionWithItemsHandler = { [weak self] _, _, _, _ in
self?.resetNavBarAppearance()
}
present(activityVC, animated: true, completion: nil)
The only problem, that if activity is like mail sending, it is full screen. Your appearance will not be applied to current visible views. A little hacks to solve it:
setNavBarAppearance()
activityVC.completionWithItemsHandler = { [weak self] _, _, _, _ in
self?.resetNavBarAppearance()
// Hacks(choose one of them):
// 1)
self?.navigationController?.isNavigationBarHidden = true
self?.navigationController?.isNavigationBarHidden = false
// 2)
let redrawTriggerVC = UIViewController()
redrawTriggerVC.modalPresentationStyle = .popover
self.present(redrawTriggerVC, animated: false, completion: nil)
redrawTriggerVC.dismiss(animated: false, completion: nil)
}
present(activityVC, animated: true, completion: nil)

I haven't found a mechanism I liked, so for what it's worth here's mine. Part of the trouble is later versions of iOS add the capability for apps to add system-wide Share and Action Extensions. These third-party items seem to be coded all sorts of ways. Some inherit the app's nav bar style, some use their own, and some seem to assume a white nav bar (but actually inherits from the app).
This is tested on iOS 12.2.
I create an UIActivityItemSource, to which I have:
- (nullable id)activityViewController:(nonnull UIActivityViewController *)activityViewController itemForActivityType:(nullable UIActivityType)activityType {
if (activityType == UIActivityTypePrint || [activityType.lowercaseString containsString:#"extension"] || [activityType containsString:#"AssignToContact"]) {
//What a hack, but the best I can do. Seems some extensions inherit nav style from parent, others don't.
//ActionExtension is bottom row; all those I tested need this. The string comparison catches most non-OS extensions (the type is set by developer).
[[UINavigationBar appearance] setBarTintColor:[UIColor kNavigationBarBackgroundColor]]; //kNavigationBarBackgroundColor is my app's custom nav bar background color
} else {
[[UINavigationBar appearance] setBarTintColor:[UIColor whiteColor]];
}
return self.pdfData; //In my case I'm sharing a PDF as NSData - modify as needed for your shared item
}
Then in my UIActivityViewController's completionWithItemsHandler I include:
[[UINavigationBar appearance] setBarTintColor:[UIColor kNavigationBarBackgroundColor]]; //Again, this is my app's custom nav bar background color
Unrelated to the specific issue, but if you don't currently have a UIActivityItemSource you need to do something like this:
NSArray *activities=#[self]; //And set self to be a UIActivityItemSource
UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:activities applicationActivities:nil];
I'm sure this isn't 100% reliable, but worked with all extensions I tried.

Related

iOS 9 Contact List buttons White on White

I realize that ABPeoplePicker has changed for iOS 9 but the functionality is still there and working for now. The issue I am having is that the "Group" and "Cancel" buttons are coming up as white on a white background. So very hard to see. The previous controller that this is coming from does make use of white buttons on its nav bar but of course the background is darker.
I have tried to use the following which works under iOS 8 but seems to do nothing under iOS 9:
[[UIBarButtonItem appearanceWhenContainedIn:[ABPeoplePickerNavigationController class], nil] setTintColor:[UIColor blueColor]];
I have tried to directly set it as well with the navigationcontroller.navbar.tintcolor property. That didn't work under 8 or 9.
How can I get these buttons to be visible on the contact page?
Update: I have also tried this which doesn't work either:
[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:#[[ABPeoplePickerNavigationController class]]] setTintColor:[UIColor blueColor]];
Update 2: I tried using the new CNContactPickerViewController and it does the same thing with white on white.
I also faced this issue earlier. To fix this, you need to set tint colour for UINavigation bar like below:
[[UINavigationBar appearance] setTintColor:[UIColor blueColor]];
ex:
- (void)showContactList
{
[[UINavigationBar appearance] setTintColor:[UIColor blueColor]];
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
[self presentViewController:picker animated:YES completion:nil];
}
I don't know how but this worked for me:
// Text color of navigation bar
let textAttributes = [NSForegroundColorAttributeName:UIColor.color_template_1_2()]
UINavigationBar.appearance().titleTextAttributes = textAttributes
UINavigationBar.appearance().tintColor = UIColor.color_template_1_2()
let contactPicker = CNContactPickerViewController()
contactPicker.delegate = self
contactPicker.displayedPropertyKeys =
[CNContactPhoneNumbersKey]
self.present(contactPicker, animated: true, completion: {
let textAttributes2 = [NSForegroundColorAttributeName:UIColor.white]
UINavigationBar.appearance().titleTextAttributes = textAttributes2
UINavigationBar.appearance().tintColor = UIColor.white
})

How to change Status Bar text color in iOS 8 embeded with UInavigationController?

iOS8.1(xcode 6.1)
I used the below method to change the status bar text color.
[self setNeedsStatusBarAppearanceUpdate];
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent; }
following the link preferredStatusBarStyle isn't called
But this is not working for me.Anyone knows how to change status bar color related to uinavigationcontroller.
set UIViewControllerBasedStatusBarAppearance to YES in your info.plist
override - (UIViewController *)childViewControllerForStatusBarStyle in your navigationController. return your childVC
override preferredStatusBarStyle or something need.
code:
- (UIStatusBarStyle)preferredStatusBarStyle{
return self.test?UIStatusBarStyleLightContent:UIStatusBarStyleDefault;
}
- (IBAction)test:(id)sender {
self.test = !self.test;
[self setNeedsStatusBarAppearanceUpdate];
}
let me know if it don't work.
You can customize the title text style on UINavigationControllers by assigning an NSDictionary containing your settings to the titleTextAttributes property.
NSDictionary *titleTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
[UIColor whiteColor], NSForegroundColorAttributeName, nil];
[[UINavigationBar appearance] setTitleTextAttributes:titleTextAttributes];
More stack overflow discussion here, and apple ref here.

iOS: Tabbar Tint Color

I'm creating a TabBar in code:
self = [super init];
self.tabBarController = [[UITabBarController alloc]init];
self.tabBarController.delegate = self;
self.tabBarController.navigationController.delegate = self;
//Build Model
NSArray *topLevelControllers = [self buildTopLevelControllers];
[self.tabBarController setViewControllers:topLevelControllers animated:NO];
//Inbox will be lead navigation
self.tabBarController.selectedIndex = kSelectedIndex;
[self.view addSubview:self.tabBarController.view];
self.tabBarController.customizableViewControllers = #[];
return self;
}
In App Delegate I have the following code for Tint:
[[UIView appearance] setTintColor:[ColorUtils globalTintColor]];
Problem: When the App launches, all the icons in the Tab Bar are tinted with the global color. When I select one and then unselect it, they go back to Grey (images default color).
Desired Result: When the App launches, all the buttons are Grey (Grey is the image color in the PNGs). When I tap on the tab bar icon, the color changes to the global tint color.
Tried: In the App delegate, I have added the following code and it does NOT work:
TabBarVC *tabBarVC = [[TabBarVC alloc]init];
tabBarVC.tabBarController.tabBar.tintColor = [UIColor greyColor];
tabBarVC.tabBarController.tabBar.selectedImageTintColor = [STColorUtils globalTintColor];
[[UINavigationBar appearance] setTitleTextAttributes:#{NSForegroundColorAttributeName : [ColorUtils globalTintColor]}];
[[UIView appearance] setTintColor:[ColorUtils globalTintColor]];
[self.window setRootViewController:tabBarVC];
However, if I comment out:
//[[UIView appearance] setTintColor:[ColorUtils globalTintColor]];
The icons do appear Grey, but the global tint color is iOS7 default: Blue.
There is a known issue with selectedImageTintColor in iOS 7. Last I checked this has yet to be resolved. So remove -
tabBarVC.tabBarController.tabBar.selectedImageTintColor = [STColorUtils globalTintColor];
Also you want to use the UITabBar's appearance so replace
[[UIView appearance] setTintColor:[ColorUtils globalTintColor]];
with
[[UITabBar appearance] setTintColor:[ColorUtils globalTintColor]];
this is the best solution i've found so far:
[UIView appearance].tintColor = [UIColor redColor];
// the selected image and text will still use UIView.tintColor.
// this is to tint the unselected images until they are tapped
// [UIColor grayColor] does not exactly match the default color, but it's subtle
[UIView appearanceWhenContainedIn:[UITabBar class], nil].tintColor = [UIColor grayColor];
when using swift i needed to create an objective-c file that contains a +(UIView *)viewAppearanceWhenContainedInTabBar() method to use [UIView appearanceWhenContainedIn:] method as it is not available to swift :(
change the UIWindow's tintColor property. It's applied across every UIView which is added onto this window.

UISearchBar text color change in iOS 7

How to change text color of UISearchBar in iOS 7?
In iOS 6, I was subclassing the UISearchBar and in layoutSubviews customising the properties of UITextField subview of UISearchBar.
But in iOS 7, UISearchBar doesn't have UITextField as its subview. How to fix this?
In iOS 7 to access Text Field you have to reiterate on level more. Change your code like this
for (UIView *subView in self.searchBar.subviews)
{
for (UIView *secondLevelSubview in subView.subviews){
if ([secondLevelSubview isKindOfClass:[UITextField class]])
{
UITextField *searchBarTextField = (UITextField *)secondLevelSubview;
//set font color here
searchBarTextField.textColor = [UIColor blackColor];
break;
}
}
}
Note : This is Not Public API
OR
You can use appearance Property of UIControls, Like
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:#{NSForegroundColorAttributeName:[UIColor redColor]}];
Note: Appearance proxy can be used for iOS 9.0+
OutPut
You can set The tintcolor to apply to key elements in the search bar.
Use tintColor to tint foreground elements.
Use barTintColor to tint the bar background.
In iOS v7.0, all subclasses of UIView derive their behavior for tintColor from the base class. See the discussion of tintColor at the UIView level for more information.
Apple Doc
You can set the text colour by
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor blueColor]];
For XCode 6 (iOS8 SDK) the following DOESN'T work
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor redColor]];
But the following DOES work (for deployment to iOS7 and iOS8)
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:#{NSForegroundColorAttributeName:[UIColor redColor]}];
While it's true that the UIAppearance protocol is a "public API," it's not true that UITextField supports this.
If you take a look at UITextField.h and look for the string "UI_APPEARANCE_SELECTOR" you'll see that it has no instances of this string. If you look at UIButton, you find quite a few - these are all of the properties that are officially supported by the UIAppearance API. It's somewhat well-known that UITextField is not supported by the UIAppearance API, so the code in Sandeep's answer will not always work and it's actually not the best approach.
This is a useful post with useful links: http://forums.xamarin.com/discussion/175/uitextfield-appearance
The correct approach is unfortunately messy - iterate through the subviews (or subviews of main subview for iOS7) and set it manually. Otherwise you will have unreliable results. But you can just create a category for UISearchBar and add a setTextColor:(UIColor*)color method. Example:
- (void)setTextColor:(UIColor*)color
{
for (UIView *v in self.subviews)
{
if([Environment isVersion7OrHigher]) //checks UIDevice#systemVersion
{
for(id subview in v.subviews)
{
if ([subview isKindOfClass:[UITextField class]])
{
((UITextField *)subview).textColor = color;
}
}
}
else
{
if ([v isKindOfClass:[UITextField class]])
{
((UITextField *)v).textColor = color;
}
}
}
}
Caution : This should lead to App Rejection!
KVC FTW. This did it for me.
UITextField *searchField = [self.searchBar valueForKey:#"_searchField"];
searchField.textColor = [UIColor redColor];
You can set the text attributes like so
[[UITextField appearanceWhenContainedIn:[<YOUR_CONTROLLER_NAME> class], nil] setDefaultTextAttributes:#{NSForegroundColorAttributeName:[UIColor whiteColor], NSFontAttributeName:[UIFont systemFontOfSize:14.0]}];
Here is working example done in C# using Xamarin:
SearchBar = new UISearchBar ();
foreach (var subView in SearchBar.Subviews) {
foreach (var field in subView.Subviews) {
if (field is UITextField) {
UITextField textField = (UITextField)field;
textField.TextColor = UIColor.White;
}
}
}
Hope this helps someone.
This seems to be the correct answer https://stackoverflow.com/a/19315895/2493073
The Swift version of it is:
UITextField.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).textColor = UIColor.blueColor()
This would only work for iOS 9.0, in order to make it work for lower versions you'll need to follow this question. https://stackoverflow.com/a/27807417/2493073
Swift Extension
public extension UISearchBar {
public func setTextColor(color: UIColor) {
let svs = subviews.flatMap { $0.subviews }
guard let tf = (svs.filter { $0 is UITextField }).first as? UITextField else { return }
tf.textColor = color
}
}
In my case, I have multiple UISearchBar objects and they need to change the textField font color. The appearanceWhenContainedIn update one UISearchBar behavior, but another doesn't.
I subclass the UISearchBar and implement custom -(id)initWithFrame: as following, and it works.
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.searchBarStyle = UISearchBarStyleMinimal;
self.tintColor = [UIColor whiteColor];
self.barTintColor = [UIColor whiteColor];
[[UITextField appearanceForTraitCollection:self.traitCollection whenContainedIn:[self class], nil] setDefaultTextAttributes:
#{
NSForegroundColorAttributeName : [UIColor whiteColor]
}];
}
return self;
}
UIAppearance Protocol Reference said that,
In other words, the containment statement in
appearanceWhenContainedIn: is treated as a partial ordering. Given a
concrete ordering (actual subview hierarchy), UIKit selects the
partial ordering that is the first unique match when reading the
actual hierarchy from the window down.
So, appearanceWhenContainedIn: won't deal with all UISearchBar in the hierachy of UIWindow. And it suggests that.
Use the appearanceForTraitCollection: and
appearanceForTraitCollection:whenContainedIn: methods to retrieve the
proxy for a class with the specified trait collection.
The easiest way to do it is by putting this code in viewDidAppear or viewWillAppear:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:#{NSForegroundColorAttributeName:[UIColor whiteColor]}];
This works in iOS 8 and Xcode 6, unlike some of the other code. It can mess around with the font and text size, etc, but you can change that in the text attributes.
That changes the text colour for all search bars in your app. If you only want to change one, use the above code, and then in any other views with a search bar, use the same code but set the colour to whatever you want.
you can use search bar inside textfield
UISearchBar * searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 50, 320, 44) ];
searchBar.autocorrectionType = UITextAutocapitalizationTypeWords;
searchBar.delegate = self;
searchBar.searchBarStyle = UISearchBarStyleMinimal;
searchBar.barTintColor = [UIColor redColor];
[[UITextField appearanceWhenContainedIn:[searchBar class], nil]setDefaultTextAttributes:#{NSForegroundColorAttributeName:[UIColor whiteColor]}];
[self.view addSubview:searchBar];
Update in Swift 3
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).textColor = UIColor.black
Even though I would have preferred to use appearance API, it didn't work with iOS8. Here's the least hackish solution I did come with:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (self.shouldEnableSearchBar)
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
UITextField *searchBarTextField = [[AFPBaseViewController findSubviewsOfView:self.searchBar ofClass:[UITextField class]] firstObject];
searchBarTextField.textColor = AFPConstantsColorGold;
});
}
}
You could maybe even create a UIView category with this. The reason why this has to be called in viewDidAppear is that UISearchBar is actually contained in a ViewController, and doesn't load all its subviews until it has appeared on screen. It could be added into viewWillAppear too, but I haven't tested it.
+ (NSArray *)findSubviewsOfView:(UIView *)view ofClass:(Class)class
{
NSMutableArray *targetSubviews = [NSMutableArray new];
for (id subview in view.subviews)
{
if ([subview isKindOfClass:class])
{
[targetSubviews addObject:subview];
}
if ([subview subviews].count)
{
[targetSubviews addObjectsFromArray:[self findSubviewsOfView:subview ofClass:class]];
}
}
return targetSubviews.copy;
}
This is the right solution for iOS8:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:#{NSFontAttributeName: [UIFont fontWithName:#"Helvetica" size:14], NSForegroundColorAttributeName:[UIColor lightGrayColor]}];
You have to set the font as well, otherwise, the font size will be wrong.
This class will give you full control over every item in the UISearchBar
import UIKit
class SMTSearchBar: UISearchBar {
override init(frame: CGRect) {
super.init(frame: frame)
initialize()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
initialize()
}
convenience init() {
self.init(frame: CGRectZero)
initialize()
}
// Style the view
func initialize() {
// Search Area
let searchField = valueForKey("searchField") as! UITextField
searchField.textColor = Colors.White
searchField.font = UIFont(name: Fonts.MuseoSans500, size: 16)
searchField.backgroundColor = Colors.Black.colorWithAlphaComponent(0.1)
// Icons
let searchIcon = UIImage(named: Icons.Search)?.imageWithTint(Colors.White)
let smallClearIconNormal = UIImage(named: Icons.SmallClear)?.imageWithTint(Colors.White)
let smallClearIconHighLight = UIImage(named: Icons.SmallClear)?.imageWithTint(Colors.White.colorWithAlphaComponent(0.5))
setImage(searchIcon, forSearchBarIcon: .Search, state: .Normal)
setImage(smallClearIconHighLight, forSearchBarIcon: .Clear, state: .Highlighted)
setImage(smallClearIconNormal, forSearchBarIcon: .Clear, state: .Normal)
}
func setPlaceHolder(placeholder: String) {
for subView in subviews{
for subsubView in subView.subviews {
if let textField = subsubView as? UITextField {
textField.attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [NSForegroundColorAttributeName: Colors.White.colorWithAlphaComponent(0.5)])
}
}
}
}
}
Usage (in navigation bar)
let searchBar:SMTSearchBar = SMTSearchBar()
searchBar.sizeToFit()
searchBar.setPlaceHolder("Search for cool things")
navigationItem.titleView = searchBar
searchBar.becomeFirstResponder()

applicationMusicPlayer volume notification

I am using an applicationMusicPlayer and when i try to change the volume appear the visual notification, as shown in the picture.
Here the code I am using:
[MPMusicPlayerController applicationMusicPlayer] setVolume:newVolune];
Anyone knows how to hide this notification?
I don't know where the docs says so, but if you add a MPVolumeView view to your app the system volume overlay goes away. Even if it is not visible:
- (void) viewDidLoad
{
[super viewDidLoad];
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame: CGRectZero];
[self.view addSubview: volumeView];
[volumeView release];
...
}
You can use the hardware volume buttons, the setVolume method or directly interact with the control (if visible) that the overlay doesn't show up.
For iOS6 I had to set an image with alpha 0 and non-zero size to the MPVolumeView's image fields in order to get the default volume change notification to disappear.
// hide the hardware volume slider
UIImage *thumb = [[UIImage alloc] initWithCIImage:[UIImage imageNamed:#"volumeHider"].CIImage scale:0.0 orientation:UIImageOrientationUp];
MPVolumeView *hwVolume = [[MPVolumeView alloc] initWithFrame:self.frame];
[hwVolume setUserInteractionEnabled:NO];
hwVolume.showsRouteButton = NO;
[hwVolume setVolumeThumbImage:thumb forState:UIControlStateNormal];
[hwVolume setMinimumVolumeSliderImage:thumb forState:UIControlStateNormal];
[hwVolume setMaximumVolumeSliderImage:thumb forState:UIControlStateNormal];
[self addSubview:hwVolume];
This made the MPVolumeView be "visible" on the screen, but invisible to the user.
I encountered the same issue recently. Instead of adding the MPVolumeView to current view controller's view, I add it to the application's window once at the start of the app:
CGRect rect = CGRectMake(-500, -500, 0, 0);
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:rect];
[self.window addSubview:volumeView];
This works in both iOS 7 and 8.
Swift 3
You can hide the System MPVolumeView using
override func viewDidLoad() {
super.viewDidLoad()
let volumeView = MPVolumeView(frame: CGRect.zero)
self.view.addSubview(volumeView)
}
I had success with this in iOS 6. Although it wouldn't perform well. It caused quite a bit of lag when sliding the thumbImage. I did have to take out the last 2 lines of code in order for this to work.
[volumeView release];
...
For me, on iOS 7, none of above solutions worked. Here is how I did it:
_volume = [[MPVolumeView alloc] initWithFrame: CGRectMake(-100,-100,16,16)];
_volume.showsRouteButton = NO;
_volume.userInteractionEnabled = NO;
[self.view addSubview:_volume];
[_volume release];
That is, simply set MPVolumeView's frame to an off-screen location such as (-100,-100).