UIActivityIndicatorView in the same hierarchy of UITableView in UITableViewController - ios

I have a UIViewController and I dropped a UITableView and UIActivityIndicatorView in the same hierarchy and it's working fine.
But then I have a UITableViewController, with a UITableView of course, and I try to drop a UIActivityIndicatorView at the same hierarchy as the Table View but with no luck. I know that there's a problem with UITableViewController and UIViewController with Table View but how to solve?
These two screenshots will help to understand the problem.
The way I want it to be:
The way it turns out:

The problem is that with the UIViewController it has a self.view as the root view where you can add any sub-items as you did , put you can't do this at least in IB with UITableViewController as the root view is the table itself
First way
add it in code and control is position as the tableView scrolls so change it's frame in scrollViewDidScroll so it's stay at center of screen during the loading
Second way
add it to the main window of the app and remove it when loading finishes

Ok, guys I found one more solution.
Define a variable inside UITableViewController
weak var spinner: UIActivityIndicatorView!
then in viewDidLoad method make this (hope the code is self explanatory)
let activityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: .gray)
tableView.backgroundView = activityIndicatorView
tableView.separatorStyle = .none
self.spinner = activityIndicatorView
and then call spinner.startAnimating() when you need to show it, and
self.spinner.stopAnimating()
self.tableView.separatorStyle = .singleLine
to remove it when you don't need it.

When you drag and drop any view (no matter if it is UILabel or UIActivityIndicatorView or UIView),
if it is above the cell you put there, it will be treated as the TableViewHeader automatically.
if it is below the cell you put there, it will be treated as the TableViewFooter automatically.
That is the reason why they are at the same level of view hierarchy of cells.
If you really want to use the indicatorView at same level as your tableView in your tableViewController, even if you programmatically create it and add it to your tableviewcontroller's self.view, it WILL NOT work, because tableViewController's self.view is its content view, which is scrollable anyways, which is kinda a bummer. We only have full control in UIViewController.

Related

Adding An UITableViewController on to a SubView

An UITableViewController pretty much takes up the entire view. I need a way to limit its height, width and add some shadows etc. For a clear explanation, I won't show the UITableViewController's contents.
Without the use of a storyboard, I subviewed the UITableViewController:
// In another UIViewController
let otherController = OtherController() // A subclass of UITableViewController
let otherControllerView = otherController.view
someView.addSubView(otherControllerView)
[...] // bunch of constraints
Notes:
In AppDelegate, if I set the rootController as OtherController(), everything works as it should. If I change it back to SomeView(), I see my modified tableView. If I should click it, it disappears.
This was the only thing that came close to my issue but sadly, I could not understand the answers provided as nothing made any sense to me.
I need to understand, why it disappears when touched etc.
view.bringSubviewToFront(...) proved futile. I'm gessing that a tableView should be rendered in its own controller and not in another view?
So just to answer this question, indeed you got two options. One is the best way, as suggested by Rakesha. Just use UITableView. Add it as a subview. Done.
And in the future, if you really want any controller to be added onto any UIView, remember you need to add that controller as a child. For example, in your case:
The controller of the view that will hold your UITableViewController will add such UITableViewController as a child.
self.addChild(yourUITableViewController)
self.whatEverViewContainer.addSubview(yourUITableViewController.view)
// Take note of the view of your tableViewController above^.
// Then setup the constraints of your yourUITableViewController.view below.
I hope this helps!
You must add the instance of UITableViewController's subclass as child view controller of the other view controller. You need to ensure few points in order to make it work. The points are as listed below:
Create the instance of your TableViewController
Add it as a child view controller of the other view controller
Add its view as a subview of the desired view (you may do these steps in viewDidLaod since they need to be done only once)
Keeping in mind the view cycle of a view controller. You must keep a weak reference of the child view controller aka TableViewController to adjust its view frame after the parent view controller has laid its subviews.
Code here:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let vc = TableViewController()
addChildViewController(vc)
view.addSubview(vc.view)
vc.didMove(toParentViewController: self)
childVC = vc
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
childVC?.view.frame = view.frame
}

Attaching UIButton on top of UIScrollView or UITableView

What is the best approach for attaching a UIButton on top of UIScrollView or UITableView so when the view is scrolled, the button stays in its place.
Here examples below:
UIButton stays in the right bottom corner when the view is scrolled.
google+ app example
yahoo mail app example
I think this should work. Lay Out your button in a view that is outside of the tableviewcontroller. Then drag an outlet to the tableviewcontroller file. Then add it in code. This code would hold it at the top of the screen.
#IBOutlet var buttonView: UIView!
override func viewDidLayoutSubviews() {
self.view.addSubview(buttonView)
}
override func scrollViewDidScroll(scrollView: UIScrollView) {
var rect = self.buttonView.frame
rect.origin.y = max(0,scrollView.contentOffset.y + scrollView.contentInset.top)
self.buttonView.frame = rect
}
Thank you all for great answers!
I got it worked through storyboard by moving the button from scrollView to View itself. That way it's attached on UIView and it's independent of scrollview.
storyboard snapshot
So now the structure is:
- View
- ScrollView
- Button
Before it was:
- View
- ScrollView
- Button
There are many ways to go about doing this but two that I use most often are as follows.
One approach is embedding the view controller within a navigation controller. This will set a bar on the top and bottom if you choose that you can place bar button items upon.
Another approach is to place a UIView along the top and snap the constraints to the left, right, and top with 0 no-margin. Then set the height. I usually use 40px for the height but you can use what is applicable to your needs. After that you can place a button in that UIView and then set constraints on it to keep in in place.
In my experience, this isn't reliably possible to do with the scrollView itself.
My solution is usually to put anything that needs to float above the tableView/scrollView in a plain ViewController that also contains the tableView/scrollView parent.
If you're using storyboards with a UITableViewController scene, this will likely mean you need to use another scene with UIViewController with a container that has your UITableViewController.
For UITableView use tableHeaderView. For UIScrollView you need to create a separate view not in the scroll view's hierarchy.
Another solution is to put your UIButton in a UIToolbar, and then make the toolbar a child of the UINavigationController's view. After that, in viewDidLayoutSubviews, you can set the rect of the toolbar to sit just below the navigation bar and offset the top of the UIScrollView or UITableView.
Add button which you want in the storyboard.
Design your scrollview
self.view.sendSubviewToBack(scrollViewObj)(in the code)
This worked for me.

