how to present another viewController in separate UIWindow - ios

I want to create a Floating Button in my app which will be visible all over the page and can handle the event from a separate ViewController to maintain the button state.
I want to open a ViewController from a separate window at the same time when the user login into the app. And if the user clicks on the button then ViewController will handle the event and if click outside the button then it should handle by the main controller.
Thanks

First Create a UIViwe with a .xib file and create your required UI. All UI-related functions will be there in UIView class and for action create a manager class that manages all events.
Use the below code to add playerView to the window
PlayerManager.shared.addPlayer()
See bellow code for playerManager class
class PlayerManager : NSObject{
static let shared = PlayerManager()
private override init(){
super.init()
}
func addPlayer(){
let window = UIApplication.shared.keyWindow
let player = Bundle.main.loadNibNamed("PlayerView", owner: nil, options: nil)![0] as! PlayerView
let outerView = UIView(frame: CGRect(x: getXValueForView(width: 180), y: getYValueForView(height: 120), width: 180, height: 60))
player.frame.size = CGSize(width: 180, height: 60)
player.playerDelegate = self
outerView.clipsToBounds = true
player.miniPlayer.isHidden = false
player.expendedPlayer.isHidden = true
outerView.addSubview(player)
window?.addSubview(outerView)
}
}

Related

Putting loading animation over VNDocumentViewController Swift

Is it possible to put a loading animation over the VNDocumentViewController? As in, when the user presses the Save button, is there a way for me to somehow indicate that the Vision is processing the image and hasn't frozen? Right now, in my app, there is a long pause between the user pressing Save and the actual image being processed.Here is an example from another post of what I'm trying to create
Here is one example of adding a loading indicator using UIActivityIndicatorView().
startAnimating() to start the animation and stopAnimation() to stop the animation.
iOS - Display a progress indicator at the center of the screen rather than the view
guard let topWindow = UIApplication.shared.windows.last else {return}
let overlayView = UIView(frame: topWindow.bounds)
overlayView.backgroundColor = UIColor.clear
topWindow.addSubview(overlayView)
let hudView = UIActivityIndicatorView()
hudView.bounds = CGRect(x: 0, y: 0, width: 20, height: 20)
overlayView.addSubview(hudView)
hudView.center = overlayView.center
hudView.startAnimating()
Alternatively, you could look into using Cocoapod MBProgressHud
https://cocoapods.org/pods/MBProgressHUD
There's a way you can extend a class in Swift that captures this problem well. The idea is you want a UIActivityIndicator in your VNDocumentCameraViewController. But we'd like that to be a part of every version of this we use. We could simply embed the DocumentVC's view into our current view and superimpose a UIActivityIndicator above it in the view stack, but that's pretty hacky. Here's a quick way we can extend any class and solve this problem
import VisionKit
import UIKit
extension VNDocumentCameraViewController {
private struct LoadingContainer {
static var loadingIndicator = UIActivityIndicatorView()
}
var loadingIndicator: UIActivityIndicatorView {
return LoadingContainer.loadingIndicator
}
func animateLoadingIndicator() {
if loadingIndicator.superview == nil {
view.addSubview(loadingIndicator)
//Setup your constraints through your favorite method
//This constrains it to the very center of the controller
loadingIndicator.frame = CGRect(
x: view.frame.width / 2.0,
y: view.frame.height / 2.0,
width: 20,
height: 20)
//Setup additional state like color/etc here
loadingIndicator.color = .white
}
loadingIndicator.startAnimating()
}
func stopAnimatingLoadingIndicator() {
loadingIndicator.stopAnimating()
}
}
The place we can call these functions are in the delegate methods for VNDocumentCameraViewController that you implement in your presenting ViewController:
func documentCameraViewController(
_ controller: VNDocumentCameraViewController,
didFinishWith scan: VNDocumentCameraScan
) {
controller.animateLoadingIndicator()
}

I can't call touchUpInside of button to ViewController when is at a subview

I'm make a library from wallet of cards, but when i am pushing a button in my controller not working, i don't kwon if my instance is bad, need help please.
The repository of project is in github this is the link:
https://github.com/RAES9/WalletOfCards
The name class id WalletOfCards.swift
let controller = self.delegate?.storyboard!.instantiateViewController(withIdentifier: self.destitaionController as String)
self.delegate?.addChild(controller!)
controller!.didMove(toParent: self.delegate!)
Lines: 143,144,15.
Function: tappedButton
I created new var for my controller and i added new subview in this
let controller = self.dataSource.storyboard!.instantiateViewController(withIdentifier:
self.destitaionController as String)
self.dataSource.addChild(controller)
controller.didMove(toParent: self.dataSource)
controller.view.frame = CGRect(x: 0, y: 0, width: (cardSelected?.frame.width)!, height: (cardSelected?.frame.height)!)
controller.view.alpha = 0.0
self.dataSource.view.addSubview(controller.view)
controller.view.alpha = 1.0

Maintain custom UIView that is added to KeyWindow

