iOS prevent subview of tableview from scrolling with tableview - ios

I have added a subview to my tableview and when ever the user scrolls the tableview, the subview scrolls with it. How do I prevent this? I know it's probably along the lines of not adding the view to the tableview's subviews, but I have no knowledge of any other ways to do this. Thanks.

If you want to make a view a subview of the table view, then you can make it floating (non-scrolling) by changing its origin.y value in the scrollViewDidScroll method.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
self.iv.frame = CGRectMake(self.ivOrigin.x, self.ivOrigin.y + self.tableView.bounds.origin.y, self.iv.frame.size.width, self.iv.frame.size.height);
}
In this example, "iv" is a property for an image view, and "ivOrigin" is a property for the initial origin of the image view (defined when I created the image view and its frame in viewDidLoad).

The UITableView is built and intended to be a view of things that scroll.
So, you can either fight that, which as you're discovering is quite hard since everything about the component is built and focused around scrolling and fast display of a subset of the full list data... Or, you can not fight it and put your static item on top of the table as a fixed-position item.
If there's a reason you can't add the table view and your animate-out item in your main view, you can always add a custom UIView class that contains both the table view and your animated view. Have your custom view class expose the contained table view as a .table property, and the container you're putting things in can be tweaked to use "mycontainerObject.tableview" instead of just "tableview" where needed.
Yes, it's a little more work to write the custom UIView subclass and give it a couple properties to hold the UITableView and whatever UIView you're animating out.. but it's likely a lot safer in the long run than trying to "hack" into the UITableView's methods and view hierarchy to try to give it a "fixed in place" behavior.

Related

Button not responding in Table View Cell [duplicate]

This question already has answers here:
Programmatically send to front/back elements created from interface builder
(2 answers)
Closed 10 days ago.
I am using a .xib for my cell in a table view. Inside the .xib, is another view (cellBackgroundView), and a button. When I run the app, and click the button, it does not respond at all. Instead, it calls the tableView's didSelectedRowAtIndexPath method which brings another view controller.
Using Xcode's Debug View Hierarchy, I discovered that I have a view overlaying the all the buttons (see pic attached: this overlaying view is highlighted). This view (called backgroundView) that is overlaying my button is a View, within a view. I have a feeling when you place a view in a view, and put a button in the initial view, the button isn't called because its below the view hierarchy.
How do I fix this issue? Is there a way to move background view to the back of the view heirarchy so that the buttons will be responsive?
Debug View hierarchy:
Structure of .xib
Two things that you could check
1) Do you have a delegate method for cell height and is the height returned correct? Unless you have Clip Subviews on for the UITableViewCell, the contents of the cell can be visible outside it's frame, but the parts that are outside the cell's frame are not registering user interactions.
2) Is some other view element higher in the hierarchy (lower in the XCode listing you posted) overlapping the button? iOS Simulators Debug -> Color Blended Layers can help spotting this.
Edit:
If I interpret the added screenshots correctly, you probably have the issue mentioned in the option 1) above. If the other elements showing in the screenshot are those listed as subviews of the Cell Background View they are mostly outside the parent view's frame and thus don't receive touch events. If the background view's frame is correct, then you might want to move the other elements as children for Feed Cell directly.
Also, the element listing suggests that you are using plain UIView as the parent element. I don't know the inner workings of your application, but if you only use this view in a UITableViewCell you might want to consider making the parent view a Table View Cell in the xib. This will reduce some bloat and allow you to configure some properties for the cell in the xib.
Maybe you forgot assign your Button to code
I assume Feed Cell is a subclass of UITableViewCell, and cellBackgroundView is the property contentView of this cell.
If so, the cells property backgroundView should be behind your cellBackgroundView (the docs say: UITableViewCell adds the background view as a subview behind all other views and uses its current frame location.).
You could set the cells property backgroundView = nil, and see whether it is still there in the view hierarchy. If so, you do add a custom backgroundView on top of the other cells views somewhere.
To check this, you could read out the subview hierarchy of your cell in your method tableView:cellForRowAtIndexPath: with something like NSArray *svs = cell.subviews; (assuming cell is the tableViewCell) and set a breakpoint behind this statement.
svs usually contains first the UITableViewCellContentView, and above it the _UITableViewCellSeparatorView. The cells backGroundView will not be shown. You could check there your view hierarchy.
If by chance there is a custom backgroundView on top, you could - as a workaround, not a solution - bring the contentView to the front by sending to the cell bringSubviewToFront: with the contentView as argument. Then the button should respond.
In your Structure of Xib Place your button below the view that is first the view is added to superView then the Button, then your button will work.
or you can code
-(void)viewDidLayoutSubviews{
[self.view insertSubview:yourButton aboveSubview:cellBackgroundView];
}
Hope it will help.
Do you add an UIButton by code?
If so you should ensure you addSubview: into cell.contentView and not into cell.
Also you could try to apply CellBackground class to a view inside contentView, not directly to contentView.
you can use this method.
[cell.contentView bringSubviewToFront:yourButton];
after that if you want to back in background then tou can use sendSubviewToBack: method .
After adding this methods your button is not responding set the userIntractionEable of button's superview.

Adding a Scrolling Subview to a UITableView (NOT a Cell)

