Ios webview with capacitor, set safe areas - ios

Using capacitor to build an app in ios. In ios the webview covers the whole screen, for iphone-x that means the notch will be included and content will go behind it, like the picture on the right. But i want the picture on the left, black bars on 'no go areas'.
The expected solution (html/css) for this would be to set correct viewport and use the 'safe-area'insert-?', se: https://css-tricks.com/the-notch-and-css/
But for the webview in ios the 'safe-area'insert' will always be 0, that is how it works => this solution is useless.
How can i solve this? Can i change the webview to not cover the whole screen, without changing in the capacitor-framework?

You can use a compatible Cordova plugin cordova-plugin-safearea
npm i -D cordova-plugin-safearea
npx cap sync
With this installed, you can request the safe margin area over the cordova/capacitor bridge:
// Types for clarity
type SafeArea = {
top: string,
bottom: string,
}
window.plugins.safearea.get(
(result: SafeArea) => {
// elegantly set the result somewhere in app state
},
(error: any) => {
// maybe set some sensible fallbacks?
}
);
You could use these values to specify extra padding on the body, or on your header / bottom-menu components
The docs say it returns the values as Numbers, but it seems to me they are actually strings (consider parseFloat before doing math with them).
I have just implemented this in React (running the getter in React.useLayoutEffect); the project is wrapped in Capacitor and have tested on two iOS devices with different ingenious Apple notch screen formats (iPhone 8 and iPhone 11 Pro).
Refer to the documentation for more at https://github.com/rickgbw/cordova-plugin-safearea

There is a CSS variable preset by capacitor you can use to set the padding or a margin for example.
html {
--ion-safe-area-top: env(safe-area-inset-top);
--ion-safe-area-bottom: env(safe-area-inset-bottom);
--ion-safe-area-left: env(safe-area-inset-left);
--ion-safe-area-right: env(safe-area-inset-right);
}

Related

Programmatically Collapse NavigationSplitView to One Column

I have developed a SwiftUI NavigationSplitView app with two columns and it works as expected.
I have chosen dynamic fonts and crafted the visual elements to respond to user settings
for visual accessibility. I know that a number of the users who will employ this app will have
the font size set to the largest available. While that enhances their view of the detail
screen, it pretty much makes the sidebar unreadable. I'm trying to find a way to change
the app's behavior based on the size of the dynamic type. Specifically, I'd like to have
the iPad behavior the same as an iPhone behavior based on a font size that I define.
As it is, the app on an iPhone collapses to a single column. I have not been able to
find a way to programmatically do this on an iPad.
I have tried:
Setting the horizontalSizeClass and as expected, this is a getter only.
.horizontalSizeClass = .compact
I have tried setting the column width of the detail to 0.
.navigationSplitViewColumnWidth(0)
that does not work
I have tried using the old stack function.
.navigationViewStyle(StackNavigationViewStyle())
that does not work.
Clearly, this can be done, since it is automatic when the device is an iPhone. I guess
I could create two views - one stacked and one split and choose based on a State variable
but that seems a bit crude.
Any guidance would be appreciated. Xcode 14 beta 6, iOS 16
This is a great idea and can be achieved by overriding the horizontalSizeClass in the environment depending on the environment value of dynamicTypeSize as follows:
struct NavigationSplitViewTest: View {
#Environment(\.dynamicTypeSize) var dynamicTypeSize
var body: some View {
ViewContainingSplitView()
.environment(\.horizontalSizeClass, dynamicTypeSize > .large ? .compact : .none)
}
}
I tested it by launching the app on iPad simulator and it was in 2 column, then switching to Settings to increase the type size by one notch then back to app and it had switched to single column. However when attempting to switch the size back I noticed the show/hide column button disappeared so I think we have some feedback to submit.
I still have not found an elegant way to do this, but my solution here does work.
Basically, I code for NavigationSplitView and for NavigationStack and change based on the
Environment(.dynamicTypeSize). Like this:
if dynamicTypeSize <= .xxLarge {
NavigationSplitView(columnVisibility: $columnVisibility) {
//all the code
} detail: {
//all the code
}
} else {
NavigationStack {
//all the code
}
}
For others, I was confused by the terms involved here. There is DynamicTypeSize, dynamic
fonts and Larger Accessibility Sizes. Dynamic fonts are those pre-built fonts that
support dynamic type out of the box - .title, .headline, .body etc. Dynamic type size is
the slider in settings that allows the user to scale the dynamic fonts to suit their
needs - all the dynamic fonts scale with the slider setting. Then on top of the slider
in settings for these pre-made fonts, is the option for Larger Accessibility sizes
which gives the user even bigger options.
My scheme above supports all of those intermingled options for both iPad and iPhone.

swift ios macCatalyst app does not load some views on startup on macOS Monterey

