Remove any view from any where e.g from window - swift

I have 2 views on the screen, one is overlayView at the bottom and introView at the top of that overlayView. When I tap(tapToContinueAction) on the screen they should both hide or remove themselves.
extension UIView {
....
func hideView(view: UIView, hidden: Bool) {
UIView.transition(with: view, duration: 0.5, options: .transitionCrossDissolve, animations: {
view.isHidden = hidden
})
}
}
class IntroScreen
#IBAction func tapToContinueAction(_ sender: UITapGestureRecognizer) {
self.hideView(view: self, hidden: true)
}
--
class OverlayView : UiView {
...
}
In current situation i can hide introScreen only and i dont know how the other class's action can effect the overlayView at the same time and hide that view as well. Any idea?

You have two different classes for your views. Make an extension of your window to remove your specific views just like I have made removeOverlay and removeIntroView both these computed properties will go and search in subviews list of window and check each view with their type and remove them. Thats how you can remove any view form any where.
class OverLayView: UIView {}
class IntroView: UIView {
#IBAction func didTapYourCustomButton(sender: UIButton) {
let window = (UIApplication.shared.delegate as! AppDelegate).window!
window.removeOverlay
window.removeIntroView
}
}
extension UIWindow {
var removeOverlay: Void {
for subview in self.subviews {
if subview is OverLayView {
subview.removeFromSuperview()// here you are removing the view.
subview.hidden = true// you can hide the view using this
}
}
}
var removeIntroView: Void {
for subview in self.subviews {
if subview is IntroView {
subview.removeFromSuperview()// here you are removing the view.
subview.hidden = true// you can hide the view using this
}
}
}
}

Related

How to present a ViewController as a Modal Sheet without the background shadow

Is there any way to present a ViewController as a Modal Sheet without the background shadow as shown in the first image below using swift. Is there an easy way or should we need to write custom UIPresentationController? [![The required output][1]][1]
[1]: https://i.stack.imgur.com/QAEEn.png![enter image description here](https://i.stack.imgur.com/q4JD5.jpg)
You can use a smaller size view controller as per your need. Firstly add a class.
class SmallSizePresentationController : UIPresentationController {
override var frameOfPresentedViewInContainerView: CGRect {
get {
guard let theView = containerView else {
return CGRect.zero
}
return CGRect(x: 0, y: theView.bounds.height * (281 / 896), width: theView.bounds.width, height: theView.bounds.height)
}
}
}
Then when you want to present this type of view controller just add the extension of your current view controller.
extension YourCurrentViewController: UIViewControllerTransitioningDelegate {
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return SmallSizePresentationController(presentedViewController: presented, presenting: presenting)
}
}
Then present your new view controller like this
let VC = withoutShadowVC()
VC.transitioningDelegate = self
VC.modalPresentationStyle = .custom
self.present(VC, animated: true, completion: nil)
You can modify the view controller height.

How to show and hide the keyboard with a subview

I have a custom UIView that is a subview on a UIViewController.
I have it added in my storyboard and set it to Hidden.
My subview is also within another UIView that I'm using as a 'blur view' which is also initially Hidden.
I have functions that will unhide & hide the subviews.
My custom subview has a UITextField. I can show the keyboard and move the subview up with no problems. When I type in the keyboard or dismiss it my subview moves up and to the left. When I try to show my subview again it shows incorrectly (up and to the left).
The custom subview starts at the center of my screen.
The goal is move it up when the keyboard shows so it will not cover the subview or the UITextField, allow the user to type in the UITextField, and then dismiss the keyboard and move the custom subview back to the center.
In my UIViewController:
// Showing the custom sub view
func displayCustomSubView() {
if let window = UIApplication.shared.keyWindow {
self.blurView.isHidden = false
self.customSubView.isHidden = false
self.blurView.frame = window.frame
self.customSubView.center = window.center
window.addSubview(self.blurView)
UIApplication.shared.keyWindow?.bringSubviewToFront(self.blurView)
}
}
// Hiding the custom sub view
// the custom sub view has a button I tap to hide
#objc func dismissCustomSubView() {
self.blurView.isHidden = true
self.customSubView.isHidden = true
}
// Show Keyboard
// Since I am using the window to make sure my blur view expands to the full frame, I have tried just moving the window up
#objc func keyboardWillShow(sender: NSNotification) {
if let window = UIApplication.shared.keyWindow {
window.frame.origin.y = -75
}
}
// Hide Keyboard
#objc func keyboardWillHide(sender: NSNotification) {
if let window = UIApplication.shared.keyWindow {
window.frame.origin.y = 0
}
}
// Custom Subview Extension
extension CustomSubView: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
Added the Custom Subview Extension above.
First add this notification within your viewDidLoad(). And make a global variable called var keyboardH: CGFloat = 0:
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillShow),
name: UIResponder.keyboardWillShowNotification,
object: nil
)
And this function below:
#objc func keyboardWillShow(_ notification: Notification) {
if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
self.keyboardH = keyboardHeight
}
This function is called every time the keyboard is present and will reveal the keyboard height and later we can use this variable.
So in your code:
#objc func keyboardWillShow(sender: NSNotification) {
if let window = UIApplication.shared.keyWindow {
let position = window.frame.origin.y - keyboardH
window.frame.origin.y = position
}
}

