UIView Positioning for iPhone: Any concept of "Z-Index"? - iphone

I know if I want to add a black background to a UIImageView, I can create an UIImageView that is a bit smaller than the UIView it's contained in. If I do this, the UIImageView is positioned on top of the black background.
Just hypothetically speaking, suppose I want the black background UIView on TOP of the UIImageView (so that it covers the image), how do I do this? Is there a concept of a z-index?
Here's my code to add a black background to an image:
UIView *blackBG = [[UIView alloc] initWithFrame:CGRectMake(0,0,100,100)];
blackBG.backgroundColor = [UIColor blackColor];
UIImageView *myPicture = [[UIImageView alloc] initWithImage:
[UIImage imageNamed: #"myPicture.jpg"]];
int borderWidth = 10;
myPicture.frame = CGRectMake(borderWidth,
borderWidth,
blackBG.frame.size.width-borderWidth*2,
blackBG.frame.size.height-borderWidth*2)];
[blackBG addSubview: myPicture];

Subviews are layered, you can send a subview to the back with...
[myView sendSubviewToBack:mySubView];
or bringSubviewToFront etc.
You can also do one of these...
[myView insertSubview:mySubview atIndex:0]; //Places it at the bottom
[myView insertSubview:mySubview belowSubview:anotherSubview]; //Places it below anotherSubview
As soon as you add a view as a subview to another view however, the parent view is the bottom of the stack. You can play around with CALayer z orders but you are bypassing the general approach of views and subviews.
Create a single view as a parent for both the bg view and the imageview, then you can order them how you like.
UPDATE: I have a UIView+Layout category which has nice [subview sendToBack]; and [subview bringToFront]; which you may find useful.... article here

Related

Do I have to create view to draw rectagle?

I have MyViewController class which is subclass of UIViewController.
I want to draw filled rectagle on it's view.
Do I have to create a new view, set it's background color and addSubview?
What is the simplest way?
If you want a custom sized rectangle... yea pretty much what you described is the easiest.
UIView *rect = [[[UIView alloc] initWithFrame:CGRectMake(10,30,100,100)] autorelease];
[rect setBackgroundColor:[UIColor redColor]];
[[myViewController view] addSubview:rect];
Other possibilities exist though. You can go down into drawing stuff with like Quartz2D and what not. You could also make it so that when you draw the rect of the view, you draw a custom rectangle.
If you just want the entire view's background color set to a color:
[[myViewController view] setBackgroundColor:[UIColor redColor]];

disable elements on UIView behind modal UIView

i have a UIView that is smaller than the superview so i can represent this view as a modal view when a button is clicked.
I have managed to do the following:
* add a subview to the superview.
* centered this modal view
I am now trying to make the elements behind the UIView unclickable. And also add a grey shadow te the ourside of my modal view so that the user understands that the modal view is the view in focus.
I would like to know how to achieve this.
I do not wish to use the presentation modal transition. I know and have already implemented this in other projects.
Any help is appreciated.
The simplest thing would be to lay a fullscreen UIView with a translucent gray background behind your "modal" view. Then it will intercept all of the touches. It might look something like this:
UIView *dimBackgroundView = [[UIView alloc] initWithFrame:theSuperview.bounds];
dimBackgroundView.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:.5f];
[theSuperview addSubview:dimBackgroundView];
[theSuperview addSubview:modalView];
For future reference, you can set myView.userInteractionEnabled = NO to disable touch events on a view.
There are several ways to do it.
If you have a custom view which has custom location, you can modify it like that:
Create an instance var:
UIView* backgroundView;
And whenever you need it, put it behind your custom view:
if (backgroundView == nil)
backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width)];
backgroundView.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:.5f];
[self.view addSubview:backgroundView];
[backgroundView animateBump:customView.view];
[backgroundView addSubview:customView.view];
When you do not need it anymore
[backgroundView removeFromSuperview];

selectedBackgroundView on UITableViewCell gets applied to all views in cell

