Larger search bar in iOS 11? How to opt-into new style? - ios

I noticed that in the App Store app, the UISearchBar they're using is larger. (see attached) — Currently when I compile for iOS 11b9 using Xcode 9b6, it still uses the old style, which is too small and is clipped by the status bar.
Is there some clean way to enable/mimic this larger variant of UISearchBar, while still maintaining backwards compatibility with older iOS versions?

I did find after the iPhone X announcement (and subsequent video additions to the Developer site) that there is a bit of a workaround necessarily: https://developer.apple.com/videos/play/fall2017/201
For iOS 11+ only:
Apply the UISearchController to the "navigationItem" not the UIViewController itself. Then set it to be "active" (= true).
Ensure this hidesNavigationBarDuringPresentation is true.
Monitor the delegate callback to track when it was dismissed, and then remove it from the "navigationItem" until it's needed again.
... Honestly it seems like this was a bit of an afterthought, but it does work and is good enough for now.

Related

A fully Immersive fragment doesn't always hide the StatusBar when first launched

Since Android 11 the correct way of displaying a fully immersive fragment is by hiding and showing StatusBar and NavigationBars via the following code which fully supports all devices with a camera notch, at any API level. Note the WindowCompat version replaces the framework version, so you don’t need to check for a particular API level as you did when using the framework version.
Hide
WindowCompat.SetDecorFitsSystemWindows(Activity.Window, false);
WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.GetInsetsController(Activity.Window, Activity.Window.DecorView);
windowInsetsControllerCompat.SystemBarsBehavior = WindowInsetsControllerCompat.BehaviorShowTransientBarsBySwipe;
windowInsetsControllerCompat.Hide(WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars());
Show
WindowCompat.SetDecorFitsSystemWindows(Activity.Window, true);
WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.GetInsetsController(Activity.Window, Activity.Window.DecorView);
windowInsetsControllerCompat.Show(WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars());
This eliminated the overly complex, very poorly documented and potentially error-prone code like below, which was used prior to Android 11.
Window.DecorView.SystemUiVisibility = (StatusBarVisibility) (SystemUiFlags.Fullscreen |
SystemUiFlags.HideNavigation |
SystemUiFlags.Immersive |
SystemUiFlags.ImmersiveSticky |
SystemUiFlags.LayoutHideNavigation |
SystemUiFlags.LayoutStable |
SystemUiFlags.LowProfile);
I was attempting to provide a choice of either displaying all fragments fully immersive or allowing some fragments to display as “letterboxed” i.e. not allowing the window to render into the DisplayCutout area. So my existing preference choice Devices with Notches/Cutouts allow full screen display would have to change to support multiple choice.
The problem I hit was that code I had used (like the WindowCompat code above since Android 11) was failing to display the fragment fullscreen when first launched. When it opened for the first time the window would attempt to go full screen, but only the NavigationBar would be removed. The StatusBar area was left as a black rectangle. You could see the animation of the time on the left and the icons on the right side of the StatusBar disappearing, (statusBar contents removed) but the window didn’t render into the StatusBar area. Immediately when rotated, the fragment became full screen and when rotated back to Portrait it corrected itself and was full screen again.
So in frustration, I went hunting on StackOverFlow looking for a solution but everything I found suggested that my ImmersiveFragment class was coded correctly. Then because this was my first attempt at using Material 3, I then started to suspect Material3, so I went backwards to my NavigationGraph6 project (Material2) and after much testing, I was able to reproduce the same problem, which eliminated Material3.
More searching on StackOverflow and I came across a Kotlin post that was the same as all the others, except that it had the following line – equivalent to this C# line.
Activity.Window.AddFlags(WindowManagerFlags.LayoutNoLimits)
So I added that line before the WindowCompat.SetDecorFitsSystemWindows(Activity.Window, false) in the HideSystemUi() and then cleared the flags before the WindowCompat.SetDecorFitsSystemWindows(Activity.Window, true) line in the ShowSystemUi with
Activity.Window.ClearFlags(WindowManagerFlags.LayoutNoLimits)
and immediately it worked.
So my question is why is this required and has anyone come across the same problem with immersive fragments?
Definition of LayoutNoLimits – Allow window to extend outside of the screen ???.
Does anyone have a clue what this definition actually means?
To test the code (comment out the new lines in ImmersiveFragment.cs). You can find the project NavigationGraph7 at https://github.com/gmck/NavigationGraph7. The immersiveFragment is the RaceResultsFragment (inherits from ImmersiveFragment) accessed by the BottomNavigationBar on the SlideShowFragment.
I referred to the official doc both Android and Microsoft too. As you said that: "Allow window to extend outside of the screen". There are few official definitions of it...
You can check Can I set FLAG_LAYOUT_NO_LIMITS only for status bar?, it talks about usage of LayoutNoLimit. Wish it could be helpful to you.

