A lots app, they have the cover view, like facebook, wechat...
but when I try to use presentViewController let the cover present to main page, that still in the cover vie. The following is my code:
var window: UIWindow?
var coverVC:CoverView?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.backgroundColor = UIColor.lightGrayColor()
coverVC = ViewController()
coverVC?.refresh(window!.frame)
window!.makeKeyAndVisible()
return true
}
Coverview
class CoverView: UIViewController {
func refresh(frame:CGRect){
self.view.frame = frame
self.view.backgroundColor = UIColor.whiteColor()
var mainVC:mainView = mainView()
mainVC.refresh(frame)
self.dismissViewControllerAnimated(false, completion: nil)
self.presentViewController(mainVC, animated: false, completion: nil)
}
}
Main view:
class mainView: UIViewController {
func refresh(frame:CGRect){
self.view.frame = frame
self.view.backgroundColor = UIColor.blueColor()
}
}
Maybe can use other easy way to achieve the goal, that's ok.
otherwise, please don't use "UInavigationcontroller", I know that can present view, but I don't want the bar in cover view, thanks.
I find the correct with cover/login view, it is called SplashScreen.
And in xcode 9, you can find at [TARGETS]>[APP icons and Launch Images] (Image).(The past version, you need add "launch image" in plist file.)
Otherwise, If you doesn't want use this view, just delete "LaunchScreen".
Related
In my Flutter project, my goal was to redirect to iOS native side and I have done this. After landing on iOS native side, from flutter view controller (A), I can go to view controller (B). After this I decided to add a navigation controller on this page (B) so I Embed in that view controller (B) in a navigation controller but the navigation doesn't showed up after I was in view controller (B).
StoryBoard Image
AppDelegate Page Code
What I did so far is:
1 - Embed in Flutter view controller (A) in a navigation controller [output was: Didn't found flutter view controller when I first run the app]
2 - In AppDelegate, I did change the NavigationBarHidden to false and it starts show every where in the app.
self.navigationController.setNavigationBarHidden(false, animated: false)
I think NavigationBar have shown. While it's backgroundColor is nil.
Since UINavigationController is a native controller, it is easy to debug its view hierarchy.
The left side is its simulator. The background is the Xcode debugger.
Here is my case solved:
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
if let ctrl = window.rootViewController as? FlutterBinaryMessenger{
let methodChannel = FlutterMethodChannel(name: "_PageMineState", binaryMessenger: ctrl)
methodChannel.setMethodCallHandler { call, handler in
switch call.method{
case "pic":
if let vc = ctrl as? FlutterViewController{
let controllerOne = UIViewController()
// bar title
controllerOne.navigationControllergationItem.title = "Come"
controllerOne.view.backgroundColor = UIColor.red
let navigationController = UINavigationController(rootViewController: controllerOne)
navigationController.modalPresentationStyle = .fullScreen
// To solve it is to add:
// bar background color
navigationController.navigationControllergationBar.backgroundColor = UIColor.white
vc.present(navigationController, animated: true) { }
}
default:()
}
}
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
I'm trying to present a viewcontroller on topMostViewController. It's working in iOS 12 and lower. But on iOS 13 I'm getting this error:
Manually adding the rootViewController's view to the view hierarchy is no longer supported. Please allow UIWindow to add the rootViewController's view to the view hierarchy itself.
I have checked on iOS 12 and lower, and the code below works fine. But on iOS 13 I am having trouble presenting the view controller. I printed on viewDidLoad; it's getting printed but the view doesn't appear.
func presentInWindow(animated flag: Bool = true, completion: (() -> Void)? = nil) {
DispatchQueue.main.async {
var alertWindow: UIWindow?
alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow?.windowLevel = UIWindow.Level.alert + 1
alertWindow?.rootViewController = UIApplication.topViewController()
if let rootViewController = alertWindow?.rootViewController {
alertWindow?.makeKeyAndVisible()
rootViewController.present(self, animated: flag, completion: completion)
}
}
}
static func topViewController() -> UIViewController? {
var topViewController: UIViewController?
if #available(iOS 13.0, *) {
topViewController = shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first?.rootViewController
} else {
topViewController = shared.delegate?.window??.rootViewController
}
while true {
if let presented = topViewController?.presentedViewController {
topViewController = presented
} else if let nav = topViewController as? UINavigationController {
topViewController = nav.visibleViewController
} else {
break
}
}
return topViewController
}
This code will work to create a view controller on top. You can adjust the size of the view controller on this line: popOverVC.view.frame = lSs I'm not sure if this code is exactly what you are asking for, but if you need a quick solution, it will present view controllers in swift 5, iOS 13, and xcode 11. Note that it is a child view controller, so if you remove the parent, it will leave too. Simply change self to ViewController that you want to present on.
let popOverVC = UIStoryboard(name: "yourSB", bundle: nil).instantiateViewController(withIdentifier: "vcYouWantID") as! vcYouWant
self.addChild(popOverVC)
let lSs = UIScreen.main.bounds
popOverVC.view.frame = lSs
popOverVC.view.tag = tag
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParent: self)
I received the same error while updating an app which worked fine previously. It looks like the new requirement for AppDelegate.swift is:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) { }
}
hth
I encountered the same issue tonight. I tried the methods suggested by people on the Net including Stackoverflow, but none had worked.
Just now, as if magic was working, I tried to form an outlet from the ViewController (visually the "background" layer for all subviews) in the Main.storyboard to the ViewConstroller class in ViewController.swift. It worked in my project for iOS 13 simulator in Xcode 12.2.
Hope this trick will also work for you.
I found this to fix my problem (in old Objective-C code):
// old way broken in iOS 13
//appDelegate.window.rootViewController = vc;
// this works in iOS 13
[appDelegate.window setRootViewController:vc];
Currently I'm following this tutorial to integrate Unity+Vuforia project to my existing iOS project. I manage to be able to show the Unity view inside my ARViewController. The thing is I lost all the user interaction in my view controller: my touch event for back button not fire up.
import Foundation
class ARViewController: UIViewController {
var unityView: UIView?
static func instantiateViewController() -> ARViewController {
let controller = UIStoryboard.main.instantiateViewController(withIdentifier: "ARViewController") as! ARViewController
return controller
}
override func viewDidLoad() {
super.viewDidLoad()
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.currentUnityController = UnityAppController()
appDelegate.currentUnityController?.application(UIApplication.shared, didFinishLaunchingWithOptions: nil)
appDelegate.startUnity()
NotificationCenter.default.addObserver(self, selector: #selector(handleUnityReady), name: NSNotification.Name("UnityReady"), object: nil)
}
}
#IBAction func onBackPressed(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.stopUnity()
}
}
#objc func backPressedTest() {
}
#objc func handleUnityReady() {
showUnitySubView()
}
func showUnitySubView() {
guard let unityView = UnityGetGLView() else { return }
self.unityView = unityView
// insert subview at index 0 ensures unity view is behind current UI view
view?.addSubview(unityView)
unityView.translatesAutoresizingMaskIntoConstraints = false
let views = ["view": unityView]
let w = NSLayoutConstraint.constraints(withVisualFormat: "|-0-[view]-0-|", options: [], metrics: nil, views: views)
let h = NSLayoutConstraint.constraints(withVisualFormat: "V:|-50-[view]-0-|", options: [], metrics: nil, views: views)
view.addConstraints(w + h)
let button = UIButton(type: .custom)
button.setImage(#imageLiteral(resourceName: "ic_back_black").withRenderingMode(.alwaysTemplate), for: .normal)
button.addTarget(self, action:#selector(backPressed), for: .touchUpInside)
button.frame = CGRect(x: 0, y: 0, width: 28, height: 60)
button.widthAnchor.constraint(equalToConstant: button.frame.width).isActive = true
button.tintColor = UIColor.purpleBrown()
view?.addSubview(button)
}
}
I also notice that button from Unity also have any effect when I touch it. The back button inside the green bar is from Unity. And the blue button is from my ARViewController. Both seem don't reach to touch event.
Debug elements:
It happens when I put the Unity configuration at the top of application:didFinishLaunchingWithOptions:, above my existing configuration for another services that I use in the project. For someone who encounter this problem in the future, here's my appDelegate.swift:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.application = application
// Another existing settings for the project, e.g. fabric
Fabric.with([Crashlytics.self])
// Put the Unity configuration at the bottom of the function
unity_init(CommandLine.argc, CommandLine.unsafeArgv)
currentUnityController = UnityAppController()
currentUnityController?.application(application, didFinishLaunchingWithOptions: launchOptions)
startUnity()
stopUnity()
return true
}
For the viewWillAppear(_:) in the view controller:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setupBackBarButtonItems(back: true, isDark: true)
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.startUnity()
showUnitySubView()
}
}
As mentioned by #Prashant in the comment, the UnityReady notification only get called once. So I don't use it.
Then I just call stopUnity() in viewWillDisappear(_:):
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.stopUnity()
}
}
The current problem is I can't kill the unity process if I leave the screen. It's known bug and I'm still figuring out how to do that, if it's possible.
I had the same issue but moving Unity configuration to the end of applicationDidFinishLaunchingWithOption method didn't solve it and I still had a UIWindow in front of my screen that steals all user interactions.
My solution is not to create a new window in UnityAppController.mm, but using the current application keyWindow.
Replace:
_window = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];
with:
_window = [UIApplication sharedApplication].keyWindow;
In my app have two UIViewControllers (first, where user choose character, and second, where characters info is shown).
Trying do everything from code. So my code:
AppDelegate.swift:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
guard let window = self.window else {
return false
}
UIApplication.shared.statusBarStyle = .lightContent
let viewController = ViewController()
let navigationController = UINavigationController(rootViewController: viewController)
window.rootViewController = navigationController
window.makeKeyAndVisible()
return true
}
ViewController: UIViewController
...
func buttonPressed(sender: UIButton) {
guard let typeName = sender.title(for: .normal), let unitType = UnitType(rawValue: typeName) else {
return
}
let unitViewController = UnitViewController(unitType: unitType)
let navigationController = UINavigationController(rootViewController: unitViewController)
self.present(navigationController, animated: true, completion: nil)
}
And UnitViewController: UIViewController (where chosen character's info is shown):
...
fileprivate func setupNavigationBar() {
let backButton = UIBarButtonItem(title: "<", style: .plain, target: self, action: #selector(backToViewController(sender:)))
self.navigationItem.setLeftBarButton(backButton, animated: true)
self.navigationItem.titleView?.backgroundColor = AppColor.Black.color
self.navigationItem.titleView?.tintColor = .white
self.navigationItem.title = "\(self.unitType.rawValue)"
}
func backToViewController(sender: AnyObject) {
self.dismiss(animated: true) {
let viewController = ViewController()
let navigationController = UINavigationController(rootViewController: viewController)
self.present(navigationController, animated: true, completion: nil)
}
}
So I have two screens:
Well, and I have some questions:
1. Getting
2016-12-02 05:48:21.855 The API Awakens[16402:551729] Warning: Attempt
to present on
whose view is not
in the window hierarchy!
warning when press 'back' button in UnitViewController. What I am doing wrong?
Gray background color and black color of NavigationBar. How change it to black and white?
How get 'system' back button for UIBarButtonItem, not just .plain with title "<"? So my UnitViewController navigation bar should looks like this:
Any help will be greatly appreciated!
UPDATE 1:
1. Warning gone, thanks to #dip
2. Made navigation bar dark, thanks to #aznelite89.
But, there is my code in AppDelegate.swift:
UINavigationBar.appearance().barTintColor = AppColor.Black.color
AppColor.Black is exact same color I'm using for background in ViewController, but that how it looks now:
Looks like alpha of NavigationBar is not 1.0...
UPDATE 2:
Different between color of NavigationBar and color I've used is 13 in RGB values, so I've hacked it setting color of NavigationBar with RGB value less by 13 than original color... It's ok now
Try this :-
let viewController = ViewController()
viewController.modalPresentationStyle = .overCurrentContext
window?.rootViewController?.present(viewController, animated: true, completion: nil)
Add this in app delegate.swift :-
UINavigationBar.appearance().barTintColor = UIColor.black
You may change these attributes on your storyboard attribute inspector
I am trying to launch google login from AppDelegate.swift and then launch my app's main screen upon login success.
I am able to
show the google login button as shown above
the user is sent to google to sign in
the user is sent back to original (step 1)
After step 3. I'd like to send the user to my app's main page.
My code is below. The problem I'm having is that authUI is not being called.
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, FIRAuthUIDelegate {
var window: UIWindow?
var authUI: FIRAuthUI?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
FIRApp.configure()
authUI = FIRAuthUI.defaultAuthUI()
authUI?.delegate = self
let providers: [FIRAuthProviderUI] = [FIRGoogleAuthUI()]
authUI?.providers = providers
// show google login button
let authViewController = authUI?.authViewController()
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = authViewController
self.window?.makeKeyAndVisible()
return true
}
func application(application: UIApplication, openURL url: NSURL, options: [String: AnyObject]) -> Bool {
return GIDSignIn.sharedInstance().handleURL(url, sourceApplication: options[UIApplicationOpenURLOptionsSourceApplicationKey] as? String, annotation: options[UIApplicationOpenURLOptionsAnnotationKey])
}
func authUI(authUI: FIRAuthUI, didSignInWithUser user: FIRUser?, error: NSError?) {
// launch main view controller
}
}
EDIT: This appears to be a duplicate of another question. The other question's title is quite general and only gets to the details a few lines deep. In any case, I believe Chris's answer is more thorough than the one there. I think both the question and answers here are clearer, more pointed and more thorough so it would be a mistake to just direct people here to go there as would happen if this was marked as a duplicate.
I think your problem lies here, in the - (void)signInWithProviderUI:(id<FIRAuthProviderUI>)providerUI method.
The delegate method is called in the dismissViewControllerAnimated:completion: completion block.
[self.navigationController dismissViewControllerAnimated:YES completion:^{
[self.authUI invokeResultCallbackWithUser:user error:error];
}];
As you can see from the Apple docs, this method is expected to be called on a modally presented viewController. You are displaying it as a root view controller. Try displaying it with a modal from a UIViewController, and things should work out. To debug this try and set a breakpoint at line 193 to see that it won't get hit. I would be very surprised if this doesn't work when you display the authController modally.
To come up with a possible solution to your problem (I am assuming you want to ensure a user is signed in before using your app). The below is a simplification of what I am using in an app currently.
EDIT: Updated for the new 1.0.0 FirebaseUI syntax.
class MainTabController: UITabBarController, FIRAuthUIDelegate {
let authUI: FUIAuth? = FUIAuth.defaultAuthUI()
override func viewDidLoad() {
super.viewDidLoad()
var authProviders = [FUIFacebookAuth(), FUIGoogleAuth()]
authUI.delegate = self
authUI.providers = authProviders
//I use this method for signing out when I'm developing
//try! FIRAuth.auth()?.signOut()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if !isUserSignedIn() {
showLoginView()
}
}
private func isUserSignedIn() -> Bool {
guard FIRAuth.auth()?.currentUser != nil else { return false }
return true
}
private func showLoginView() {
if let authVC = FUIAuth.defaultAuthUI()?.authViewController() {
present(authVC, animated: true, completion: nil)
}
}
func authUI(_ authUI: FUIAuth, didSignInWith user: FIRUser?, error: Error?) {
guard let user = user else {
print(error)
return
}
...
}
It must be a problem of reference.
class AppDelegate: UIResponder, UIApplicationDelegate, FIRAuthUIDelegate {
var window: UIWindow?
let authUI = FIRAuthUI.defaultAuthUI()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
FIRApp.configure()
authUI.delegate = self
let providers: [FIRAuthProviderUI] = [FIRGoogleAuthUI()]
authUI.providers = providers
// show google login button
let authViewController = authUI.authViewController()
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = authViewController
self.window?.makeKeyAndVisible()
return true
}
}
Try this. AppDelegate will hold the reference of authUI and its delegate.