How do you ensure a UIView to be frontmost? - iphone

I have UILabels animating on my mainView and I want to have a custom UIView pop onto the main view when a button is pressed. The labels animating in the background continue to animate and the problem that I'm having is that the labels animate on top of my custom UIView.
Does anyone know how I can ensure that my custom UIView is the front-most view so that the UILabels animate behind it?

You may want to look at
- (void)bringSubviewToFront:(UIView *)view
in the parent view.

#implementation UIView (moveToFront)
- (void) moveToFront { [[self superview] bringSubviewToFront:self]; }
#end

Related

Touch event handling with MaskToBounds NO

I was trying to implement a container view controller design into my app. However I was told that I need to support iOS 4.3 devices, so the official view controller API introduced in iOS 5 is not an option at the moment.
In order to achieve a similar behaviour I used a hack. Resized the view for my RootViewController and the added a subview to it that it's outside the view's bounds. For example: RootView has bounds 0,0,320,480. Now I resized it to 0,0,320,430 and included a subview at 0,430,320,60. This works since I do all calculations using the ApplicationFrame giving me stable frames on which to work. But the problem I'm facing right now is that the subview which is out of the bounds of the view is not receiving touch events. The maskToBounds = NO property helps me with the display. But touches? Anybody know how to do that?
Whenever you want the subview to receive touch events in such cases, you can do the following:
1- Create a new class that inherits from UIView and override hitTest:withEvent: to allow subviews to intercept touches:
#interface CustomView : UIView
#end
#implementation CustomView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
/// Check if the point is inside the subview
CGPoint newPoint = [subview convertPoint:point fromView:self];
if ([subview pointInside:newPoint withEvent:event]) {
/// Let the subview decide the return value
return [subview hitTest:newPoint withEvent:event];
}
/// Default route
return [super hitTest:point withEvent:event];
}
#end
2- Change the class of root view to our CustomView (from the right panel in Xcode > Identity Inspector > Custom Class).
And we're done!

TouchesBegan not triggered in UIView as subview of UITableViewCell

I'm creating a custom dropdown menu inside a cell of a UITableView adding this menu as a subview of the cell content view.
When I click on the menu inside the cell I enlarge the view to show all the menu items: now the menu view is over the tableView and all cells.
So, when I select on of the items inside my custom view, the TouchesBegan it's triggered only in the part of the view that's over the UITableView cell in which I call the menu and not in all the view that I enlarged.
If I touch the view in part that is over another cell, the TouchesBegan it's triggered in the cell of the table view and not in the view on top of all cells.
Any suggestion?
Views typically don't respond to touch events on views or portions of views drawn outside its bounds. There are a few possible options to fix the issue:
Enlarge the cell when the dropdown menu is visible to fit the entire menu, but this might negatively impact the visual effect depending on your design.
Add the menu on the controller instead of the cell view. If you got this route, you can use the UIScrollViewDelegate events from the table view to reposition the menu as the user scrolls the table. Remember to account for the case where the menu is displayed on the last cell and might overdraw the controller's bounds if always drawn in downward direction.
Override hitTest:withEvent: and pointInside:withEvent on both your menu view and its superview to inform the OS that you respond to events even outside its normal bounds.
The following worked for me:
Subclass your cell and connect the root view of your layout with the cell:
#interface CustomCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIView *rootView;
#end
Override hitTest of the cell like this:
#implementation CustomCell
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
BOOL res = [self.rootView pointInside:point withEvent:event];
if(res){
return [self.rootView hitTest:point withEvent:event];
}
return [super hitTest:point withEvent:event];
}
#end
Now touchesBegin/Move/End/Cancel will be delivered to the view and it's hierarchy whenever touch is inside that view

UITableViewController - limit the scrolling

I have a UITableViewController which contains a View and a Table View Section.
View contains a label that indicates the title of the table.
My problem is that the scroll includes the View. What I want is to keep View static (exclude from scrolling) and to scroll only Table. (I use static cells)
Thanks.
The hierarchy of a UITableViewController is
- UIView
-- UIScrollView
---- UITableView
Initially you're in the UITableView when modifying items, so you'll want to add the portion that you do not want to scroll to the UIView (outside of our scrollView). So you'll need to call super a couple times like this:
[self.superview.superview.view addSubview:viewThatDoesNotScroll];
Since UITableView is a subclass of UIScrollView:
- (void)viewDidLoad {
[super viewDidLoad];
// mySubview is an instance variable, declared in .h file
[self.tableView addSubview:mySubview];
// here goes the rest of your code
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if(scrollView == self.tableView) {
mySubview.frame = CGRectMake(mySubview.frame.origin.x, scrollView.contentOffset.y, mySubview.frame.size.width, mySubview.frame.size.height);
}
}
The code was taken from WWDC '10 or '11 (I don't remember), so I'm sure it's the most appropriate way to do it.
Explanation: In -viewDidLoad you create your view and add it as a subview of your tableView. You can do it in -loadView or -init - it doesn't matter. The most important lines are in the -scrollViewDidScroll: method. This method is called whenever user drags the scrollView, so you can simply set the origin.y of your subview to contentOffset.y of the scrollView.
Do not UITableViewController. Use UIViewController and manage the views outside of the UITableView object. If you need, you can also implement UIViewControllerContainment to manage different views and different view controllers inside your custom view controller.

put subviews of a UIView in front of its CALayer?

Is this possible? Basically, I want to give my UIView a subview, and have that subview be in front of the view's layer (more specifically, in front of said layer's border).
Of course I could achieve the effect I want by making two subviews of the view's superview, one on top of the other. But I'd rather avoid that if possible.
I looked for this for a while myself; i don't believe it is possible. I solved the issue by, as you hint at, adding the subview and the parent to the same 'container' superview. Then its just a matter of ordering the two subviews, so that your subview is above the other and its border.
I solved this with a segue animation where i needed the sourceViewController to be in front of the destinationViewController. I had to remove the sourceViewController in order to re-nest it. My code looks like this:
- (void) perform {
UIViewController *sourceViewController = (UIViewController *) self.sourceViewController;
UIViewController *destinationViewController = (UIViewController *) self.destinationViewController;
UIView *parent = sourceViewController.view.superview;
[sourceViewController.view removeFromSuperview];
[parent addSubview: destinationViewController.view];
[parent addSubview:sourceViewController.view];
// Perform animation stuffs...
}

Pass a tap from UIScrollView to its parent view

I have a custom UITableViewCell that has a UIScrollView in it that covers the entire cell. I want to be able to use the scroll view to scroll a label in the cell (which is working) but the scroll view seems to be 'stealing' the cell's tap event. So I was wondering:
How do you pass a touch event from a UIScrollView to its parent UITableViewCell?
In the UISCrollViewController, have you tried passing the touchesEnded on to super, assuming a scroll is not in progress?
- (void)touchesEnded:(NSSet *)aTouches withEvent:(UIEvent *)anEvent
{
if(![self isDragging])
{
[super touchesEnded:aTouches withEvent:anEvent];
}
}