简体   繁体   中英

Keyboard bottom corner icons change color in iOS

I dont want my buttons on my keyboard to change colors if I globally update all buttons to have the same color. How can I control this manually to reset to the original color?

[[UIApplication sharedApplication] delegate].window.tintColor = [Helper getColor:color];
    [[UIButton appearance] setBackgroundColor:[Helper getColor:color]];

AppDelegate

@interface ExposureDelegate : NSObject <UIApplicationDelegate> {

}

@property (nonatomic, strong) IBOutlet ExposureWindow *window;
@property (nonatomic, strong) EventsViewController *eventsViewController;

@end

@implementation ExposureDelegate

@synthesize window;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {


      self.window = [[ExposureWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        [self.window setRootViewController:menuViewController];

        NSArray *windows = [[UIApplication sharedApplication] windows];
        for(ExposureWindow *w in windows) {
            NSLog(@"window: %@",window.description);
            if(w.rootViewController == nil){
                UIViewController* vc = [[UIViewController alloc]initWithNibName:nil bundle:nil];
                w.rootViewController = vc;
            }
        }

        [self.window makeKeyAndVisible];

在此处输入图片说明

You can define which views/classes should respect a UIAppearance rule using:

+ (instancetype)appearanceWhenContainedInInstancesOfClasses:(NSArray<Class<UIAppearanceContainer>> *)containerTypes;

( Relevant Documentation )

Now there are possibly a few ways to do this, this is just one. You can skip to the end if you want your answer, but I included more information to understand why and how if curious.

More relevant discussion for using this method:

Keep in mind that the array you pass is NOT a list of all the places you want the appearance proxy to work, if you pass in multiple in the same list it will be evaluated as a hierarchy where the first element is the most nested and the last element is the outermost.

AKA

[UIButton appearanceWhenContainedInInstancesOfClasses:@[[MyView class], [UITableView class]]] 

means to ONLY apply the rule to buttons that are inside MyView 's that are inside UITableView 's.


Another good thing to understand is how the rules are evaluated. UIKit will always check the longest hierarchies first. And it will always start checking on the outermost object (in most cases something like UIViewController ).

The appearance will be applied to the first hierarchy that matches.

AKA

UILabel.appearance(whenContainedInInstancesOf: [CustomView.self]).textColor = red;
UILabel.appearance(whenContainedInInstancesOf: [UIViewController.self]).textColor = UIColor.gray;

would mean that all your labels would show up gray since it starts checking on the outermost object, UIViewController and since thats a match it stops checking further.

But because longer hierarchies are evaluated first:

UILabel.appearance(whenContainedInInstancesOf: [CustomView.self, UIViewController.self]).textColor = red;
UILabel.appearance(whenContainedInInstancesOf: [UIViewController.self]).textColor = UIColor.gray;

Means labels will show up as red on CustomView as expected since the first line has two elements in its hierarchy, which means it will be checked before all the one element hierarchies like the second line.

FINALLY YOUR ANSWER:

So all we have to do is find a parent view or view controller somewhere in the stack of the keyboard window - and set a background color of clear on that...

Except, having inspected the full hierarchy of the keyboard window every single controller and view leading up to those buttons are private: 在此处输入图片说明 (I checked the class hierarchy, visible on the right, of every single view starting at the UIRemoteKeyboardWindow. They are all private)

Since we can't touch the system classes that leaves us with less options - we have to set rules that only apply to the UIWindow or UIViewControllers of our main app window.

I can imagine a solution where I have a custom UIViewController class called BaseController that ALL my VC's inherit from.. but that seems annoying. Why don't we just create a custom UIWindow class thats used in our own app instead:

(this is in Swift because it was easier for me)

// internal and final just included for compiler optimizations, not necessary
internal final class AppWindow: UIWindow {}

@UIApplicationMain
internal final class AppDelegate: UIResponder, UIApplicationDelegate {

    lazy var appWindow: AppWindow = {
        return AppWindow(frame: UIScreen.main.bounds)
    }()

...

// then wherever you're setting the key window make sure you use your custom one
appWindow.rootViewController = vc
appWindow.makeKeyAndVisible()

Now you can just apply the rules to AppWindow :

[[UIButton appearanceWhenContainedInInstancesOfClasses:@[[AppWindow class]]]
           setBackgroundColor:[Helper getColor:color]];

(you should be fine with the tint stuff as you have it written bc that already only affects the window being used the application)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM