Objective-C – Positioning of views inside a view - objective-c

Is there a way to add some subviews to a view and then be able to position that view so all the subviews will "follow". Acting as a container so to speak for the subviews so I only need to reposition the view and not having to reposition all the subviews in that view.
I'm looking for a solution to do this programtically, not in IB.

If you use a UIView as a parent view all subviews will follow.
UIView *parentView = [[UIView alloc] initWithFrame:self.view.bounds]
[self.view addSubview:parentView]; // Assuming self is a ViewController
UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn1.frame = CGRectMake(10, 10, 120, 44);
[parentView addSubview:btn1];
// Sets a new position with the same view size
parentView.frame = CGRectMake(50, 100, self.view.bounds.size.width, self.view.bounds.size.height);
Now when you set the new frame of the parentView. The btn1 will have it's position relative to the parentView.
I Hope I understood your question correctly.
EDIT:
Added comments

Related

UIButton is moving up when navigation bar hidden

I am adding the one UIButton in bottom of view -
CGRect frame = [UIScreen mainScreen].applicationFrame;
UIButton *menu_btn = [[UIButton alloc] initWithFrame:CGRectMake(xOffset, frame.size.height - 55, 55, 55)];
[self.view addSubview:menu_btn];
And in the view i have UITableview and i am hiding the uinavigation bar when scrolling down in the list and showing when scrolling up.
menu_btn is moving up and down with the list, I want to fix this button.
Anyone please suggest me,how i can achieve this ?
I added in navigationController.view and its working fine. Thanks guys.
CGRect frame = [UIScreen mainScreen].applicationFrame;
UIButton *menu_btn = [[UIButton alloc] initWithFrame:CGRectMake(xOffset, frame.size.height - 55, 55, 55)];
[self.navigationController.view addSubview:menu_btn];

How to move scrollView down 44x to make room for NavBar

I am using the following code to create my scrollview. I would like to move the scrollView down 44px to make room for my nav bar.
scroll = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
scroll.backgroundColor = [UIColor clearColor];
scroll.delegate = self;
image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Menu.png"]];
scroll.contentSize = image.frame.size;
[scroll addSubview:image];
scroll.minimumZoomScale = scroll.frame.size.width / image.frame.size.width;
scroll.maximumZoomScale = 2.0;
[scroll setZoomScale:scroll.minimumZoomScale];
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTap:)];
[doubleTap setNumberOfTapsRequired:2];
[scroll addGestureRecognizer:doubleTap];
self.view = scroll;
any help is appreciated.
Your code is correct, to manually create a frame do:
scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0,44,320,480)];
:)
This is for iPod and iphone View but this will let the scroll start at 44px
Cant you just add a scroll view in in interface builder as an outlet, place it underneath your nav bar.
Declare scroll view in .h
in .m under ViewDidLoad
[scroll setScrollEnabled:YES];
[scroll setContentSize: CGSizeMake(320, 1000)]; ////or whatever size you want here
You probably want to init it with a different frame... but it depends on where/how this nav bar is being created. If you have a view controller, and these are all subviews of the view controller's view, then you should be creating the objects in viewDidLoad, then just create the nav bar first, using self.view.bounds to obtain the initialization width. I assume you'll want to put UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin as the autoResizingMask here. Then if the scrollview is the rest of the view below the nav bar, you can create the frame for it using
CGRect scrollFrame = CGRectInset(self.view.bounds, 0, navbar.bounds.size.height)
Put an autoresizingMask of UIViewAutoresizingFlexibleWidth | UIViewAutoResizingFlexibleHeight on the scrollview.
If you are creating the views in a different place/way, then some of that might need modification. I was assuming your view is a nav bar at the top, x pixels tall (44 in this case but it doesn't and shouldn't matter in the context of setting the scrollview frame). and then a scrollview that fills the rest of the view.

How to add an NSView to NSWindow in a Cocoa app?