since the release of the new macOS Moterey operating system (12) my MacCatalyst application does not load some views at startup until I resize the window or change focus.
If I look at XCode's Debug View Hierarchy these views are not present.
If, on the other hand, I use the classic debug (while they are not shown) it turns out that they have the correct frame (origin and size), superviews and window.
To show them I have to resize the window (manually, using the mouse) or remove the focus from the app (for example by clicking on another window and then clicking the app window again).
Only after doing one of these two things are the views loaded.
Has anyone experienced the same behavior?
The application is developed in Swift only with UIKit and various Storyboards (without SwiftUI).
Thanks a lot to everyone.
I understand what happens. 
If it can be useful to anyone ... 
I use custom margins for my UIViewControllers. To calculate a margin, I use the minimum width of a scene as a variable.
I take this value in this way: 
var minSceneWidth:CGFloat = 400
scenes.forEach { windowScene in
if let w = windowScene.sizeRestrictions?.minimumSize.width {
if minSceneWidth > w {
minSceneWidth = w
}
}
}
Since the latest version of macOS the value "minimumSize.width" seems to be also "0" and this is not good for the calculation of my margins. 
Thank you all.

Status bar overlays webview on iOS with Capacitor

I would like to achieve the same behavior of statusbar as in the capacitor example, i.e. automatically add the correct padding so my app content doesn't display inside the status bar.
However, I don't use the ionic framework but angular and the status bar overlays the webview of my application. Therefore, the content of my app is visible in the status bar.
I was expecting a method that allows to change this behavior (as the _ overlaysWebView_ method of ionic native status bar).
I also tried to add <preference name="StatusBarOverlaysWebView" value="false" /> in the config.xml file but I don't know if I should install the cordova statusbar plugin or not.
Maybe I shouldn't change this configuration and just play with padding, but then I don't know how to handle the different status bar height on different iOS devices.
I'm new to Capacitor and I never used Ionic nor Cordova. I someone could help me deal with this problem, I would be very grateful.
I have also had this issue on some applications I have worked on in the past ond only recently found a clean, less hacky way of fixing it. You will have to add the safe-area-inset-* where * can be left, right, top or bottom. This accounts for where the notch position will be when the device is either in portrait or landscape mode.
You can learn more about this by looking at this answer https://stackoverflow.com/a/47895315/4687451
You can set the padding of your directly in your css code thanks to the env variables. It works only on iOS so it can be applied on any tag you need.
body{
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}
This could be achieved by adding following line in CAPViewBridgeController file
webView?.frame.origin = CGPoint(x: 0, y: UIApplication.shared.statusBarFrame.size.height)
webView?.frame.size.height = UIScreen.main.bounds.size.height - UIApplication.shared.statusBarFrame.size.height;
Search for below function and update. The function should look like this
extension CAPBridgeViewController: CAPBridgeDelegate {
internal var bridgedWebView: WKWebView? {
webView?.frame.origin = CGPoint(x: 0, y: UIApplication.shared.statusBarFrame.size.height)
webView?.frame.size.height = UIScreen.main.bounds.size.height - UIApplication.shared.statusBarFrame.size.height;
return webView
}
internal var bridgedViewController: UIViewController? {
return self
}
}

iOS overrides the `navBarButtonColor` when using PNGs

Issue Description
In my application I have a navigation bar search button set up as follows:
static navigatorButtons = {
leftButtons: [
{
id: 'back-nav-button',
icon: require('../assets/images/icons/arrow-left.png')
}
]
};
The button works as intended on both iOS and Android, but the button is blue on iOS. I understand that this is the desired behavior and that the color can be overridden by setting navBarButtonColor, but the problem is that it's a multi-colored button - meaning I want then button to simply contain the PNG image's colors, and not the navBarButtonColor.
I've tried setting navBarButtonColor to null, transparent, but nothing seems to work.
So my question is, is there a way to make navigation bar icons take on the color of the PNG provided, as is the case on Android?
Steps to Reproduce / Code Snippets / Screenshots
Simply run any RNN app on iOS with a simple static navigatorButtons = ... using a local multi-colored PNG and you'll see the colors of the icon get overwritten.
Environment
React Native Navigation version: 1.1.473
React Native version: 0.55.3
Platform(s) (iOS, Android, or both?): iOS
Device info (Simulator/Device? OS version? Debug/Release?): Android Emulator on Debug
On iOS, UIBarButtonItem uses images created with source image's alpha channel. To display the actual image (not an alpha channel mask of it) you need to change your image's rendering mode to alwaysOriginal
Although, looking at React Native Image class documentation I can't see renderingMode property
We've managed to find a workaround for this. By setting the disableIconTint button property to true, it disables the icon color override. See the following example:
static navigatorButtons = {
leftButtons: [
{
id: 'back-nav-button',
icon: require('../assets/images/icons/arrow-left.png'),
disableIconTint: true // Add this line to use the PNG's color
}
]
};

Centering PickerIOS in React Native

I have been trying to center a PickerIOS, but I am probably missing the underlying logic behind a Picker, because I just want its width to be full screen.
I can manage to do that with iPhone 4s / 5s, but when I run it on the iPhone 6, the Picker seems to be on the left, with some space on the right side.
I have been trying to use alignItem:'center' with a wrapper around the picker, but that just makes it disappear. I have also tried alignSelf, but still doesn't work.
I thought that Picker, by default, had its width to full screen or does it adapt according to the length of the elements?
Do I have to place it in a Flexbox in order to get it centered with a full screen width?
mask1: {
height:120,
overflow:'hidden',
justifyContent:'space-around',
marginTop:50
}
I find out that the style of PickerIOSItem cannot change, and only works fine in NavigatorIOS. I review the example of UIExplorer and there is no more style binding to the Item. Maybe it's a bug.

Resources