I have a random child view in a view hierarchy. What is the best/fastest/cleverest way to get to the root superview?
Cheers,
Doug
If your app only has one UIWindow (usually true), and if that window's only subview is your root controller's view (also usually true):
[randomChildView.window.subviews objectAtIndex:0]
Or you could recursively climb out of the hierarchy, by checking view.superview until you find a view whose superview is nil.
It's an insignificant amount of processor time to go straight up the superview hierarchy. I have this in my UIView category.
- (UIView *)rootView {
UIView *view = self;
while (view.superview != Nil) {
view = view.superview;
}
return view;
}
swift3/4:
func rootSuperView() -> UIView
{
var view = self
while let s = view.superview {
view = s
}
return view
}
I like this one.
extension UIView {
func rootView() -> UIView {
return superview?.rootView() ?? superview ?? self
}
}
Fast solution (fast as in minimalist):
extension UIView {
var rootView: UIView {
superview?.rootView ?? self
}
}
Related
I am getting one weird issue, I am setting constraints on the view using storyboard as below:
But if I am accessing all applied constraint by code then always getting zero (0).
for self.view it's returning the constraint but for yellow view getting zero.
Use this code (Swift 4+ and Xcode 9.4.1)
import UIKit
class ViewController: UIViewController {
#IBOutlet var subView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
print(self.view.getAllConstraints().count)
print(self.subView.getAllConstraints().count)
}
}
extension UIView {
func getAllConstraints() -> [NSLayoutConstraint] {
var views = [self]
var view = self
while let superview = view.superview {
views.append(superview)
view = superview
}
return views.flatMap({ $0.constraints }).filter { constraint in
return constraint.firstItem as? UIView == self ||
constraint.secondItem as? UIView == self
}
}
}
Just try to print constraints in viewDidAppear. In viewDidLoad method constraints not loaded for view so, just try in viewDidAppear method.
for your information when viewDidLoad is called subviews is not laid out yet thats why you getting count zero put you code into viewDidLayoutSubviews you will get your constraints there
I am trying to get all views inside my UIViewController.
I am using this code:
for subview : UIView in self.view.subviews{
//code here
}
the problem is that I don't get views that are inside a UIView.
so I get all view except of their children.
please, how can I get ALL Views that are either child or parent inside my UIViewController? even if a view has a child that has a child that has a child. I want to go through all views.
thanx in advance :)
(please in swift 4.0)
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)
For get all views (as Label, Button, View, ...) in your view hierarchy and access to all child view in your viewController you should using from a recursive func to iterate all views :
func getAllSubviews(view:UIView) {
for subview in view.subviews {
if let takenLabel = subview as? UILabel {
takenLabel.backgroundColor = UIColor.red
}
getAllSubviews(view:subview)
}
}
You can using from this func to access other view like button and change them .
in this case i'm changing background color of all label in viewController to red
There are many different way to get subviews
To Get all the subviews in the parent view
for subview in view.subviews{
// you can get all of your views one by one here.
}
To Filter if any tagged view is available or not (lets assume view is tagged by 100)
view.subviews.filter{$0.tag == 100}
Extensions to check if Any view contains sub views
extension UIView{
func isAvailabletoParentView(inParentView : UIView, subViewTag : Int) -> Bool{
var isAvailable = false
for subviews in inParentView.subviews{
if subviews.tag == subViewTag{
isAvailable = true
return true
}else{
isAvailable = false
}
}
return isAvailable
}
}
Call Extension like
subview.isAvailabletoParentView(inParentView: parentView, subViewTag: anyTagToSubView)
Hope it will helps , Happy coding 🙂.
I'm trying to get the content size of UITableView in runtime, where I working on library that will do some moves when pop over the views and to do this I wrote this code inside the library to figure out that inside the presented view will be UITableView:
if view.isKind(of: UIView.self) {
for subView in view.subviews {
for sv in subView.subviews {
if sv.isKind(of: UITableView.self) {
print(sv.frame.size.height)
Here I got the table view, but I couldn't get the contentSize property
print("table view found")
}
}
}
}
Any tips how to get its content size ?!
Use a cast instead of a test so that the compiler knows the object's properties:
if view.isKind(of: UIView.self) {
for subView in view.subviews {
for sv in subView.subviews {
if let tableView = sv as? UITableView {
print(tableView.contentSize.height)
}
}
}
}
Does anybody know is there any way to call status bar tapping programmatically when view appeared? My view is not on the top when appearing.
Thank you!
I'm going to assume that what you want to do is scroll your view to the top, which is what tapping the status bar does. If that's the case then here is a nice little view controller extension to achieve that.
extension UIViewController {
func scrollToTop() {
func scrollToTop(view: UIView?) {
guard let view = view else { return }
switch view {
case let scrollView as UIScrollView:
if scrollView.scrollsToTop == true {
scrollView.setContentOffset(CGPoint(x: 0.0, y: -scrollView.contentInset.top), animated: true)
return
}
default:
break
}
for subView in view.subviews {
scrollToTop(view: subView)
}
}
scrollToTop(view: view)
}
var isScrolledToTop: Bool {
for subView in view.subviews {
if let scrollView = subView as? UIScrollView {
return (scrollView.contentOffset.y == 0)
}
}
return true
}
}
Then in the viewDidAppear of your view controller, you can call
myViewController.scrollToTop()
I have UIButton inside cell of UITableView, When i touch the button it is actually working but the animation of highlighted is not being seen, I have tried setting delaysContentTouches = false on viewDidLoad and also on IB
I even tried to find UIScrollVIew of table view so that i can set that properties to false, like...
for cls in cell.subviews
{
println("name of class is ::\(NSStringFromClass(cls.classForCoder))")
if NSStringFromClass(cls.classForCoder) == "UITableViewCellScrollView"
{
cls.scrollView.delaysContentTouches = false
break
}
}
Thanks in advance!
UITableView subclass
override public var delaysContentTouches: Bool {
didSet {
if let subviews = self.subviews as? [UIView] {
for view in subviews {
if let scroll = view as? UIScrollView {
scroll.delaysContentTouches = delaysContentTouches
}
break
}
}
}
}