Since the template of an OS X app in Xcode seems to be similar to an empty app template, the following is used to add a view and a button (trying not to use Interface builder for now):
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSView *view = [[NSView alloc] initWithFrame:NSMakeRect(100, 100, 100, 100)];
view.layer.backgroundColor = [[NSColor yellowColor] CGColor];
[self.window.contentView addSubview:view];
NSRect frame = NSMakeRect(10, 40, 90, 40);
NSButton* pushButton = [[NSButton alloc] initWithFrame: frame];
pushButton.bezelStyle = NSRoundedBezelStyle;
[self.window.contentView addSubview:pushButton];
NSLog(#"subviews are %#", [self.window.contentView subviews]);
}
Similar code on iOS should have produced a yellow box and a button, but the code above only produce a button, but the view won't show. Is there something wrong with the code above, and how to make it show the view with a yellow background?
Use setWantsLayer: method of NSView class.
NSView *view = [[NSView alloc] initWithFrame:NSMakeRect(100, 100, 100, 100)];
[view setWantsLayer:YES];
view.layer.backgroundColor = [[NSColor yellowColor] CGColor];
[self.window.contentView addSubview:view];
NSRect frame = NSMakeRect(10, 40, 90, 40);
NSButton* pushButton = [[NSButton alloc] initWithFrame: frame];
pushButton.bezelStyle = NSRoundedBezelStyle;
[self.window.contentView addSubview:pushButton];
NSLog(#"subviews are %#", [self.window.contentView subviews]);
To expand on the suggestion by Kevin Ballard, the classic way to do this is to subclass NSView and override the -drawRect: method. NSRectFill is a very convenient function for filling a rectangle without having to create a bezier path:
- (void)drawRect:(NSRect)rect
{
[[NSColor yellowColor] set];
NSRectFill(rect);
}
NSViews in Cocoa are, by default, not layer-backed. I suspect that if you type
NSLog(#"%#", view.layer);
you will see that it is nil.
In iOS, all views have layers. But on OS X, views don't have layers. In addition, there's 2 "modes" of layer-backed views on OS X. There's what's called a "layer-backed views" and a "layer-hosting view". A layer-backed view uses a CoreAnimation layer to cache drawn data, but you are not allowed to interact with the layer in any way. A layer-hosting view uses a CALayer that you explicitly provide, and you may mess with that layer all you want. However, with a layer-hosting view you may not add any subviews, or use the built-in NSView drawing mechanism. A layer-hosting view must only be used as the root of a CoreAnimation layer hierarchy.
Given all this, you should probably avoid using CoreAnimation at all for your view.
It's possible that an NSBox will do what you want. You can certainly set a fill color there, turn off the border, and set the style to custom. I'm just not 100% certain it will draw as a simple filled rectangle of color. Alternatively you can define your own NSView subclass that draws a color in -drawRect:.

UIGestureRecognizer's sender view not working properly

According to this question, the UIGestureRecognizer has a view property which refers to the view the gesture is attached to. I used this in my code like this:
//Code for the 1st UIScrollView
UIImageView *bookCover = [[UIImageView alloc]initWithFrame:CGRectMake(50, 100, 145, 420)];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc]initWithTarget:self
action:#selector(downloadBookTapped:)];
[bookCover addGestureRecognizer:singleTap];
[bookCover release];
[singleTap release];
//Code for the second UIScrollView
UIImageView *fileCover = [[UIImageView alloc]initWithFrame:CGRectMake(50, 100, 145, 420)];
UITapGestureRecognizer *singleFileTap = [[UITapGestureRecognizer alloc]initWithTarget:self
action:#selector(downloadFileTapped:)];
[fileCover addGestureRecognizer:singleFileTap];
[fileCover release];
[singleFileTap release];
And here is where I user the view property:
- (void)downloadBookTapped:(UITapGestureRecognizer *)sender
{
UIImageView *imgView = (UIImageView *)sender.view;
CGRect rect = [imgView frame];
UIImageView *images = [[UIImageView alloc]initWithFrame:rect];
//rest of code here...
}
- (void)downloadFileTapped:(UITapGestureRecognizer *)sender
{
UIImageView *imgView = (UIImageView *)sender.view;
CGRect rect = [imgView frame];
UIImageView *images = [[UIImageView alloc]initWithFrame:rect];
//rest of code here...
}
The problem here is that I have two scrollView and each scrollview holds multiple books. When I select a book at the 1st scrollView, the images is displayed correctly. But when I select a book inside the 2nd scrollView, the images is displayed incorrectly. Can anyone explain why this happens? Thanks.
---ADDITIONAL INFO---
The two scrollViews have the same width and height. The difference, of course, is there placement. The first scrollView is placed at (0, 0), while the second is at (0, 350). You can imagine the two as "shelves", the first one being the top shelf and the second one being the bottom shelf.
To specify the problem, say that I selected a book inside the second scrollView. The images will then be displayed as if I selected a book in the 1st scrollView. Meaning, the images is displayed in the 1st scrollView instead of the second scrollView.
Because the gestureRecognizer is bound to the first UIImageView and not the second.
[bookCover addGestureRecognizer:singleTap];
Do this for your other UIImageView and you will get the results you want.
I know now what I did wrong! Instead of adding the images as the subview of the scrollViews, I did this:
[self.view addSubView:images];
That's why It keeps appearing on the top side. It should be like this:
[scrollBook addSubview:images];
[scrollFile addSubView:files];

UITableViewCell custom selectedBackgroundView background is transparent

I have the following code that creates a UIView that I assign to my UITableViewCell's selectedBackgroundView property. Everything works as expected, with the exception of the subview's background, which is transparent.
I use the same code to create a custom view that I assign to backgroundView, and that works fine.
What is causing that subview to be transparent for selectedBackgroundView, and how can I avoid that?
- (UIView*) makeSelectedBackgroundView
{
// dimensions only for relative layout
CGRect containerFrame = CGRectMake(0, 0, 320, 40);
UIView* containerView = [[UIView alloc] initWithFrame:containerFrame];
containerView.autoresizesSubviews = YES;
// dimensions only for relative layout
CGRect subframe = CGRectMake(5, 5, 310, 30);
UIView* subview = [[UIView alloc] initWithFrame:subframe];
subview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
subview.backgroundColor = [UIColor redColor];
subview.layer.cornerRadius = 5;
subview.layer.borderWidth = 2;
subview.layer.borderColor = [UIColor greenColor].CGColor;
[containerView addSubview:subview];
return containerView;
}
As we can see from name of ivar selectedBackgroundView, this background shown by cell when it was selected.
I've to reload few methods (– setSelected:animated: and – setHighlighted:animated:) of UITableViewCell subclass to reset background color of subviews back to their values. Look's like UIKit do some magic in this template methods (iterating over all UIView subclasses and set their background to clearColor)
This code might be helpful for you:
UIImageView *cellImageView = [[UIImageView alloc]
initWithFrame:CGRectMake(0,
0,
cell.frame.size.width,
cell.frame.size.height
)];
cellImageView.contentMode = UIViewContentModeScaleAspectFit;
// normal background view
[cellImageView setImage:[UIImage imageNamed:#"*<ImageName>*"]];
[cell addSubview:cellImageView];
[cell sendSubviewToBack:cellImageView];
[cellImageView release], cellImageView = nil;
Here cell is an object of custom UITableViewCell.
Also you can set backgroundColor property.
I would try to set the alpha for both containerView and subView to 1.0
[containerView setAlpha:1.0];
...
[subview setAlpha:1.0];
this should make your controls totally opaque.
You could also create some images for the background and use that images in state of creating 2 views. Let's say you create 2 image (normalBackground.png and selectedBackground.png) and then set this images as cell background. Here is a nice tutorial.
Try setOpaque:YES on your views.
In the end, I ended up subclassing UITableViewCell which contained a custom view object, and that worked.