Indentation of UITableViewCell changes after rotation only on iOS 8

I have an UITableView with three dynamic rows. When displaying the UITableViewController the first time everything works fine. After a rotation the rows which have a data in it get an indentation despite I set setLayoutMargins to zero. I cannot reproduce this issue in another project until now. It is only appearing in iOS 8 but but only on one table. The same source for the table is working in a test project without problems. The only difference here is that it is in a container with some other views.
I checked auto layout constraints, the rotation methods, commented things out - all without success. The change of the indentation occurs between willRotateToInterfaceOrientation and didRotateToInterfaceOrientation or after viewWillTransitionToSize. I even updated to iOS 8.1 with the same results.
Has someone expeerienced a similar behavior?
PS:
What I've also noticed that when setting the layout margins to zero on iOS 8 the animation is not as smooth as it would be with the default values (with indentation). On iOS 7 the animation is always smooth.
EDIT:
I tracked some things down. If a UITableViewController is embedded into an UINavigationController the indentation happens on rotation. If you rotate further it goes back to it's set indentation (no indentation in my case).
If the UITableViewController is embedded into a container (and this container is in a navigation controller) than after the rotation the cell get it's default indentation back. If you rotate further this behavior stays the same (always indented).
Are some events not send to the child view controller or none of you uses a UITableViewController embedded into an UINavigationController?
In my opinion it is a iOS 8 Bug or a Xamarin Bug. Perhaps one other could verify if it is the same with his installation. I'm using Xamarin Studio 5.5.2 with Xcode 6.1.
One ugly solution to this is this:
public override void DidRotate (UIInterfaceOrientation fromInterfaceOrientation)
{
base.DidRotate (fromInterfaceOrientation);
// otherwise cells are indented! iOS 8 Bug?
TableView.ReloadData ();
}
One could use reloadData or reloadSection in didRotateFromInterfaceOrientation, despite it is a deprecated function. But there is no viewDidTransitionToSize and I also have to support iOS 7.
Edit:
Another solution I have come up with is to draw a custom separator line. This only works for iOS 8 and would answer the question (despite I've another issue on iOS 7 where this approach doesn't help).

What is the best way to manage support for both iOS6 and iOS7?