I am working on a sync feature for my app.
What I want to achieve is to display a custom UIView that will serve as an indicator to the user, wherever screen the user at (such as navigate to dashboard, settings, profile page, etc), that the synchronization is in progress. In short term, it will stick to a position within the app statically.
After done some researches from the web, I come to a conclusion to use keyWindow and add a subview to it.
Here is my code
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let window = UIApplication.shared.keyWindow {
window.windowLevel = .statusBar
let uiView = UIView()
uiView.backgroundColor = .green
window.addSubview(uiView)
uiView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
uiView.heightAnchor.constraint(equalToConstant: 150),
uiView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 25),
uiView.topAnchor.constraint(equalTo: view.topAnchor, constant: 150),
uiView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.4)
])
}
}
Above code is working fine, I can attach a custom view to the keyWindow. However, when the user navigate to another screen, the added customView will dissappear, and only show when the user goes back to the previous screen.
Can someone guide on what part I am missing? On which part I did wrong?
Thanks
As per comments I am adding a minimum requirement to create a new window which will can now always be on top of your view controller or even other windows:
class OverlayViewController: UIViewController {
private var myWindow: UIWindow? // Our own window needs to be retained
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.black.withAlphaComponent(0.3)
view.addSubview({
let label = UILabel(frame: .zero)
label.text = "This is an overlay."
label.sizeToFit()
label.center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
return label
}())
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onTap)))
}
#objc private func onTap() {
myWindow?.isHidden = true
myWindow?.removeFromSuperview()
myWindow = nil
}
static func showInNewWindow() {
let window = UIWindow(frame: UIScreen.main.bounds)
// window.windowLevel = .alert
// window.isUserInteractionEnabled = false
window.rootViewController = {
let controller = OverlayViewController() // OR UIStoryboard(name: "<#FileName#>", bundle: nil).instantiateViewController(withIdentifier: "<#Storyboard Identifier#>")
controller.myWindow = window
return controller
}()
window.makeKeyAndVisible()
}
}
So this is just all-in-code simple view controller example which can be used anywhere in the project by simply calling OverlayViewController.showInNewWindow(). The view controller can be from storyboard though.
The interesting part is the showInNewWindow which creates a new window and an instance of this view controller that is set as a root view controller. To show the new window all you need to call is makeKeyAndVisible. And to remove it simply hid it and remove it from superview as done in onTap. In this case the window is referenced by the view controller which should create a retain cycle. It seems that this is mandatory. It also means that we need to do some cleanup once window is dismissed by calling myWindow = nil.
There are some settings possible as well like you can disable user interaction and enable user to still use the window below this one (window.isUserInteractionEnabled = false). And you can set the level of window as to where is it displayed (window.windowLevel = .alert). You can play around a bit with these values. Which to set depends on what level you want your window to be.

How to show a customizable view into all view controller?

the question is little bit elaborate what I really want to know.I want to make an app whose some functionality looks like SoundCloud and gaana. Below here I show some screenshot of gaana.
Here if we click any song they automatically update the above view and play the song and also this view will show into all view controller.Clicking this up arrow button how they showing up a new view where the previous small view is no where and also load a collection view into this new view.how to do all of this?the new view is here.
You can do that by creating an overlay, i.e. you add a UIView as a child element to the app's main window like so:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
showOverlay()
}
func showOverlay() {
guard let window = UIApplication.shared.keyWindow else {
//if this block runs we were unable to get a reference to the main window
print("you have probably called this method in viewDidLoad or at some earlier point where the main window reference might be nil")
return
}
//add some custom view, for simplicity I've added a black view
let blackView = UIView()
blackView.backgroundColor = .black
blackView.translatesAutoresizingMaskIntoConstraints = false
blackView.frame = CGRect(x: 0, y: window.frame.height - 100, width: window.frame.width, height: 100.0)
window.addSubview(blackView)
}
Now this view should always be floating above the current UIViewController

Can we get an array of all storyboard views

I'm developping application in Swift.
This application has many view and I would like to put a UIProgressView on all views
Can we get an array of all storyboard views ?
for exemple :
self.progressBar = UIProgressView(progressViewStyle: .Bar)
self.progressBar?.center = view.center
self.progressBar?.frame = CGRect(x: 0, y: 20, width: view.frame.width, height: CGFloat(1))
self.progressBar?.progress = 1/2
self.progressBar?.trackTintColor = UIColor.lightGrayColor();
self.progressBar?.tintColor = UIColor.redColor();
var arrayViewController : [UIViewController] = [...,...,...]
for controller in arrayViewController {
controller.view.addSubview(self.progressBar)
}
Thank you
Ysée
I assume that what you really want is to have the progress displayed on every view IF there is an operation in progress.
There are many ways to do that (using delegation, NSNotificationCenter, …) but the easiest I can think of would be to rely on viewWillAppear
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// Check if there's an operation in progress and add progressView if relevant
}
For the user, it will effectively look like you added the progress view to all views.
Why not create a base class that has a lazy stored property of type UIProgressView ? Optionally you can have two methods setProgressViewHidden(hidden : Bool) in order to easily show and hide the progress view and setProgress(progress : Float) to update the progress. Then all your view controllers can subclass this base class and conveniently interact with the progress view.
class ProgressViewController : UIViewController {
lazy var progressView : UIProgressView = {
[unowned self] in
var view = UIProgressView(frame: CGRectMake(0, 20, self.view.frame.size.width, 3))
view.progress = 0.5
view.trackTintColor = UIColor.lightGrayColor()
view.tintColor = UIColor.redColor()
self.view.addSubview(view)
return view
}()
}
To read more about lazy stored properties, check: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html

Resources