Swift remove subview from another class

I have my ViewController 'chatPage' in which I am presenting a UIView using a xib file called 'chatOverlay'. I have placed a button inside the xib which when pressed I would like to remove the subview from the chatPage ViewController.
I am not sure how to go about this as the button is in a different class to the subview and has no reference to the ViewController I wish to remove the sub view from.
I am aware I could use a notification observer to notify the viewController but is there an alternative way?
How would I go about removing the subview from within the chatOverlay class when the button is tapped?
chatOverlay:
import Foundation
class chatOverlay: UIView {
#IBAction func closeOverlay(_ sender: UIButton) {
print("CLOSE OVERLAY")
}
}
chatPage:
class chatPage: UIViewController {
override func viewDidLoad(){
view.addSubview(overlayAdd().show(height: view.frame.size.height, width: view.frame.size.width, x: view.frame.origin.x, y: view.frame.origin.y, tag: 101))
}
}
overlayAdd:
import Foundation
import UIKit
class overlayAdd {
func show(height: CGFloat, width: CGFloat, x: CGFloat, y: CGFloat, tag: Int) -> UIView{
let chatOverlay = xibLoad().chatOverlay()
chatOverlay.frame.size.height = height
chatOverlay.frame.size.width = width
chatOverlay.frame.origin.x = x
chatOverlay.frame.origin.y = y
chatOverlay.tag = tag
let view = chatOverlay
return view
}
func remove(tag: Int){ }
}
You can use self.removeFromSuperview()
// Completely agree with comments, change to ChatOverlay
class chatOverlay: UIView {
#IBAction func closeOverlay(_ sender: UIButton) {
self.removeFromSuperview()
}
}
If you want it to fade away
// Again, completely agree with comments, change to ChatOverlay
class chatOverlay: UIView {
#IBAction func closeOverlay(_ sender: UIButton) {
UIView.animate(withDuration: 0.5, animations: {
self.alpha = 0.0
}) { (_) in
self.removeFromSuperview()
}
}
}
I am really curious how you are using a UIView inside chatOverlay when you appear to only be importing Foundation? Also, cannot figure out why in overlayAdd you are importing both Foundation and UIKit? UIKit itself imports Foundation. The biggest confussion to me is why do you have a class overlayAdd at all? Shouldn't the show function be more of a create function (you are not showing it till you add it as a subview) and just be a part of chatOverlay? Something like:
// Completely agree with comments, change to ChatOverlay
class chatOverlay: UIView {
#IBAction func closeOverlay(_ sender: UIButton) {
UIView.animate(withDuration: 0.5, animations: {
self.alpha = 0.0
}) { (_) in
self.removeFromSuperview()
}
}
static func create(withFrame: frame, tag: Int) -> UIView{
let chatOverlay = xibLoad().chatOverlay()
chatOverlay.frame = frame
chatOverlay.tag = tag
/*
What in the world are you trying to do here???
let view = chatOverlay
return view
get rid of these two completely useless lines!
just return chatOverlay like below...
*/
return chatOverlay
}
}
and then in chatPage:
// Completely agree with comments, change to ChatPage
class chatPage: UIViewController {
override func viewDidLoad(){
view.addSubview(chatOverlay.create(withFrame: view.frame, tag: 101))
}
}

How to slide TabBar up to hide it in tvOS app?

