Resetting the appearance of UIBarButtonItems and UINavigationBar - ios

Let us say I used some code to change the appearance property of the UINavigationBar including the UIBarButtonItems in my app. Is there any simple way to reset the appearance for some specific views to the default iOS style?

A couple of options I can think of.
Save the initial state in variables (background, font etc) to use
later during the reset.
Destroy and recreate the view. If this is done during a transition
(page switch etc) it may not be noticeable to the user.
Keep the original view hidden behind the new view and destroy the
new view when you want to reset it. (This may be memory expensive.)
I think your best bet may be to create a custom object (extend the original NavBar etc), save its original appearance variables (color, font etc) and add a reset option to be called by the controller.

Related

How do you properly dim tint colors when tintAdjustmentMode is active and using the new contentConfigurations?

Say I want to mimic this "Shut Down" blue-tinted button in the iOS Settings app using the new (as of iOS 14) cell content configuration options:
How would I do this in a way that would also allow it to be properly dimmed if a user presented, say, an alert controller over top? For the unaware in this case it "dims" all the interactive/tinted views like this one to a grey color. Here's an example where an alert controller is shown over a grid of UIImageView buttons with a normally blue tint where you can see they're grey due to the action sheet:
But with cell content configurations, at least the default one, the only option I get for changing text color is via textProperties.color = ..., and since this isn't technically a "tint" (and there's no tint option I can see) it remains blue even when other views properly dim.
How do I fix this?
I tried reading the value of tintAdjustmentMode in the updateConfiguration method of the cell subclass, but it's not called for tintAdjustmentMode changes. I then tried calling setNeedsUpdateConfiguration() manually when tintColorDidChange() is called on the subclass, but that causes a brief delay in the color changing which looks bad/out of sync with other views.
Is there a way to do this that I'm missing?

iOS custom error popup

I would like to add "more info" collapsible accordion into my error alert view. So it will expand with additional information about the err after user presses it. And of course it will animate the size of error alert too. How it can be done? Maybe there is already existing solution for what I need?
Thanks a lot!
The standard UIAlertView does not allow this. You'll have to make your own view that mimicks the appearance of an alert view (using a UIVisualEffectView and possibly even a UIInterpolatingMotionEffect if you really want it to look like the real thing). Takes a fair but of work, especially if you want to support older iOS versions. And of course with every new iOS version that changes the appearance of alerts, you'll have to update the code. You might be better off just going with a completely different appearance unique to your app.
Once you have made that custom view, you can add the extra field as a hidden text field. When the triangle button is pressed, you set the height of that hidden field to 0, unhide it, then animate the height of the text field and the height of the containing view to their new values.
Try this custom alert view
https://github.com/wimagguc/ios-custom-alertview
You can add whatever animation you want.

How to prevent using UIAppearance with UIView's tintColor from changing all UITabBar icon colours?

If I perform UIView.appearance().tintColor = ... the tintColor of all the icons in the tab bar change from the normal inactive grey state to whatever I set the tint color to.
I don't understand why this is the case. I'm just changing the tint color of the app, and by default the tint color doesn't mess with making all the tab bar icons look active at once.
How do I stop it from doing this? I want the tint color to change, but the unselected tabs to retain an inactive color.
I hope you've found a solution by now, but here's my two cents anyway.
Interface Builder doesn't use the UIAppearance API anywhere (as far as I am aware). It does, however, set properties on certain objects, to be applied to them as they're instantiated.
There is a "Global Tint" property in the File Inspector which controls the top-level default tintColor. It is worth noting that, unless explicitly told a different color to use (whether via UIView.appearance() or just UIView.tintColor) child views inherit their tintColor from their parent views. Remember, this chain continues up through the view hierarchy until it hits something that has a tintColor. Usually, it's the UIWindow it ends up hitting, and that has the default blue color of which Apple is so fond. Any dimming or temporary recoloring for state is inherited either from the view itself, or a close ancestor. This is important to note.
It is also good to note that you can respond to this in UIViewController by overriding the tintColorChanged() method, which gets called whenever this happens. By messing with UIView.appearance(), you effectively disable the chain of inheritance for every view in the hierarchy, and you let each fend for itself for its own colors. In my mind, there are at least two ways that this might prevent a UITabBar from properly representing a tab's state:
First, the tab bar has tinted image views under the hood, which inherit their tint color from the parent UITabBar. Even if they could get state-specific colors from the tab bar, the poor thing wouldn't have anything different to tell them, other than, "You were given a color, and you will respect that color!", followed by a slap and a sound flogging, at which point they would sulk back, knowing no more than before. By disabling the hierarchical tintColor inheritance system, you disable state. That's not good. Don't do that.
Second, by setting the tint color for every UIView regardless of state, you have told the tab bar items to hold that color regardless of state. That's not good. Don't do that either.
If you're using Interface Builder (or Storyboards if you prefer), I'd recommend setting that global tint color in the File Inspector, and leaving it at that. This would still set your tint color the way you want, while saving these poor views from domestic abuse.
If you need screenshots of where to find the File Inspector or the Global Tint option, I'd suggest poking around that sidebar on the right in Xcode. A little poking around never hurt anybody (except in movies).
What do you mean when you say you're "changing the tint color of the app"?
The UIView appearance proxy is doing exactly what you told it to. You asked it to set the tintColor of ALL UIViews in your app, which includes those views inside your UITabBar.
It sounds like you don't actually want to alter the tintColor of all UIViews, but instead want to target a specific subset. You should look into appearanceForTraitCollection or the (now deprecated) appearanceWhenContainedIn methods.

Is there any way to allow a view to be automatically "click-throughable" in a Storyboard?

I have a dark overlay I occasionally present over the full tableview, and I'd like to set it up in the Storyboard, but when I do, it obfuscates access to all the views beneath it (AKA all the views).
Setting it to hidden makes it transparent, but you can still click it. Is there any way to make it click-throughable all the time?
Set the property userInteractionEnabled to NO on your dark overlay view and all user touches should pass through.
Edit:
The simple answer is no. You cannot change how interface builder works. Besides, it's better to do things in code, especially when collaborating.

Changing UIToolBar (appearance) at runtime

I want to change an UIToolBar at runtime. In it's initial state, is has only one button, when that button is pressed i want it to change it's appearance to show 4 buttons. One of these buttons should cause the first UIToolBar to reappear.
Im seeing two approaches:
1) Have two UIToolBar nibs, and load them as needed.
2) Having all buttons on the first UIToolbar, and hide/show them as needed.
What would be the correct approach?
Personally, I would want to see all 4 button at initial launch with only relevant button in enabled state and rest in disabled state. Once I tap on the already enabled button I should see other buttons getting enabled. This is less surprising UI for end user. However, you can also go with #2 mentioned above in which case you might want to add some animation effect for better user experience.
The second approach would be better, because if you want to add more buttons tomorrow, you need to maintain 2 nib files instead of one.
But, think again is creating toolbar in xib file good solution?
I would create custom toolbar extending UIToolbar class and make 2 methods in it:
-(NSArray*) toolbarButtonsInitial;
-(NSArray*) toolbarButtonsExtended;
-toolbarButtonsInitial method returns UIBarButtonItems for initial state
-toolbarButtonsExtended method returns UIBarButtonItems for second state.
IMHO, this way has several advantages:
Your xib file doesn't have hidden buttons, or some button above other
one
If you need to add or remove some buttons you can do that easily for
each state
You can easily reuse this toolbar on other screens and create new
states if necessary

Resources