I'm trying to do the following:
alt text http://img101.imageshack.us/img101/7396/33959221.png
I need to do a lot of custom things, so I subclassed everything.
alt text http://img248.imageshack.us/img248/4201/49422483.png
I'm having issues with autoresize and positioning. For instance the UIToolBar is not at the correct position.
So here is the question:
If you don't use UITableViewController or any other Controller, that takes care of all the positioning and sizing, then you have to do it yourself.
Can someone someone tell me how this works? What do I need to understand?
---- UPDATE:
My custom goals are actually not that important as my question is actually about something else. But OK. So all "elements" like the TableView, the Toolbar and the TabBar will have custom backgrounds and use custom buttons. The TableView will be GroupedStyle and the groups can be collapsed.
My question is how do I have to structure my code especially regarding positioning and autoresizing in order to achieve what you can see in picture #1.
This is how it's structured right now:
Application Delegate:
- (void) loadView {
RootViewController *rootView = [[RootViewController alloc] init];
[window addSubview:rootView.view];
[window makeKeyAndVisible];
RootViewController:
- (void) loadView {
self.theView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
self.theView.autoresizesSubviews = YES;
self.theView.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
self.view = self.theView;
ChildViewController *childView = [[ChildViewController alloc] init];
[self.view addSubview:childView.view];
ChildViewController:
- (void) loadView {
self.theView = [[UIView alloc] init];
self.view = self.theView;
}
- (void) viewDidLoad {
self.view.frame = [[UIScreen mainScreen] bounds];
CGRect toolbarBounds = self.theToolbar.bounds;
CGRect viewBounds = self.view.bounds;
CGRect tableViewBounds = CGRectMake(0, CGRectGetHeight(toolbarBounds), CGRectGetWidth(viewBounds), CGRectGetHeight(viewBounds) - CGRectGetHeight(toolbarBounds));
self.view.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
self.theTableView = [[MyTableView alloc] initWithFrame:tableViewBounds
style:UITableViewStyleGrouped
parent:self];
[self.view addSubview:self.theToolbar];
[self.view addSubview:self.theTableView];
}
MyToolBar:
- (id)initWithParent:(id)theParent {
if ((self = [self init])) {
self.parent = theParent;
CGRect rectArea = CGRectMake(0, 0, CGRectGetWidth([[[self parent] view] bounds]), 44);
[self setFrame:rectArea];
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[self loadButtons];
}
return self;
}
So this is how the positioning is structured at the moment (messy). It actually works, BUT I have a ModalView which is handled by the ChildViewController. When I have the iPad in Portrait view and I pop up the modal view and dismiss it, then everything works. But when I do the same on Landscape view it rotates the hole view... the ChildViewController by 90 degrees when dismissing the modal view. Very strange. When I load directly ChildViewController in my AppDelegate, then again everything works fine.
You're missing the UIViewAutoresizingFlexibleBottomMargin option in the autoresize mask of your toolbar, for instance.
Related
I have one view Controller and one UIView now in my ViewController when i click barButton than second view will apear like popup,now i want to add page controller and scrollview in that second view, my second view is not UIViewController but it is UIView.so how can i do that...
my first view is "ImageViewController" and second view is "PopupView"
in ImageViewController.m
#import "PopupView.h"
#implementation ImageViewController
- (void)viewDidLoad
{
UIBarButtonItem *clipArt = [[UIBarButtonItem alloc] initWithTitle:#"Clip Art"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(popUpView:)];
}
- (void)popUpView:(id)sender {
CGRect * imageFrame = CGRectMake(10, 90, 300, 300);
PopupView *popUpView = [[PopupView alloc] initWithFrame:imageFrame];
[self.view addSubview:popUpView];
}
And in PopupView.m
- (id)initWithFrame:(CGRect)frame
{
if (self) {
CGRect * imageFrame = CGRectMake(0, 0, 300, 300);
self = [super initWithFrame:frame];
UIImageView *starImgView = [[UIImageView alloc] initWithFrame:imageFrame]; //create ImageView
starImgView.alpha =0.8;
starImgView.layer.cornerRadius = 15;
starImgView.layer.masksToBounds = YES;
starImgView.image = [UIImage imageNamed:#"black"];
[self addSubview:starImgView];
self.backgroundColor = [UIColor clearColor];
}
return self;
}
Implement like this in the second view, for scroll view with page control (this example illustrates the scenario for two views):
CGRect scrollViewFrame = CGRectMake(ur dimensions for scroll view);
UIScrollView *myScrollView = [[UIScrollView alloc] initWithFrame:scrollViewFrame];
myScrollView.pagingEnabled = YES;
myScrollView.contentSize = CGSizeMake(scrollViewFrame.size.width * 2, scrollViewFrame.size.height);
//content size is the actual size of the content to be displayed in the scroll view.
//Since, here we want to add two views so multiplied the width by two.
CGRect viewFrame = [myScrollView bounds];
UIView *view1 = [[UIView alloc] initWithFrame:viewFrame];
viewFrame.origin.x = viewFrame.size.width; //setting the offset so that view2 is next to view 1
UIView *view2 = [[UIView alloc] initWithFrame:viewFrame];
//add both the view to scroll view
[myScrollView addSubview:view1];
[myScrollView addSubview:view2];
//add scroll view to parent view
[self addSubview:myScrollView];
You can replace the view1/2 with any visual element. To have scrolling with page control make sure all the view that you want to add to scrollview are so same width/height. That way it work out of the box and you wont have to do anything. Also, its always a good idea to add UIPageControl to the view for giving user some kind of feedback. Its optional though.
One more thing, if you want horizontal scrolling with page control, increase the width as done above. If you want vertical scrolling, increase the height and keep the width same.
I have a question regarding the implementation of loadView:
Right now, I have it like this:
- (void)loadView
{
image = [UIImage imageNamed:#"plan.gif"];
scrollView=[[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
imageView = [[UIImageView alloc] initWithFrame:
CGRectMake(0, 0,scrollView.frame.size.width + 40, scrollView.frame.size.height)];
imageView.image = image;
[imageView setContentMode:UIViewContentModeCenter];
scrollView.contentSize = image.size;
scrollView.maximumZoomScale = 3.0;
scrollView.bounces = NO;
scrollView.delegate = self;
// do any further configuration to the scroll view
// add a view, or views, as a subview of the scroll view.
[scrollView addSubview:imageView];
// release scrollView as self.view retains it
self.view=scrollView;
[scrollView release];
}
I suppose some of it should be in viewDidLoad:?
Thanks in advance.
This seems fine to me.
viewDidLoad is normally used as your hook after getting a view returned from IB. In this case you are essentially just doing the work of IB in code (setting up the view heirachy and configuring it).
Therefore in this case I think splitting out the logic may be superfluous unless it makes your code more readable.
I noticed that Expedia app ( http://a5.mzstatic.com/us/r1000/027/Purple/4c/f4/6c/mzl.wcipbyyg.320x480-75.jpg) has a customized sectionIndex for UITableView on hotels list. (image attached)
I'm figuring that it could be a custom view, maybe with a vertical UISlider but, as I know, UISlider cannot recognize touch events on slides but just dragging ones.
So, how they do that ? A vertical sequence of buttons ? But, in this case, how to recognize dragging events ?
I would like to replicate that control but I need some hints ;)
thanks
There are more ways how to achieve the effect. Assuming you have a self.view initialized from a nib file and it's ordinary UIView, you can put this code into viewDidLoad:
- (void)viewDidLoad
{
CGRect tvFrame = self.view.frame;
tvFrame.origin = CGPointZero;
UITableView* tv = [[UITableView alloc] initWithFrame:self.view.frame];
tv.delegate = self;
tv.dataSource = self;
tv.showsVerticalScrollIndicator = NO;
[self.view addSubview:tv];
CGRect svFrame = CGRectMake(290, 10, 30, 400);
UIScrollView* sv = [[UIScrollView alloc] initWithFrame:svFrame];
sv.contentSize = CGSizeMake(10, 780);
sv.showsVerticalScrollIndicator = NO;
sv.bounces = YES;
CGRect vFrame = CGRectMake(10, 380, 10, 20);
UIView* v = [[UIView alloc] initWithFrame:vFrame];
v.backgroundColor = [UIColor blueColor];
[sv addSubview:v];
[self.view addSubview:sv];
[super viewDidLoad];
}
This will create a table with a narrow scroll view with a blue rectangle over the table. Now you can scroll both scroll views (the table is also a scroll view) independently.
Then you will have to setup delegates and receive scroll events via UIScrollViewDelegate. When one of the scroll views starts dragging, you have to start setting offset of the other scroll view.
I have this very simple code or at least i think it's simple.
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
CGRect rect = CGRectMake(0.0f, 20.0f, 320.0f, 216.0f);
UIPickerView *myPickerView = [[UIPickerView alloc] initWithFrame:rect];
self.view = myPickerView;
[myPickerView release];
}
I am running a general View Based template with XCode. I can see the loadView getting called but i get an black frame instead of the UIPickerView.
What am i doing wrong ?
/donnib
Have you implemented the picker's datasource methods? You need it otherwise it won't show.
Link to Apple Documentation here: http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/Reference/UIPickerViewDataSource_Protocol/Reference/Reference.html#//apple_ref/occ/intf/UIPickerViewDataSource
You've forgotten to set the UIPickerView's delegate to your current view. Add:
myPickerView.delegate = self;
...following your initialization and before your view. And of course, make sure you set up your header file as a UIPickerView delegate and implement the dataSource methods.
Try this:
UIView *contentView = [[UIView alloc] initWithFrame: [[UIScreen mainscreen] bounds]];
UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame: CGRectZero];
CGSize pickerSize = [pickerView sizeThatFits: CGSizeZero];
pickerView.frame = [self pickerFrameWithSize: pickerSize];
[pickerView setShowsSelectionIndicator: YES];
[contentView addSubview: pickerView];
[pickerView release];
[self setView: contentView];
[contentView release];
Instead of overriding -loadView, you should override -viewDidLoad. Once the view has loaded you'll create the picker and add it as a subview of the view owned by the view controller.
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect rect = CGRectMake(0.0f, 20.0f, 320.0f, 216.0f);
UIPickerView *myPickerView = [[UIPickerView alloc] initWithFrame:rect];
[self.view addSubview:myPickerView];
[myPickerView release];
}
I'm having a bit of difficulty trying to build my view. Everything works out great up to the point where I need to insert a UIToolBar into my view. The tableView is placed where I expected it to be placed. The UIToolBar on the other hand, scrolls up and down with the table, it doesn't remain fixed as it should. It also looks rather odd when put on the screen -- I'm guessing because the calculation to place it isn't right? Attached to this question is a screenshot as well as the code I've used to build this. Thanks for your help in spotting out what I'm doing incorrect. Screenshot: http://dl-web.dropbox.com/u/57676/screenshots/broketoolbar.png
The code:
- (void)loadView
{
[super loadView];
// TableViews that wish to utilize tableView footers/headers should override this method.
UITableView *aTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain];
aTableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight);
aTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
aTableView.delegate = self;
aTableView.dataSource = dataSource;
self.tableView = aTableView;
self.view = tableView;
[aTableView release];
UIToolbar *toolbar = [UIToolbar new];
[toolbar setBarStyle:UIBarStyleBlackOpaque];
[toolbar sizeToFit];
CGFloat toolbarHeight = [toolbar frame].size.height;
CGRect mainViewBounds = self.view.bounds;
[toolbar setFrame:CGRectMake(CGRectGetMinX(mainViewBounds),
CGRectGetMinY(mainViewBounds) + CGRectGetHeight(mainViewBounds) - (toolbarHeight * 2.0),
CGRectGetWidth(mainViewBounds),
toolbarHeight)];
[self.view insertSubview:toolbar aboveSubview:self.tableView];
[toolbar release];
}
because self.view is tableView onto which you added toolbar.