In my tvOS app I have a TabBarController with 3 viewControllers. What I want to do is to automatically hide/change focus of the tabBar when I switch to the next viewController.
I saw some posts here, on SO that suggested to change alfa on the tabBar, but I would like to have a slide up animation, same way as it does when you change focus to something in the viewController.
Any kind of help is highly appreciated.
As Charles said.. Something like this in the derived UITabBarController:
var focusOnChildVC : Bool = false {
didSet {
self.setNeedsFocusUpdate()
}
};
override weak var preferredFocusedView: UIView? {
get {
let v : UIView?;
let focused = UIScreen.mainScreen().focusedView
//A bit of a hack but seems to work for picking up whether the VC is active or not
if (focusOnChildVC && focused != nil) {
v = self.selectedViewController?.preferredFocusedView
} else {
//If we are focused on the main VC and then clear out of property as we're done with overriding the focus now
if (focusOnChildVC) {
focusOnChildVC = false
}
v = super.preferredFocusedView;
}
return v
}
}
The basic idea of the solution described below is to subclass UITabBarController and selectively use the super implementation of weak var preferredFocusedView: UIView? { get } or one that returns selectedViewController?.preferredFocusView along with an implementation of didUpdateFocusInContext(_:withAnimationCoordinator:) that sets up an NSTimer that triggers a focus update and sets a flag that controls the preferredFocusView implementation.
More verbosely, Subclass UITabBarController and override didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator). In your implementation (make sure to call the super implementation) you can inspect the context and determine if a descendent view of the tabBar property is the nextFocusedView or the previousFocusedView (and the nextFocusedView is not a descendent).
If the tab bar is gaining focus you can create an NSTimer for the duration that you want to show the tab bar before hiding it. If the tab bar loses focus before the timer fires, invalidate it. If the timer fires, call setNeedsFocusUpdate() followed by updateFocusIfNeeded().
The last piece you need to get this to work is a flag that is set to true while the timer is set. You then need to override weak var preferredFocusedView: UIView? { get } and call the super implementation if the flag is false and if it is true return selectedViewController?.preferredFocusedView.
You can do it in a UITabBarController subclass:
final class TabBarViewController: UITabBarController {
private(set) var isTabBarHidden = false
func setTabBarHidden(_ isHidden: Bool, animated: Bool) {
guard isTabBarHidden != isHidden else {
return
}
var frame: CGRect
let alpha: CGFloat
if isHidden {
frame = tabBar.frame
frame.origin.y -= frame.height
alpha = 0
} else {
frame = tabBar.frame
frame.origin.y += frame.height
alpha = 1
}
let animations = {
self.tabBar.frame = frame
self.tabBar.alpha = alpha
}
if animated {
UIView.animate(withDuration: 0.3, animations: animations)
} else {
animations()
}
isTabBarHidden = isHidden
}
}

How to programmatically scroll to next view controller in Scroll View Container

I created a scroll view container that houses three view controllers. It's meant to mimic snapchat's swipe layout. however, I can't seem to get a code to manually switch to the next view controller without actually swiping (which I'm not interested in)
I tried calling the container class and setting it's scroll offset but it crashes... tried creating a delegate protocol, but delegate is returning nil... I'm stumped.
Here is my code:
class AViewController: UIViewController, ABViewControllerDelegate {
#IBOutlet var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
// 1) Create the three views used in the swipe container view
var ATVc : ATViewController = ATViewController(nibName: "ATViewController", bundle: nil);
var ACVc : ACViewController = ACViewController(nibName: "ACViewController", bundle: nil);
var ABVc : ABViewController = ABViewController(nibName: "ABViewController", bundle: nil);
// 2) Add in each view to the container view hierarchy
// Add them in opposite order since the view hieracrhy is a stack
self.addChildViewController(ABVc);
self.scrollView!.addSubview(ABVc.view);
ABVc.didMoveToParentViewController(self);
self.addChildViewController(ACVc);
self.scrollView!.addSubview(ACVc.view);
ACVc.didMoveToParentViewController(self);
self.addChildViewController(ATVc);
self.scrollView!.addSubview(ATVc.view);
ATVc.didMoveToParentViewController(self)
// 3) Set up the frames of the view controllers to align
// with eachother inside the container view
var adminFrame :CGRect = ATVc.view.frame;
adminFrame.origin.y = adminFrame.height;
ACVc.view.frame = adminFrame;
var BFrame :CGRect = ACVc.view.frame;
BFrame.origin.y = 2*BFrame.height;
ABVc.view.frame = BFrame;
// 4) Finally set the size of the scroll view that contains the frames
var scrollWidth: CGFloat = self.view.frame.width
var scrollHeight: CGFloat = 3 * self.view.frame.size.height
self.scrollView!.contentSize = CGSizeMake(scrollWidth, scrollHeight)
self.scrollView!.setContentOffset(CGPointMake(0, self.view.frame.height), animated: false)
var changeMe : String = "okay"
}
func scrollUp() {
println("clicked!")
self.scrollView.contentOffset.y - self.view.frame.height
}
}
and this is the view controller I'm trying to get out off by pressing a button..
protocol ABViewControllerDelegate {
func scrollUp()
}
class ABViewController: UIViewController {
let delegate = ABViewControllerDelegate?()
#IBAction func button(sender: AnyObject) {
println("button clicked!")
delegate!.scrollUp()
}
}
I feel like I'm leading myself on and that it can't be done!