How do I adjust a UIRefreshControl's position in my view hierarchy?

I have a custom UIRefreshControl "pull to refresh" and for some reason, when I start to scroll, the view appears above all other views, instead of gradually showing itself as the scroll gets dragged down.. this is what I mean:
Now I've attempted to patch this up by making the background and tint colors clear in the viewDidLoad:
var refreshControl: UIRefreshControl!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
refreshControl = UIRefreshControl()
refreshControl.backgroundColor = UIColor.clearColor()
refreshControl.tintColor = UIColor.clearColor()
collectionView?.addSubview(refreshControl)
}
While this does fix the issue of the refresh just being plastered over everything, regardless of its transparency, the refreshControl is still on top of my view hierarchy, you can see when I release the scroll, the letters are still hanging over the view.. And while it does hide the view, when you begin to drag the scroll, it glitches really fast showing the view again:
Now I've even tried calling the sendSubviewToBack and insertSubview:aboveSubview: methods but they don't do anything.. Keep in mind this is a collectionViewController and not a UIViewController with a collectionView on top, so I guess there isn't a view behind the top view which i can send something to the back.. but is there any logic i can implement that will adjust the views bounds when the scrolling begins?
Try this:
refreshControl.layer.zPosition = -1
Also, be careful about using UIRefreshControl without attaching it to an actual UITableViewController. You may see odd artifacts like stuttering (even attaching it to just a UITableView will cause errors). See:
UIRefreshControl without UITableViewController

UIScrollView with UIView (Swift)

I have implemented a UIScrollView with a UIView which I add when viewDidLoad() to the UIScrollView which is set to the UIViewControllers view. When I do this how ever the frame of the UIView with the setTranslatesAutoresizingMaskIntoConstraints(false) gets set to -101.0. This does not happen to another view that is displayed differently,but only happens to this view which is designed the same, and displayed with pushViewController from the navigationController.
The constraints are setup from the NIB/XIB files and I am confused why this is occurring.
Another thing to note is that, when this happens, no matter where I try and change the frame of the UIView, it has no affect.
EDIT:
CODE for viewDidLoad():
override func viewDidLoad(){
// call the super implementation
super.viewDidLoad();
// load our scrollview from our nib file
customScrollView = CustomScrollView.loadFromNib();
// set the resizeing mask to fill screen
customScrollView!.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
// load our uiview from our nib file
containerView = ContainerView.loadFromNib();
// we handle the constraint changes
containerView!.setTranslatesAutoresizingMaskIntoConstraints(false);
customScrollView!.addSubview(containerView!);
// intialize our refresh control
refreshControl = UIRefreshControl();
refreshControl!.tintColor = UIColor.whiteColor();
refreshControl!.addTarget(self, action: "onRefresh", forControlEvents: UIControlEvents.ValueChanged);
containerView!.addSubview(refreshControl!);
// add the view to our controller here
view = customScrollView!;
}
The answer ended up being a custom tableview. If anyone else is having this problem, I highly recommend ditching UIScrollView, because it is an utter disappointment from apple. The documentation is poor, and there are technical issues with it known to be true. There are also technical document notes for some issues on the class for anyone who is trying to do something with the class, be sure to read those.

Can't place UIImageView behind UITableView in storyboard

I can't seem to position a UIImageView behind a UITableView on my Table View Controller. I'm trying to do this within the storyboard designer. Moving a UIImageView onto the View Controller just stacks the imageview onto the tableview. In previous versions of XCode I had a window that allowed me to change the stack order of views within a view controller. Is this still possible?? I've tried dragging the views around in the jump bar and this doesn't work. So how do I accomplish this using XCode 5?
Thanks!
Use UIViewController for parent of UITableView!
Or if you want to set Background of tableView, can use this code
self.tableView.backgroundView = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"bg"]];
UITableView has a backgroundView property. You will need to set it in code.
In your example, you're probably using a UITableViewController in your storyboard. This means that the root view is a UITableView and you can't add a UIImageView as a subview to a UITableView and put it behind the superview. Doesn't make sense.
In a previous version that you've made, I suspect that you had a UIViewController with a UIView root view, which you added a UIImageView subview and a UITableView subview on top of that.
Every UIViewController is associated with a UIView, i.e. [viewController view]. In the case of UITableView, [viewController view] is of type UITableView, so when you add subviews to it, you're adding to the UITableView, not a superview of type UIView as you seem to expect.
I would recommend using a UIViewController to control that view, adding subviews of types UIImageView and UITableView.

Resources