I always have an app requirement to support both iOS6 and iOS7. But because of iOS6 support, I can't use some feature of iOS7.
For example, I have to do UIView bounce animation, in iOS6 I have to do it with CAKeyframeAnimation or UIView animation, but iOS7 has UIKit dynamics which provide me UIDynamicAnimator class and I can do with it.
So should I always use older methods like CAKeyframeAnimation or UIView animation because it supports both iOS6 and iOS7 or write both by checking iOS version?
Ruthlessly strip things from the iOS 6 version that require ios7 features to work, particularly if they are cosmetic things like bouncing animations.
When challenged about this, tell your client they can spend 80% of their dev budget supporting an ever-shrinking pool of unconcerned users, or they can get real. API compatibility is only one headache between 6 and 7. The layout issues are far harder. Any new app being written today needs a really, really good reason to support 6, particularly with 8 just round the corner.
I believe the best way is to check iOS version and implement both variants of code.
Yes, maybe, it's quite a lot of work but in majority of cases newest features provided in new iOS releases are more flexible and simple to understand/integrate. In most cases they are also more plain in support. They are supported by Apple with more care and there is a small possibility of their deprecation.
You can use Foundation runtime variable NSFoundationVersionNumber and NSFoundationVersionNumber_iOS_6_1 macros to divide your code:
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
// write iOS 7+ code here
}
else {
// write iOS 6.1- code here
}
Note, sometimes some recent released API can be quite raw. In such cases you should take a decision individually whether you really need the migration immediately.
You can use class API to check for availability of classes.
if ([UIPrintInteractionController class]) {
// Create an instance of the class and use it.
}
else {
// The print interaction controller is not available.
}
For more information see link below Advanced App Tricks

iOS5: Best method of forcing UI orientation programmatically

[I know this has been done to death, and I'd ask follow up questions on an existing question were it not for not having enough stackoverflow points to make one:(]
I'm after an App Store valid way of forcing an existing UI to re-orientate without having to destroy the main ViewController or View. We work in fullscreen mode, so I'm assuming I can't use any of the toolbar approaches normally quoted. Finally I'm only interested in iOS5.
For iOS6 I have a solution based on the answers in How to change the device orientation programmatically in iOS 6. I used the solution which includes ForcePortrait, with the variation that I changed it so I can supply the required orientation as a parameter.
For iOS5 I have experimented with the suggestion of:
[UIDevice currentDevice] performSelector:NSSelectorFromString(#"setOrientation:") withObject:(id)UIInterfaceOrientationPortrait];
from How to set device (UI) orientation programmatically?. This works well but I'm worried that it would be rejected by App Store (complete no no for us).
Has anyone used this on something that has App Store approval and/or got a better suggestion?
Check this out: Force Rotate UIViewController.
Maybe it will work. This is however very hackish.
[Found a solution, at any rate. Not sure if it the best.]
Got the temporary UIViewController approach to work by adding shouldAutorotateToInterfaceOrientation. The meaning of this is overloaded by iOS5 to discover not only should it autoRotate but also should it start in a particular orientation to start with - I guess that is why it is replaced by several methods at iOS6.. Thus we return true in orientations that are OK.
Perhaps should have realised that before.
Not quite as neat as the setOrientation hack. Key glitch we've noticed is that when you then rotate the device around to the proper orientation you still get a rotation animation. This does not occur on iOS6. Oh well, you win some, you lose some.

iOS 6 iAd property and methods deprecated

Since iOS 6 release, there are some iAd properties and methods that are deprecated like :
currentContentSizeIdentifier
requiredContentSizeIdentifiers
ADBannerContentSizeIdentifierPortrait
ADBannerContentSizeIdentifierLandscape
So what's the best way to implement iAd now on both orientation ? Should we now resize the banner view frame manually ?
I have my application only support Landscape mode(should work for Portrait mode also), and have iAd showing up on the top of the application. And to make this work with ios6 I had to do this:
In Monotouch
storesAdBannerView = new ADBannerView();
storesAdBannerView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth;
For objc (which I dont use), I think it might be
[storesAdBannerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth]
It seems that landscape ads are somewhat phased out.
See: http://www.iphonedevsdk.com/forum/iphone-sdk-development/108118-landscape-iad-banners-in-ios-6-edit-landscape-phased-out-completely.html
It need further confirmation, as I could not find any Apple document regarding that change.
I sAw 2 workaround there : http://www.touch-code-magazine.com/iad-code-is-broken-in-ios6/ Tested the first solution:
easy temporary solution – you can quickly get your app to compile again by using a cheap cheat, add explicitly #import to the files where you are accessing currentContentSizeIdentifier and the size name constants. That should get you going until you alter your app to use the new auto-layout features.
It works ok on xcode 4.5 (banner test ok).

Resources