Using Xcode 7 I wanna to create a small application with a UIWebView.
This app will have to run it from all devices.
I'm using "New iOS Launch Image" in Assets.
But when the "Launch" terminate there is a waiting time (which varies from connection speed ) before that WebView is loaded .
In this time I would like to "Launch Screen" that continue to persist using the Image for the type of device .
Can you help me?
You cannot increase the time of splash screen as recommended by apple but you can do something which will make the user feel like splash screen is still there.
You can achieve it in this way:
I am assuming that the first screen load after your splash screen is your WebView screen. Add UIImageView on your WebView in interface builder and set splash screen image on your ImageView. Now make IBOutlet for this imageView and set it hidden property as yes when webview intimates you that its loaded in its delegate methods. Don't forget to set the delegate of your UIWebView in interface Builder.
class WebViewController: UIViewController, UIWebViewDelegate {
#IBOutlet var UIImageView: imgThumbSplash!
override func viewDidLoad() {
super.viewDidLoad()
imgThumbSplash.hidden = false
}
func webViewDidFinishLoad(webView: UIWebView){
imgThumbSplash.hidden = true
}
func webView(webView: UIWebView, didFailLoadWithError error: NSError?){
imgThumbSplash.hidden = true
}
}
I solved it with this code:
extension UIImage {
convenience init?(fullscreenNamed name: String) {
switch UIScreen.mainScreen().bounds.size.height {
case 480: //iPhone 4/4s
self.init(named: "\(name)-700#2x.png")
case 568: //iPhone 5/5s
self.init(named: "\(name)-700-568h#2x.png")
case 667: //iPhone 6/6s
self.init(named: "\(name)-800-667h#2x.png")
case 736: //iPhone 6+/6s+
self.init(named: "\(name)-800-Portrait-736h#3x.png")
default:
self.init(named: name)
}
}
}
I take in "LaunchImage" the right image for the device screen in use.
Related
To make it more clear I have created a demo app with only 2 ViewControllers. The issue only occurs on iPad on which I have kept all orientations enabled which are already enabled by default. So if I present a UIViewController as FormSheet on iPad, the viewWillTransition method is not triggering sometimes when iPad is in landscape mode. I tested it both in simulator as well as on the physical device. Firstly I thought it might be due to my code but in this demo it was clear, if I try to print a statement in viewWillTransition method in my ViewController, it will be printed every time no matter which orientation you are in. However, when I present a FormSheet, it will work for every orientation if iPad is in Portrait mode but if you switch to landscape mode, and try to change app size in Split View, sometimes the statement is not printed. It also happens if you have 2 apps opened in Split Mode with equal ratio and you switch your app to slideOver. So im confused why viewWillTranstion working fine for portrait mode but sometimes will not trigger for landscape mode?
This is my code in ViewController:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
}
#IBAction func button(_ sender: Any) {
let vc = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
if self.traitCollection.userInterfaceIdiom == .phone {
vc.modalPresentationStyle = .fullScreen
}
else {
vc.modalPresentationStyle = .formSheet
}
vc.modalTransitionStyle = .coverVertical
self.present(vc, animated: true, completion: nil)
}
}
And this is code for SecondViewController:
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
DispatchQueue.main.async {
print("Transition Detected")
}
}
}
Here is a video in which you can see the statement is only getting printed in portrait mode: https://youtu.be/iz5iOzOtGCg
It gets printed in landscape mode too but I have included the part ion which viewWillTransition is not triggering.
In Portrait mode, no matter what you do, rotate, change to Split View or drag size of app in Split View, or switch app to slipover, Transition Detected is printed. However in landscape mode, it will not print if you are in Split View and drag to make app small.
This behaviour is so confusing. Any idea how to detect all the transitions in landscape mode too?
Somebody else asked the same question in 2018, but he/she did not get answer so hopefully I will have more chance. :-)
Basically, I need my app to have the split view enabled. To do so the target deployment info should be:
All the 'Device orientation' selected
The 'Requires full screen' not selected
To have the possibility to control the orientation, you need the target deployment information to be:
The 'Device orientation' needs at least 'Portrait' OR 'Portrait + Landscape left + Landscape right'
The 'Require full screen' needs or does not need to be selected.
Like you can see, I did not put the 'Upside Down' option from 'Device Orientation' because doing so, I can't lock the orientation for a specific view controller.
If you think it is possible, what am I missing?
Here the code that I am using to lock the orientation based on this:
AppOrientationUtility
struct AppOrientationUtility {
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation: UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
And using it:
override func viewDidLoad() {
super.viewDidLoad()
AppOrientationUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait)
}
I have a WKWebview page in my app which selects an image to upload it so I have NO CONTROL over opening the UIImagePicker It happens natively but the "DONE" button which I can click is not shown in iPad ios 14.7.1 but it's actually clickable!!
This is how UIImagePicker shown natively
The red area is actually clickable!
I tried changing tint color globally but only the back arrow has changed the button is still hidden or something!
Use this:
extension UIImagePickerController {
open override func viewDidLoad() {
super.viewDidLoad()
self.modalPresentationStyle = UIModalPresentationStyle.custom
}
}
Try this:
extension UIImagePickerController {
open override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
self.navigationBar.topItem?.rightBarButtonItem?.tintColor = UIColor.black
self.navigationBar.topItem?.rightBarButtonItem?.isEnabled = true
}
}
I've come across the following, which I believe is a bug in iOS 12. This worked fine in iOS 11.4.1. Try the following.
Open a new project in Xcode 10. Add a UI button. Add the following to your PLIST Privacy - Camera Usage Description with some description.
Copy the following code:
import UIKit
class ViewController: UIViewController {
let imagePickerController = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func takePic(_ sender: Any) {
takePicture()
}
func takePicture() {
imagePickerController.allowsEditing = false
imagePickerController.sourceType = UIImagePickerController.SourceType.camera
imagePickerController.cameraCaptureMode = .photo
imagePickerController.modalPresentationStyle = .fullScreen
present(imagePickerController, animated: true, completion: nil)
}
}
Wire up the UIButton to the takePic IBAction.
Run the app on an iOS 12 device, since the simulator doesn't have a camera. The UIImagePickerController should show the camera.
Now remove Portrait from the Device Orientation in Xcode Targets-> Deployment Info. Run again and the app will crash with the following:
*** Terminating app due to uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason: 'Supported orientations has no common orientation with the application, and [CAMViewfinderViewController shouldAutorotate] is returning YES'
*** First throw call stack:
(0x1d1ecff78 0x1d10c8284 0x1d1dd075c 0x1ff912b30 0x1ff913130 0x1ff9139a0 0x1ff8fcff0 0x1ff8d70bc 0x1ff8d6e84 0x1ff8d6e84 0x1ff8d6e84 0x1ff8d6e84 0x1ff8c9968 0x1ff8c982c 0x1ff8d9d88 0x1ff894ab4 0x1ff91dbb4 0x1ff550888 0x1ff904430 0x1ff21171c 0x1ff1fed44 0x1ff22fa84 0x1d1e5bfe0 0x1d1e56ab8 0x1d1e5703c 0x1d1e56844 0x1d4105be8 0x1ff205428 0x102f9d9f4 0x1d190c020)
libc++abi.dylib: terminating with uncaught exception of type NSException
This used to work on devices on iOS 11...
Since I have an app that is now crashing, how do I somehow trick the app to tricking the app is in portrait mode before presenting the UIImagePickerController?
UPDATE: Appears to only crash on iPhone X/XS
Thanks.
I had the same problem with an iPhone X on iOS 12, what i did to solve it is :
Not setting any interface orientation in the project file
Defining an initial interface orientation in the info.plist file, using the key Initial interface orientation and the value Landscape (right home button)
Finally, in each of your UIViewController, you should define the interface orientation using for example:
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscape
}
I have an activity indicator that gets presented on an iPhone and iPad. In the iPad in split screen mode it gets presented to whichever side of the view that called it. I would instead like it to get presented in the middle/center the window's screen. If I do it this way wether on the iPhone in portrait or iPad in split screen mode it will always be in the center of the screen.
How do I do this?
MyView: UIViewController{
let actInd = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
#IBAction fileprivate func buttonPressed(_ sender: UIButton) {
guard let window = UIApplication.shared.keyWindow else { return }
//how to add actInd as subview to the window' screen?
actInd.startAnimating()
}
}
It's pretty simple. Turn off the auto-resizing mask. Add the add actInd to window, then set the center anchors.
actInd.translatesAutoresizingMaskIntoConstraints = false
window.addSubview(actInd)
actInd.centerXAnchor.constraint(equalTo: window.centerXAnchor).isActive = true
actInd.centerYAnchor.constraint(equalTo: window.centerYAnchor).isActive = true
Window is subclass of UIView. Just add it as it's subview like you're adding a view to another view. But remember that window is shared throughout your app, so adding it every-time will consume memory, remove it after your job is done.
If you want to center it in the window, you can use autoResizingMask or add constraints to it.