I have multiple UIView, then after add and remove button on UIView in last want check my view is empty or not.
above image 3rd view is empty how to check programmatically
this view is empty or not.
You can check the amount of subviews in that specific view:
if([theView.subviews count] == 0) {
// View does not contain subviews
}
If you have multiple UIViews inside a parent view and you wish to figure out which views are empty, then loop over the parent subviews and check each if empty or not:
for(UIView * view in parentView.subviews) {
if([view isKindOfClass:[UIView class]] && [view.subviews count] == 0) {
// We found an empty UIView...
// Can you identify this view?
// If you need to do something with it, do it here.
}
}
Try This:
extension UIView {
var isViewEmpty : Bool {
return self.subviews.count == 0 ;
}
}
Paste extension code outside of the viewController class.
After removing button from view, every time check for isViewEmpty as below,
//if you don't have the object of view, you can get view as below,
let view = bottonToRemove.superview;//this will give you obejct for check
//your code to remove button from the view
if view.isViewEmpty {
//implement your logic for if view is empty
}else{
//view not empty
//do you stuff
}
UIView has a property subViews. This will return you an array of all subViews. If the array is null or has count zero then there is no subview in it.
i think as per your requirement you need check there is any button in view or not you can try
BOOL isEmpty = true;
for (UIButton *btn in viewTest.subviews) {
if ([btn isKindOfClass:[UIButton class]]) {
isEmpty = false;
break;
}
}
if (isEmpty == false) {
// there is button in view
}
else
{
// there no button in view
}
Seems like you are checking on the UINavigationBar,
for (UIView *view in self.navigationController.navigationBar.subviews) {
if(view)
//Do your thing
}
I am trying to incorporate some 3D touch into an application and I've run into a weird issue where the forceTouchCapability check is returning nil on viewDidLoad but not in viewWillAppear/viewDidAppear.
I'm aware that this is only available on iOS 9+ so I've added checks to verify that the traitCollection property on the view controller responds to forceTouchCapability as in the following:
- (void)loadView {
self.view = [[MyView alloc] init];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Checking the force touch availability here
if ([self.traitCollection respondsToSelector:#selector(forceTouchCapability)] &&
self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
// This won't get called because forceTouchCapability is returning nil
// which corresponds to UIForceTouchCapabilityUnknown
[self registerForPreviewingWithDelegate:self sourceView:self.view];
}
}
In LLDB with a breakpoint at the if statement, entering po [self.traitCollection forceTouchCapability] returns nil which corresponds to UIForceTouchCapabilityUnknown. However, the traitCollection itself is not nil.
According to the documentation for UIForceTouchCapabilityUnknown:
UIForceTouchCapabilityUnknown: The availability of 3D Touch is unknown. For example, if you create a view but have not yet added it to your app’s view hierarchy, the view’s trait collection has this value.
Has the view not been added to the hierarchy by this point?
I'm curious if anyone has run into this issue before and how to work around this? I would like to avoid adding this in the viewDidAppear as this can get called quite a bit.
If it helps, I'm running this on a 6S on iOS 9.1 with Xcode 7.2
The view hasn't been added to the View Hierarchy yet. You can see this easily by checking for a superview in the debug console
(lldb) po self.view.superview
nil
If that's what you're seeing, the view hasn't been added to a hierarchy yet: so you have to put your check elsewhere.
This is kind of confusing because in Apple's ViewControllerPreview sample app it's in viewDidLoad. But it really should in traitCollectionDidChange:, because then you're sure that the view has been added to the app's hierarchy.
This is the code I use (works on iOS 8, if you don't need to support that feel free to move the outer conditional).
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
[super traitCollectionDidChange:previousTraitCollection];
if ([self.traitCollection respondsToSelector:#selector(forceTouchCapability)]) {
if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
// retain the context to avoid registering more than once
if (!self.previewingContext) {
self.previewingContext = [self registerForPreviewingWithDelegate:self sourceView:self.view];
}
} else {
[self unregisterForPreviewingWithContext:self.previewingContext];
self.previewingContext = nil;
}
}
}
The added benefit to this is that your view will be registered/unregistered if the user changes their 3D Touch settings while the app is running.
I've also seen this issue, and found that the easiest way to check whether the device can support force touch or not is doing it via the screen instance. This kinda makes sense because the capability is a property of the screen. Doing it this way means you don't have to worry about the lifecycle of a viewcontroller or a view.
func canForceTouch() -> Bool
{
if iOS9OrHigher // pseudocode, a function that makes sure u only do this check on ios9 or higher
{
return UIScreen.mainScreen().traitCollection.forceTouchCapability == .Available
}
return false
}
Like what #bpapa said, Your view hasn't added to view hierarchy yet, But my solution is different little bit:
var token:dispatch_once_t = 0
override func viewDidAppear(animated: Bool) {
dispatch_once(&token) {
// Force Touch Checking
if #available(iOS 9.0, *) {
if self.traitCollection.forceTouchCapability == .Available {
self.registerForPreviewingWithDelegate(self, sourceView: self.view)
}
}
}
}
This is the code I am using to set the constraints in viewDidLoad:
if (self.presentingViewController?.isKindOfClass(GameViewController) != nil) {
print("huhu")
self.bottomViewToBottomConstraint.constant = -367
self.bottomViewToHiddenButtonConstraint.constant = 401
} else {
self.bottomViewToBottomConstraint.constant = -200
self.bottomViewToHiddenButtonConstraint.constant = 200
print("No presenting viewController")
}
The message I'm getting is No presenting viewController. As you can see I am also setting constraints which will be animated differently, depending on what class is presenting viewController. So at what time it is already known who is presenting view controller and is also the right time to set the constraints? Thanks for help
As simple as:
After you add the bottomView to it's superview.
Try viewWillAppear method:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// here
}
I want to override my MYViewController : UIViewController's setView: method, such that, I do not allow some one to set view's property to nil.
-(void)setView:(UIView*)view {
if (view == nil)
//ignore - make no change
else
//default performance
}
How can I do this?
Calling the super class only when you want the default behavior should do the work:
-(void)setView:(UIView*)view {
if (view == nil) {
//ignore - make no change
}
else {
//default performance
[super setView:view];
}
}
#synthesize view = _view;
-(void)setView:(UIView*)view {
if (view)
_view = view;
}
It could be done as simple as this. If view is not nil, set the variable.
I have a tab bar application, with many views. Is there a way to know if a particular UIViewController is currently visible from within the UIViewController? (looking for a property)
The view's window property is non-nil if a view is currently visible, so check the main view in the view controller:
Invoking the view method causes the view to load (if it is not loaded) which is unnecessary and may be undesirable. It would be better to check first to see if it is already loaded. I've added the call to isViewLoaded to avoid this problem.
if (viewController.isViewLoaded && viewController.view.window) {
// viewController is visible
}
Since iOS9 it has became easier:
if viewController.viewIfLoaded?.window != nil {
// viewController is visible
}
Or if you have a UINavigationController managing the view controllers, you could check its visibleViewController property instead.
Here's #progrmr's solution as a UIViewController category:
// UIViewController+Additions.h
#interface UIViewController (Additions)
- (BOOL)isVisible;
#end
// UIViewController+Additions.m
#import "UIViewController+Additions.h"
#implementation UIViewController (Additions)
- (BOOL)isVisible {
return [self isViewLoaded] && self.view.window;
}
#end
There are a couple of issues with the above solutions. If you are using, for example, a UISplitViewController, the master view will always return true for
if(viewController.isViewLoaded && viewController.view.window) {
//Always true for master view in split view controller
}
Instead, take this simple approach which seems to work well in most, if not all cases:
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
//We are now invisible
self.visible = false;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
//We are now visible
self.visible = true;
}
For those of you looking for a Swift 2.2 version of the answer:
if self.isViewLoaded() && (self.view.window != nil) {
// viewController is visible
}
and Swift 3:
if self.isViewLoaded && (self.view.window != nil) {
// viewController is visible
}
For over-full-screen or over-context modal presentation, "is visible" could mean it is on top of the view controller stack or just visible but covered by another view controller.
To check if the view controller "is the top view controller" is quite different from "is visible", you should check the view controller's navigation controller's view controller stack.
I wrote a piece of code to solve this problem:
extension UIViewController {
public var isVisible: Bool {
if isViewLoaded {
return view.window != nil
}
return false
}
public var isTopViewController: Bool {
if self.navigationController != nil {
return self.navigationController?.visibleViewController === self
} else if self.tabBarController != nil {
return self.tabBarController?.selectedViewController == self && self.presentedViewController == nil
} else {
return self.presentedViewController == nil && self.isVisible
}
}
}
You want to use the UITabBarController's selectedViewController property. All view controllers attached to a tab bar controller have a tabBarController property set, so you can, from within any of the view controllers' code:
if([[[self tabBarController] selectedViewController] isEqual:self]){
//we're in the active controller
}else{
//we are not
}
I made a swift extension based on #progrmr's answer.
It allows you to easily check if a UIViewController is on screen like so:
if someViewController.isOnScreen {
// Do stuff here
}
The extension:
//
// UIViewControllerExtension.swift
//
import UIKit
extension UIViewController{
var isOnScreen: Bool{
return self.isViewLoaded() && view.window != nil
}
}
For my purposes, in the context of a container view controller, I've found that
- (BOOL)isVisible {
return (self.isViewLoaded && self.view.window && self.parentViewController != nil);
}
works well.
I use this small extension in Swift 5, which keeps it simple and easy to check for any object that is member of UIView.
extension UIView {
var isVisible: Bool {
guard let _ = self.window else {
return false
}
return true
}
}
Then, I just use it as a simple if statement check...
if myView.isVisible {
// do something
}
I hope it helps! :)
Good point that view is appeared if it's already in window hierarchy stack.
thus we can extend our classes for this functionality.
extension UIViewController {
var isViewAppeared: Bool { viewIfLoaded?.isAppeared == true }
}
extension UIView {
var isAppeared: Bool { window != nil }
}
XCode 6.4, for iOS 8.4, ARC enabled
Obviously lots of ways of doing it. The one that has worked for me is the following...
#property(nonatomic, readonly, getter=isKeyWindow) BOOL keyWindow
This can be used in any view controller in the following way,
[self.view.window isKeyWindow]
If you call this property in -(void)viewDidLoad you get 0, then if you call this after -(void)viewDidAppear:(BOOL)animated you get 1.
Hope this helps someone. Thanks! Cheers.
if you're utilizing a UINavigationController and also want to handle modal views, the following is what i use:
#import <objc/runtime.h>
UIViewController* topMostController = self.navigationController.visibleViewController;
if([[NSString stringWithFormat:#"%s", class_getName([topMostController class])] isEqualToString:#"NAME_OF_CONTROLLER_YOURE_CHECKING_IN"]) {
//is topmost visible view controller
}
The approach that I used for a modal presented view controller was to check the class of the presented controller. If the presented view controller was ViewController2 then I would execute some code.
UIViewController *vc = [self presentedViewController];
if ([vc isKindOfClass:[ViewController2 class]]) {
NSLog(#"this is VC2");
}
I found those function in UIViewController.h.
/*
These four methods can be used in a view controller's appearance callbacks to determine if it is being
presented, dismissed, or added or removed as a child view controller. For example, a view controller can
check if it is disappearing because it was dismissed or popped by asking itself in its viewWillDisappear:
method by checking the expression ([self isBeingDismissed] || [self isMovingFromParentViewController]).
*/
- (BOOL)isBeingPresented NS_AVAILABLE_IOS(5_0);
- (BOOL)isBeingDismissed NS_AVAILABLE_IOS(5_0);
- (BOOL)isMovingToParentViewController NS_AVAILABLE_IOS(5_0);
- (BOOL)isMovingFromParentViewController NS_AVAILABLE_IOS(5_0);
Maybe the above functions can detect the ViewController is appeared or not.
If you are using a navigation controller and just want to know if you are in the active and topmost controller, then use:
if navigationController?.topViewController == self {
// Do something
}
This answer is based on #mattdipasquale's comment.
If you have a more complicated scenario, see the other answers above.
you can check it by window property
if(viewController.view.window){
// view visible
}else{
// no visible
}
I needed this to check if the view controller is the current viewed controller, I did it via checking if there's any presented view controller or pushed through the navigator, I'm posting it in case anyone needed such a solution:
if presentedViewController != nil || navigationController?.topViewController != self {
//Viewcontroller isn't viewed
}else{
// Now your viewcontroller is being viewed
}
Window:
window.isVisible
viewController.view.window?.isVisible ?? false
View (macOS):
extension NSViewController {
var isOnScreen: Bool {
return ( self.isViewLoaded && view.window != nil )
}
}