I am trying to loop all my subviews and print them in NSLog.
I have developed this recursive method:
- (void)allSubViews:(UIView*)mainV
{
for (UIView *view in mainV.subviews) {
NSLog(#"%#", view);
if ([[view subviews]count]>0) {
[self allSubViews:view];
}
}
}
which I call from MainViewController.m:
[self allSubViews:self.myView];
The result is:
2015-09-12 11:18:48.919 Profile-Statistics[3153:506562] <_UILayoutGuide: 0x7fc70bf1c330; frame = (0 0; 0 0); hidden = YES;
layer = >
2015-09-12 11:18:48.919 Profile-Statistics[3153:506562] <_UILayoutGuide: 0x7fc70bf1ced0; frame = (0 0; 0 0); hidden = YES;
layer = >
My View has Top and Bottom Layout Guide and a View which has 3 UIButtons, 1 ImageView and 1 UIView.
Did I miss something here?
Update:
Screenshot of StoryBoard
For what it's worth, I tried this in a sample project with a bunch of subviews and it worked as expected.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (IBAction)printButtonTapped:(id)sender {
[self allSubviews:self.view];
}
- (void) allSubviews:(UIView*) parent {
NSLog(#"%#", parent);
for (UIView *child in parent.subviews) {
[self allSubviews:child];
}
}
#end
Console output is:
2015-09-13 22:06:00.904 RecursivePrint[66243:3455899] <UIView: 0x7fa902e0e6e0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7fa902e15030>>
2015-09-13 22:06:00.905 RecursivePrint[66243:3455899] <UIView: 0x7fa902e0e840; frame = (70 56; 452 337); autoresize = RM+BM; layer = <CALayer: 0x7fa902e15050>>
2015-09-13 22:06:00.905 RecursivePrint[66243:3455899] <UIView: 0x7fa902e24c90; frame = (31 33; 153 160); autoresize = RM+BM; layer = <CALayer: 0x7fa902e21f00>>
2015-09-13 22:06:00.906 RecursivePrint[66243:3455899] <UIView: 0x7fa902e24fc0; frame = (219 41; 153 160); autoresize = RM+BM; layer = <CALayer: 0x7fa902e1ec10>>
2015-09-13 22:06:00.906 RecursivePrint[66243:3455899] <UIButton: 0x7fa902d177e0; frame = (164.5 603; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fa902d16c80>>
2015-09-13 22:06:00.907 RecursivePrint[66243:3455899] <UIButtonLabel: 0x7fa902d1f010; frame = (0 6; 46 18); text = 'Button'; alpha = 0.2; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fa902d1f670>>
2015-09-13 22:06:00.907 RecursivePrint[66243:3455899] <_UILayoutGuide: 0x7fa902e25ed0; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x7fa902e21b20>>
2015-09-13 22:06:00.907 RecursivePrint[66243:3455899] <_UILayoutGuide: 0x7fa902f77ec0; frame = (0 667; 0 0); hidden = YES; layer = <CALayer: 0x7fa902f09f70>>
As a side note, this is the first time in over a year that I've tried to do something in Objective-C. The Swift version seems so much easier to understand:
import UIKit
class ViewController: UIViewController {
#IBAction func printButtonTapped(sender: UIButton) {
printSubviews(self.view)
}
}
func printSubviews(parent:UIView) {
print(parent)
for child in parent.subviews {
printSubviews(child)
}
}
In addition, the Swift version of printSubviews is defined as a function, not a method so you don't call it from self, you just call it with the top level view you want to start with.
Related
I have several UIView layers in one ViewController.
How can I determine the order of UIView programmatically?
I found the solution...
In the UIView documentation, where are several methods listed for the manipulation of the order of subviews:
bringSubviewToFront(_:)
sendSubviewToBack(_:)
removeFromSuperview()
insertSubview(_:atIndex:)
insertSubview(_:aboveSubview:)
insertSubview(_:belowSubview:)
exchangeSubviewAtIndex(_:withSubviewAtIndex:)
In Swift 4.0
view.sendSubview(toBack:yourUIView)
view.bringSubview(toFront:yourUIView)
Views are ordered from back-most to front-most in view.subviews array.
For example, here are 3 subview added to an empty view.
view.addSubview(UILabel())
view.addSubview(UIButton())
view.addSubview(UITextField())
Printing the subviews with the following code
for view in view.subviews {
print(view.debugDescription)
}
has the output
<UILabel: 0x7feef00042e0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x60400008c210>>
<UIButton: 0x7feef00045c0; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x604000222300>>
<UITextField: 0x7feeef02c800; frame = (0 0; 0 0); text = ''; opaque = NO; gestureRecognizers = <NSArray: 0x60800005b090>; layer = <CALayer: 0x604000222280>>
When the views are reordered, the position in view.subviews changes
if let button = view.subviews.first(where: { $0 is UIButton }) {
view.bringSubview(toFront: button)
}
Now, printing the view, has the output
<UILabel: 0x7feef00042e0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x60400008c210>>
<UITextField: 0x7feeef02c800; frame = (0 0; 0 0); text = ''; opaque = NO; gestureRecognizers = <NSArray: 0x60800005b090>; layer = <CALayer: 0x604000222280>>
<UIButton: 0x7feef00045c0; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x604000222300>>
I use transitionFromView switch two UIView ,But there is somethine wrong with it , When I transition the view to second UIView ,it work ok, then I transition the view back The error is happen(the location of first UIView is wrong)
What happen?
self.primaryView.hidden = !self.primaryView.hidden
self.secondaryView.hidden = !self.secondaryView.hidden
println("\(self.primaryView)")
UIView.transitionFromView(displayingPrimary ? self.primaryView : self.secondaryView,
toView: displayingPrimary ? self.secondaryView : self.primaryView,
duration: 1.0,
options: nil ) { (finish) -> Void in
if finish {
println("after:\(self.primaryView)")
self.displayingPrimary = !self.displayingPrimary;
}
}
this is print info in console
<UIView: 0x79fe3c80; frame = (0 0; 399 349); hidden = YES; autoresize = RM+BM; layer = <CALayer: 0x79fe3d10>>
after:<UIView: 0x79fe3c80; frame = (0 0; 399 349); hidden = YES; autoresize = RM+BM; layer = <CALayer: 0x79fe3d10>>
<UIView: 0x79fe3c80; frame = (0 0; 399 349); autoresize = RM+BM; layer = <CALayer: 0x79fe3d10>>
after:<UIView: 0x79fe3c80; frame = (-436 -328; 399 349); autoresize = RM+BM; layer = <CALayer: 0x79fe3d10>>
When is UIView.didAddSubview called ?
I have created a simple View and ViewController app.
When I run this app, didAddSubview is called twice on first time the View appears.
https://github.com/toshi0383/HelloUIView
below is the log output
didAddSubView
<_UILayoutGuide: 0x7f92d3425210; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7f92d3419cf0>>
didAddSubView
<_UILayoutGuide: 0x7f92d3425c10; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7f92d34244a0>>
viewDidLoad
[<_UILayoutGuide: 0x7f92d3425210; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7f92d3419cf0>>, <_UILayoutGuide: 0x7f92d3425c10; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7f92d34244a0>>]
didMoveToWindow
didMoveToSuperView
layoutSubviews
<ViewTest.View: 0x7f92d3424bc0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7f92d3423320>>
UILayoutGuide is a private Apple class.
UILayoutGuide is normally referred to -topLayoutGuide and -bottonLayoutGuide, those are not really constraints.
same questions here:
stack overflow : what-is-uilayoutguide
I'm getting some issues with a constraint relative from the bottom layout.
There are some views inside a UITabBarViewController. When I change to another view from the tab and return to first one, the viewcontroller not recognize the bottom layout as the tab bar, but from the bottom of the view.
I uploaded the problem here: https://sites.google.com/site/rveducationapps/layoutError.png?attredirects=0&d=1
I already tried put in ViewDidAppear and also ViewWillAppear:
[self.view layoutSubviews];
[self.view setNeedsUpdateConstraints];
I logged the subviews in the two cases, the right one and after I exit and return to the view:
subviews:(
"<UIView: 0x146b2260; frame = (210 0; 814 712); autoresize = RM+BM; layer = <CALayer: 0x146b22c0>>",
"<UIButton: 0x146a9eb0; frame = (727 672; 287 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x146aa070>>",
"<UITableView: 0x151d3400; frame = (0 0; 210 761); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x146b14b0>; layer = <CALayer: 0x146ade20>; contentOffset: {0, 0}>",
"<_UILayoutGuide: 0x146b23b0; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x146b24a0>>",
"<_UILayoutGuide: 0x146b28a0; frame = (0 712; 0 56); hidden = YES; layer = <CALayer: 0x146b2910>>"
)
subviews:(
"<UIView: 0x146b2260; frame = (210 0; 814 768); autoresize = RM+BM; layer = <CALayer: 0x146b22c0>>",
"<UIButton: 0x146a9eb0; frame = (727 728; 287 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x146aa070>>",
"<UITableView: 0x151d3400; frame = (0 0; 210 817); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x146b14b0>; layer = <CALayer: 0x146ade20>; contentOffset: {0, 0}>",
"<_UILayoutGuide: 0x146b23b0; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x146b24a0>>",
"<_UILayoutGuide: 0x146b28a0; frame = (0 768; 0 0); hidden = YES; layer = <CALayer: 0x146b2910>>"
)
I see there are some differences, specially in:"<_UILayoutGuide: 0x146b28a0; frame = (0 712; 0 56); hidden = YES; layer = <CALayer: 0x146b2910>>"
But I don't know how to fix it.
EDITED:
I think I fixed. I selected the UIViewController in the Storyboard and disabled the EXTEND EDGES->Under Bottom Bars option.
If you are transitioning from your UITabBarViewController to a new UIViewController, and then attempting to go back to your tabBarController from that UIViewController, then you could simply segue back to the UITabBarViewController(The segue will take you back to your rootViewController for your UITabBarViewController).
If you need to transition back to a specific tab, instantiate a custom segue and send it back to a different tab using a different specified VC, this can be set in your UITabBarViewController class or in your applications AppDelegate.m file.
This question has been re-written, since I think it has more to do with views and layers than the original 'Finding the center of a tableview'. Also in hope of finding another answer.
In question, is a set of 4 views to show activity, in a tableview, in a tab bar.
The code of:
NSLog(#"view.center: %#", self.view.center);
NSLog(#"view.frame: %#", self.view.frame);
Produces, on first display of 'loading':
view.center: {160, 250}
view.frame: {{0, 20}, {320, 460}}
For 2nd (and subsequent) displays: (after a pop up date picker)
view.center: {160, 205.5}
view.frame: {{0, 0}, {320, 411}}
Self (ListViewController) is subclass of UITableViewController. So, the height of the view (or tableview) frame is changing. Why?
I've been exploring and found this info in the debugger, that seems relevant.
--- Before ---
[self parentViewController]:
<UITabBarController: 0x6e115a0>
[[self parentViewController] view]:
<UILayoutContainerView: 0x6e1b750; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0x6e0c8f0>>
self: <ListsViewController: 0x6e13730>
[self tableView]:
<UITableView: 0x71e4000; frame = (0 20; 320 460); clipsToBounds = YES; opaque = NO; autoresize = W+H; layer = <CALayer: 0x6834db0>; contentOffset: {0, 0}>
[[self view] subviews]: (array)
<UIImageView: 0x6825e30; frame = (0 453; 320 7); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x6835a90>>,
<UIImageView: 0x68314e0; frame = (313 411; 7 20); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x683d120>>,
<UIView: 0x6a054f0; frame = (0 0; 320 460); alpha = 0.4; tag = 12; layer = <CALayer: 0x6a07840>>,
<UIView: 0x6a04c60; frame = (110 155.5; 100 100); alpha = 0.6; tag = 13; layer = <CALayer: 0x6a073c0>>,
<UILabel: 0x6a07480; frame = (110 200.5; 100 50); text = 'Loading ...'; clipsToBounds = YES; userInteractionEnabled = NO; tag = 14; layer = <CALayer: 0x6a065b0>>,
<UIActivityIndicatorView: 0x6a07a80; frame = (140 167.5; 40 40); tag = 15; layer = <CALayer: 0x6a07b40>>
--- After datepicker ---
[self parentViewController]:
<UITabBarController: 0x6e115a0>
[self parentViewController] view]:
<UILayoutContainerView: 0x6e1b750; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0x6e0c8f0>>
self: <ListsViewController: 0x6e13730>
[self tableView]:
<UITableView: 0x71e4000; frame = (0 0; 320 411); clipsToBounds = YES; opaque = NO; autoresize = W+H; layer = <CALayer: 0x6834db0>; contentOffset: {0, 0}>
[[self view] subviews]:
<DetailTableViewCell: 0xb642120; baseClass = UITableViewCell; frame = (0 369; 320 44); autoresize = W; layer = <CALayer: 0xb642230>>,
<DetailTableViewCell: 0xb643850; baseClass = UITableViewCell; frame = (0 325; 320 44); autoresize = W; layer = <CALayer: 0xb643960>>,
<DetailTableViewCell: 0xb6435c0; baseClass = UITableViewCell; frame = (0 281; 320 44); autoresize = W; layer = <CALayer: 0xb6436d0>>,
<DetailTableViewCell: 0xb63cf30; baseClass = UITableViewCell; frame = (0 237; 320 44); autoresize = W; layer = <CALayer: 0xb63d130>>,
<DetailTableViewCell: 0x6a14050; baseClass = UITableViewCell; frame = (0 193; 320 44); autoresize = W; layer = <CALayer: 0x6a16fb0>>,
<DetailTableViewCell: 0x6a13760; baseClass = UITableViewCell; frame = (0 149; 320 44); autoresize = W; layer = <CALayer: 0x6a13870>>,
<DetailTableViewCell: 0x6a10920; baseClass = UITableViewCell; frame = (0 105; 320 44); autoresize = W; layer = <CALayer: 0x6a10010>>,
<DetailTableViewCell: 0xb63ce20; baseClass = UITableViewCell; frame = (0 60; 320 45); autoresize = W; layer = <CALayer: 0xb63c3e0>>,
<UIImageView: 0x6825e30; frame = (0 404; 320 7); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x6835a90>>,
<UIView: 0xb6477f0; frame = (0 0; 320 60); autoresize = W; layer = <CALayer: 0xb647820>>,
<UIImageView: 0x68314e0; frame = (313 411; 7 20); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x683d120>>,
<UIView: 0x6a098a0; frame = (0 0; 320 411); alpha = 0; tag = 9; animations = { opacity <CABasicAnimation: 0xb6279f0>; }; layer = <CALayer: 0x6a154b0>>,
<UIDatePicker: 0x6a23350; frame = (0 455; 320 216); tag = 10; animations = { position <CABasicAnimation: 0xb63bd40>; }; layer = <CALayer: 0x6a20590>>,
<UIToolbar: 0x6843f60; frame = (0 411; 320 44); opaque = NO; tag = 11; animations = { position=<CABasicAnimation: 0xb645f80>; }; layer = <CALayer: 0x6844a20>>,
<UIView: 0xb60baa0; frame = (0 0; 320 411); alpha = 0.4; tag = 12; layer = <CALayer: 0xb626af0>>,
<UIView: 0xb626b20; frame = (110 155.5; 100 100); alpha = 0.6; tag = 13; layer = <CALayer: 0xb626930>>,
<UILabel: 0xb60cfb0; frame = (110 200.5; 100 50); text = 'Loading ...'; clipsToBounds = YES; userInteractionEnabled = NO; tag = 14; layer = <CALayer: 0xb60d020>>,
<UIActivityIndicatorView: 0xb649e20; frame = (140 167.5; 40 40); tag = 15; layer = <CALayer: 0xb626960>>
You can use tableview.frame to access the origin points and it's dimensions. You can use tablview.center which is a CGPoint which gives you the center point of the object.