I'm creating my views programmatically. I have a UITableView in my UIViewController subclass that I want to add a scrolling subview to that is not a cell. I want to add some text-based subview to the UITableView that scrolls with the table and starts out above y=0 so the user will only see it if he pushes the table down. That is, it should reside above the first section of my table. If it helps for visualization, I intend to make something similar to those "scroll down to refresh" features and want some indication to the user that scrolling down causes a refresh. Is there any way to do this without something messy like using another UITableViewCell to represent it or abusing the UITableView delegate methods to move a view around whenever the user scrolls?
Simply using [tableView addSubview:] in my viewWillLoad only makes it appear for a split-second then disappear once the table data is loaded. This seems weird to me because UITableView is a subclass of UIScrollView, which is meant to hold other views in it. Using [tableView.backgroundView addSubview] does nothing.
P.S. Why not use a UIRefreshControl for this? I'm still undecided but leaning towards not using one because I don't like how slow that spinning wheel "feels" when the refreshes are usually very very quick. I've been looking at other options like flashing the background subtly and only showing a wheel if it's taking a longer time than usual.
I You can implement pull to refresh with only a table view
To do this using the scroll view delegate, since tableview is a subclass of scroll view.
Set view controller to be the tableview delegate and implement
(void)scrollViewDidScroll:(UIScrollView *)scrollView
When scrollview content offset y value passed a point, add a label to the viewcontroller.view not tableview. When you scroll back or release, remove the view.
You might also be able to add label to the table view and set the frame origin to negative y value, so when you pull the label will move into view (Never tested this do might not work)

What's the best way to build a very flexible/dynamic "header" in UICollectionView

I need to build a UICollectionView with a UICollectionViewFlowLayout and a very dynamic "header" (for clarity, I'll call it "view A" to avoid mixing it with a true collection view header) but I'm not sure about what can be the best way to do that: collectionViewCell, header or supplementary view?
What I mean by flexible, the bullet point being ordered by decreasing importance:
View A will contain buttons and subviews that need to detect gestures so I must be able to detect actions on subviews of view A.
I need to be able to reload data on the collection view without reloading view A.
I need to be able to update the layout of subviews of view A whenever I want (on viewDidScroll of the collection view delegate for example, update according to contentOffset changes).
If possible, I'd like to be able to change the frame of view A dynamically (I mean without having to invalidate the layout). I would like view A to be sticky at the top and shrink while scrolling until it disappear. Have a look at recently launched "Secret" app to see what I mean (done on UITableView for them). Though I could just scroll without changing the frame and cheat by changing the layout of subviews (see point 3) in order to give the sensation of a sticky header.
What do you think is the best component to do that? Can I use a UICollectionViewCell, a header or a supplementary view? If so which one? If not, do you think of an alternative way I could use to have the same behavior (transparent header and view A behind the collection view? adding view A somewhere else, where, in the view hierarchy?).
Thanks for your help!
Take a look at the UICollectionReusableView class.
You can register your nib on the CollectionView as "SupplementaryView" (registerNib:forSupplementaryViewOfKind:withReuseIdentifier:, use the UICollectionElementKindSectionHeader kind of view)
then you have to implement the collectionView:viewForSupplementaryElementOfKind:atIndexPath: method in your delegate and make sure to return something for the UICollectionElementKindSectionHeader kind.
and finally you have to implement the collectionView:layout:referenceSizeForHeaderInSection: method of your UICollectionViewDelegateFlowLayout to set the size of your header.
Let me know if it help.

How would I create an "About" page like this for my app? How do I have a UITableView (grouped) under a UIView?

Take this about page for Things:
I'm having trouble creating something similar. I just want a UITableView under a UIView with a UIImageView and a UILabel in it.
If I use a UIViewController and so I can position the UITableView downward, I get this error: "Static table views are only valid when embedded in UITableViewController instances."
If I use a UITableViewController with a grouped style and use contentInset on self.tableView to move it down ([self.tableView setContentInset:UIEdgeInsetsMake(150,0,0,0)];) I can't figure out how to place a view above it. If I try to attach anything to self.view it crashes (obviously). Same happens if I attach anything to self.tableView.
I then tried making the UIView the header of my UITableView section (I only need one section) but I can't get it to move up enough. It just sits inside the UITableView almost.
How do I have a UITableView (grouped style) exist with a UIView above it?
This can be achieved easily using the tableHeaderView property of UITableView. If you are using Interface Builder (which it looks like you are), then you can just drag a UIView above the table view and it will be set as the table's header view. All you need is a UITableViewController; no need for UIViewController and manually laying it out.
That's because the view probably isn't placed on top of the table but rather within the table's section 0 header. Or, even more likely, the view in question is just a regular UITableViewCell with a 0 alpha background.
Either of these options would allow the top view to be scrolled out of frame as the user scrolls under every condition.
I recommend [MDAboutController] (https://github.com/mochidev/MDAboutController)
It's easy to integrate and you don't have to waste any time configuring the UITableView.

UITableViewController or UIViewController when adding additional controls

I have a number of views that include tableviews, but other controls as well. Up till now I have been subclassing UIViewController and manually adding a tableview to it (with my other controls above/below it). Not too much hassle, other than having to manually handle the scrolling, and sometimes some resizing (if the table's content is dynamic).
I only just found that the tableHeaderView and tableFooterView of a UITableView can pretty much handle anything you throw at them. I guess I skimmed them previously, thinking they were related to section headers/footers when they are of course not related at all.
So with that in mind, and before I convert a bunch of classes over to subclass UITableViewController instead of UIViewController, is this standard practice? If I have a view, for example, that is mostly non-table content but with a dynamic tableview half way down, is it a good idea simply to use a UITableViewController and put everything around it in the header/footer?
The table view header and footer are scrolled with the table view's content. If you need them to always be visible, your current approach is the best. If you don't mind the header views being scrolled, you can indeed refactor your app.
A UIViewController manages a view hierarchy. If your view contains significant non-UITableView content, I would manage the view hierarchy with aUIViewController and include the UITableView as a subview in the view controller's view property.

Resources