How to List Out All the Subviews in a Uiviewcontroller in iOS

How to list out all the subviews in a uiviewcontroller in iOS?

You have to recursively iterate the sub views.

- (void)listSubviewsOfView:(UIView *)view {

// Get the subviews of the view
NSArray *subviews = [view subviews];

for (UIView *subview in subviews) {

// Do what you want to do with the subview
NSLog(@"%@", subview);

// List the subviews of subview
[self listSubviewsOfView:subview];
}
}

Swift: Get all subviews of a specific type and add to an array

The filter function using the is operator can filter items of a specific class.

let myViews = view.subviews.filter{$0 is MyButtonClass}

MyButtonClass is the custom class to be filtered for.

To filter and cast the view to the custom type use compactMap

let myViews = view.subviews.compactMap{$0 as? MyButtonClass}

Getting all subviews of a subview

You can either create IBOutlets, or use unique tags in all the objects you wish to reference and use viewWithTag to get a reference to the objects pointer.

If you use viewWithTag, make sure to check the object pointer against nil, to avoid runtime crashes.

To use viewWithTag, you need to assign a unique Tag in IB, see screenshot:

Sample Image

As you see my UILabel has here a Tag of 253 and to access it's pointer object I have to use viewWithTag:

UILabel *myTagLabel = (UILabel*)[self.view viewWithTag:253];

And as I suggested before using that pointer, check against nil:

if (myTagLabel) {
//object pointer retrieved successfully
myTagLabel.text = @"Hello";
}

How can I loop through all subviews of a UIView, and their subviews and their subviews

Use recursion:

// UIView+HierarchyLogging.h
@interface UIView (ViewHierarchyLogging)
- (void)logViewHierarchy;
@end

// UIView+HierarchyLogging.m
@implementation UIView (ViewHierarchyLogging)
- (void)logViewHierarchy
{
NSLog(@"%@", self);
for (UIView *subview in self.subviews)
{
[subview logViewHierarchy];
}
}
@end

// In your implementation
[myView logViewHierarchy];

Get ALL view inside ViewController

You need to recursively process all subviews.

func processSubviews(of view: UIView) {
// 1. code here do something with view
for subview in view.subviews {
// 2. code here do something with subview
processSubviews(of: subview)
// 3. code here do something with subview
}
// 4. code here do something with view
}

You need to put your code at either position 1, 2, 3, or 4 (or possibly two or more of those places) depending on the results you want.

Then you can call this as:

processSubviews(of: self.view)

ios how can get the list of subview on view?

You can do in this way

- (void)listSubviewsOfView:(UIView *)view {

// Get the subviews of the view
NSArray *subviews = [view subviews];

// Return if there are no subviews
if ([subviews count] == 0) return;

for (UIView *subview in subviews) {

NSLog(@"%@", subview);

// List the subviews of subview
[self listSubviewsOfView:subview];
}
}

Please go through this link How to list out all the subviews in a uiviewcontroller in iOS?

Laying out & sizing of subviews in a UIViewController

autoresizesSubviews should be set on your parent view, while autoresizingMask should be set on the child views - this is the mistake I made so you could, too.

In loadView you should size your subviews to fit whatever size of parent view is at the moment, and then later on when parent view is resized from 460 to 367 pixels your sub-views will be resized as well, according to your mask settings above.

If that fails, there is nothing wrong in setting the view size within viewWillAppear - the performance impact of doing it every time is negligible.

If nothing else works, there is always layoutSubviews: - there you could do manual layout if you have to, it's invoked when system believes layout may have to change. there is also setNeedsLayout: that I sometimes invoke from viewWillRotate:/viewDidRotate: etc. But really this shouldn't be needed and autoresize should be good enough.

EDIT: Yes, to implement custom layout logic in layoutSubviews as I mention above one would need to subclass UIView.

Add subview on the top of every ViewController


UIApplication.topWindow.addSubview(CustomView)

extension UIApplication {

static var topWindow: UIWindow {
if #available(iOS 15.0, *) {
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
return windowScene!.windows.first!
}
return UIApplication.shared.windows.filter { $0.isKeyWindow }.first!
}
}

When to layout subviews of UIViewControllers view?

You can override - (void)layoutSubviews on your safeAreaView class:

- (void)layoutSubviews {
[super layoutSubviews];

// Manual frame adjustment for non-autolayout participating subviews
// ...
}

Another option would be to override your safeAreaView's class frame setter, so each time the frame of your view changes, you'll get a chance to manually set any subview frames as needed.

Redrawing UIViewController and its subviews


Here is the solution.

@interface ViewController ()
@property (strong, nonatomic) NSMutableArray *frames;
@end

@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];

//Saving initial frames of all subviews
self.frames = [NSMutableArray new];
NSArray *allViews = [self allViewsOfView:self.view];
for (UIView *view in allViews) {
CGRect frame = view.frame;
NSValue *frameValue = [NSValue valueWithCGRect:frame];
[self.frames addObject:frameValue];
}
}

- (NSMutableArray *)allViewsOfView:(UIView *)view
{
NSMutableArray *result = [NSMutableArray new];
[result addObject:view];
for (UIView *subView in view.subviews) {
[result addObjectsFromArray:[self allViewsOfView:subView]];
}

return result;
}

- (void)resetFrames
{
NSArray *allViews = [self allViewsOfView:self.view];
for (UIView *view in allViews) {
NSValue *frameValue = [self.frames objectAtIndex:[allViews indexOfObject:view]];
CGRect frame = [frameValue CGRectValue];
view.frame = frame;
}
}

@end

Call [self resetFrame]; whenever you want to revert view's frames back to their initial values.



Related Topics



Leave a reply



Submit