I have a table cell being displayed that shows a users image, name and some text. The user's image is 50x50, but I want a border around it so I set the view to center the image and set the frame to 52x52 and then set the background color of that view to my border color. That shows a 1 pixel border around the image.
I also want to show a 30 pixel wide border on the right of the cell when the cell is selected. I've tried to do that by creating a UIView the size of the cell's frame, then adding a subview to that view with a UIView the width and background color I would like. I then set that view to the selectedBackgroundView of the cell.
The problem here is that the cell's selectedBackgroundView gets applied to the background of all views inside the cell. So when I select a cell, the images "border" gets set to the cell's selected background color, the other 30px "border" I'm adding gets changed to that background color also.
Code inside my cellForRowAtIndexPath:
cell = (UserCellView *) currentObject;
UIView *c = [[UIView alloc ] initWithFrame:CGRectMake(0, 0, 30, cell.frame.size.height)];
c.backgroundColor = [[UIColor alloc] initWithRed:64/255.0 green:64/255.0 blue:64/255.0 alpha:1.0];
UIView *v = [[UIView alloc ] initWithFrame:cell.frame];
v.backgroundColor = [[UIColor alloc] initWithRed:35/255.0 green:35/255.0 blue:35/255.0 alpha:1.0];
[v addSubview:c];
cell.selectedBackgroundView = v;
[c release];
[v release];
I'll assume that you haven't actually tested what's going on to form your analysis that it "gets applied to the background of all views inside the cell".
I did something like this:
#interface TestView : UIView {
}
#end
#implementation TestView
-(void)setBackgroundColor:(UIColor*)c {
// Breakpoint here.
NSLog("setBackgroundColor: %#",c);
[super setBackgroundColor:c];
}
#end
...
UIView * v = [[[UIView alloc] initWithFrame:(CGRect){{0,0},{20,20}}] autorelease];
v.backgroundColor = [UIColor magentaColor];
UIView * v2 = [[[TestView alloc] initWithFrame:(CGRect){{5,5},{10,10}}] autorelease];
v2.backgroundColor = [UIColor yellowColor];
[v addSubview:v2];
cell.selectedBackgroundView = v;
The end result is that -setBackgroundColor: is called from -[UITableViewCell _setOpaque:forSubview:] when the view is selected, with something like UIDeviceWhiteColorSpace 0 0 (i.e. [UIColor clearColor]).
Or, in other words, the background colour of some of the subviews are set to [UIColor clearColor] while the cell is selected, allowing selectedBackgroundView to show through. I think this happens because a common optimization is to give textLabel/detailTextLabel the table's background colour (e.g. white) so it draws faster, but this means the background colour has to be reset when the cell is selected.
The easiest fix is to use an image instead: a 1-by-1-pixel image of the correct colour in a UIImageView will work, if a bit messy. (I had this problem when drawing custom separator lines with 1-pixel-high UIViews, so I just included the separator into the background image.)
An alternative fix is to use a CALayer instead: Add a 52x52 sublayer to the UIImageView's layer, and set the sublayer's background colour. I'm pretty sure UITableViewCell simply walks the view hierarchy, so it should ignore custom layers. (The big disadvantage with layers is that they don't auto-size, which made them unsuitable for my purposes, and means the 30px right border won't auto-size.)
A workaround is to subclass the relevant views and ignore -setBackgroundColor: if it's equal to [UIColor clearColor].
A simple but obnoxious-to-maintain solution is to override setSelected:animated: and setHighlighted:animated: with implementations re-setting the various backgrounds you want. Something along the lines of:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
self.childView.backgroundColor = [UIColor blueColor]; // whichever you want
}
First add this to your file
#import <QuartzCore/QuartzCore.h>
Then turn your view into an image with...
UIView *rowView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 1.0, 60.0)];
rowView.backgroundColor = [UIColor colorWithRed:35/255.0 green:35/255.0 blue:35/255.0 alpha:1.0];
UIGraphicsBeginImageContext(rowView.bounds.size);
[rowView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *yourImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Then instead of adding a UIView to your cell, just add a UIImageView with "yourImage".
A simple solution if the affected view can be a custom subclass is to override -setBackgroundColor:
- (void)setBackgroundColor:(UIColor *)color
{
// Ignore requests and do nothing
}
Thus UITableViewCell's attempt to set the colour will go ignored. Code in the custom view which really does want to set the background colour needs to call super:
- (void)setColor:(UIColor *)color
{
[super setBackgroundColor:color];
}
(or could probably message the underlying CALayer directly)
you will need to customize the contentView of the cells and handle the delegate tableView:cellForRowAtIndexPath
See Posting Here

Why are there left/right gaps when I add an image to my navigationBar?

UIImageView *navBarImageView = [[UIImageView alloc] initWithImage:navBarImage];
[navBarImageView setFrame:CGRectMake(0, 0, 320, 44)];
self.navigationItem.titleView = navBarImageView;
[navBarImageView release];
I am trying to add an image to my navigationBar, but when I used the code as listed above, it places the image into the navigationBar but leaves a grey gap to the left and right of the image. The image was created at 320x44, I'm not sure why it is resizing it despite the fact that I am setting the frame.
That's... probably not how you want to do that—it's not what the titleView is for. The usual way to do a custom navigation-bar background is to create a category on UINavigationBar, like so:
#implementation UINavigationBar(MyCustomBackground)
- (void)drawRect:(CGRect)r
{
[[UIImage imageNamed:#"my-navigation-background.png"] drawInRect:self.bounds];
}
#end
Throw that in a .m file in your project and you should see all of your navigation bars use "my-navigation-background.png" as their background.

UIButtons over a UIImageView Zooming

I am pretty new to iphone programming. I just started about a month ago and have only been tinkering with small tutorial type applications but anyways, here is my question.
I currently have a UIScrollView thats scrollable and zoomable, that loads a UIImageView subview, and i want to add in some controls(UIButtons) over the image view but when i zoom in and out the whole group(the buttons and the image) zoom togeather.
If I add the UIButtons to my UIScrollView and zoom, the image zooms and the buttons stay in origional place
If I add the UIButtons to my UIImageView they zoom correctly but arent buttons anymore. IE they lose their interactivity.
Later ill add lots of buttons into an array and add them.
I would appreciate any help i can get
This is part of my mainViewController.m:
- (void)viewDidLoad
{
[scrollView2 setBackgroundColor:[UIColor blackColor]];
[scrollView2 setCanCancelContentTouches:NO];
scrollView2.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView2.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scroll2ImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"bigNH.jpg"]];
[scrollView2 addSubview:scroll2ImageView];
[scrollView2 setContentSize:CGSizeMake(scroll2ImageView.frame.size.width, scroll2ImageView.frame.size.height)];
scrollView2.minimumZoomScale = .5;
scrollView2.maximumZoomScale = 3;
scrollView2.delegate = self;
[scrollView2 setScrollEnabled:YES];
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect newSize = CGRectMake(658, 435, 50, 50); // position in the parent view and set the size of the button
myButton.frame = newSize;
[myButton setImage:[UIImage imageNamed:#"redStop.png"] forState:UIControlStateNormal];
// add targets and actions
[myButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
// add to a view
[scroll2ImageView addSubview:myButton];
[redLineArray addObject:myButton];
[scroll2ImageView release];
}
This might not help and it is not what it appears that you want to do.
However, when I want buttons associated with a scrollview, I add a parent view, add the buttons to that view and also add the scrollview to that view. The button(s) and the scrollview would be siblings. This allows the user to scroll around the contents of the scrollview, while insuring that the buttons are always in view.
-isdi-
By default, UIImageView has userInteraction disabled. Have you changed this?
Also, I would be really uneasy adding subviews to an UIImageView, it's really meant to hold one image. It would be better to create a normal UIView and add the UIButtons and UIImageView to that. It's very easy to control the ordering so that the buttons appears on top of the image.
P.S. Just to make your life easier, instead of :
[scrollView2 setContentSize:CGSizeMake(scroll2ImageView.frame.size.width, scroll2ImageView.frame.size.height)];
You can use :
[scrollView2 setContentSize:scroll2ImageView.frame.size];
Make a single view to contain all your zoomable content (everything it would appear), and call it say contentView. Now place everything you want in that contentView, the imageView and all your buttons etc.
In your UIScrollView delegate place this: (Be sure to set the scrollView's delegate if you haven't already)
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.contentView;
}
Only one view is allowed to zoom, but that one view can however contain other views that will scale because they're child views.
Also be sure to set the scrollView's contentSize value to the exact size of your zoomable contentView.