0

I know this is really basic stuff but i need to understand whether my understanding of this is correct.

So what i want to do is this. I want an view with a label on which when double tapped flips and loads another view. On the second view i want a UIPickerView and above i have a button saying back. Both views will be of same size as an UIPickerView which is 320px x 216px.

What i am thinking of to do is create two UIViewclasses named labelView and pickerView. I would then create a viewController which on loadView loads labelView then when user double taps the labelView i get an event in labelView class which is sent to my viewController that then can unload loadView and load the pickerView.

Does this sound as the best way to do this ? Is there a simpler way ? I am also unsure how i route the event from the labelView class to the viewControllerclass.

3 Answers 3

2

I dont exactly know the most efficient way to do it(as i am also now to this language),but it is for sure that i have solved ur problem. I made a simple program for that.Three classes involved here in my eg are BaseViewController (which will show two views),LabelView and PickerView (according to ur requirement).

In LabelView.h

@protocol LabelViewDelegate -(void)didTapTwiceLabelView; @end @interface LabelView : UIView { id <LabelViewDelegate> delegate; } @property(nonatomic,retain)id <LabelViewDelegate> delegate; -(void)didTouch; @end 

In LabelView.m

@synthesize delegate; -(id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { UILabel* labl = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, frame.size.width-20,20)]; labl.text = @"Some Text"; [self addSubview:labl]; [labl release]; labl = nil; self.backgroundColor = [UIColor grayColor]; UITapGestureRecognizer* ges = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTouch)] autorelease]; ges.numberOfTapsRequired = 2; [self addGestureRecognizer:ges]; } return self; } -(void)didTouch { [delegate didTapTwiceLabelView]; } 

//=============================================================

In Pickerview.h

@protocol PickerViewDelegate -(void)didTapBackButton; @end @interface PickerView : UIView <UIPickerViewDelegate,UIPickerViewDataSource>{ id <PickerViewDelegate> delegate; } @property(nonatomic,retain)id <PickerViewDelegate> delegate; @end 

In Pickerview.m

@implementation PickerView @synthesize delegate; -(id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { UIPickerView* picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 30, 320, 216)]; picker.delegate = self; picker.dataSource = self; [self addSubview:picker]; [picker release]; picker = nil; self.frame = CGRectMake(frame.origin.x, frame.origin.y, 320, 250); UIButton* btn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [btn setFrame:CGRectMake(10, 1, 50, 27)]; [btn setTitle:@"Back" forState:UIControlStateNormal]; [btn addTarget:self action:@selector(backButton) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:btn]; } return self; } -(void)backButton { [delegate didTapBackButton]; } 

//====================================================================

in BaseViewController.h

#import "LabelView.h" #import "PickerView.h" @interface VarticalLabel : UIViewController<UITextFieldDelegate,PickerViewDelegate,LabelViewDelegate> { PickerView* myPickerView; LabelView* myLabelView; } @end 

In BaseViewController.m

-(void)viewDidLoad { [super viewDidLoad]; myPickerView= [[PickerView alloc] initWithFrame:CGRectMake(0, 50, 320, 250)]; [self.view addSubview:myPickerView]; myPickerView.delegate = self; myLabelView= [[LabelView alloc] initWithFrame:CGRectMake(0, 50, 320, 250)]; [self.view addSubview:myLabelView]; myLabelView.delegate = self; myPickerView.hidden = YES; } #pragma mark PickerViewDelgate -(void)didTapBackButton { myPickerView.hidden = YES; myLabelView.hidden = NO; } #pragma mark LabelViewDelegate -(void)didTapTwiceLabelView { myPickerView.hidden = NO; myLabelView.hidden = YES; } 
Sign up to request clarification or add additional context in comments.

3 Comments

pretty cool, thx alot. yes that solved it. one thing i have left is to change the didTapBackButton to do an animation.
I'm not new to the language, and this looks pretty good to me. Good work, Amit! @donnib: if you're not already on top of it, check out UIView +beginAnimations:context: and related bits for a really simple hook into CoreAnimation.
A few potential issues: BaseViewController's viewDidLoad is alloc'ing without release (memory leak), and you really probably don't want to retain a delegate, it leads to cycling retain problems. Assigning your delegates usually makes sense when there's a pretty clear ownership involved, and I think that fits in this example.
2

To get events from a button to the view controller, just hook up the button's event, e.g. touch up inside, to a method in the view controller, using interface builder. (Double tapping is probably more complicated though.)

When you say 'flips', do you mean it actually shows an animation of flipping over a view to show a 'reverse' side? Like in the weather app when you hit the 'i' button? I'm assuming this is what you mean.

Perhaps check TheElements sample example on the iPhone Reference Library, it has an example of flip animation.

Btw, it's not strictly necessary to unload the loadView that is being 'hidden' when you flip -- it saves you having to construct it again when you flip back -- but it may be pertinent if you have memory use concerns, and/or the system warns you about memory being low.

Also, what do you mean by "create a UIView"? Do you mean subclass UIView, or just instantiate a UIVIew and add children view objects to it? The latter is the usual strategy. Don't subclass UIView just because you want to add some things to a UIView.

3 Comments

yes i mean the same animation as with the i in the maps. my issues here is more if the architecture of the app is correct using UIView and UIViewController. I am unsure whether i should instead create three UIViewControllers instead.
Apple have some advice on this, and it's usually correct: for one screen of stuff, have one UIViewController. Although Apple actually break their own rule (!) in various places, for you as the 'end-user' programmer it's usually a good idea.
So you might want to structure things like this: have a container UIView, which contains either the front or the back of the two possible views. At the point you remove one of those subviews and add the other, do it inside a UIViewAnimation block with the 'flip' effect.
1

If you've got one screen of information that gives way to another screen of information, you'd normally make them separate view controllers. So in your case you'd have one view controller with the label and upon receiving the input you want, you'd switch to the view controller composed of the UIPickerView and the button.

Supposing you use Interface Builder, you would probably have a top level XIB (which the normal project templates will have provided) that defines the app delegate and contains a reference to the initial view controller in a separate XIB (also supplied). In the separate XIB you'd probably want to add another view controller by reference (so, put it in, give it the class name but indicate that its description is contained in another file) and in that view controller put in the picker view and the button.

The point of loadView, as separate from the normal class init, is to facilitate naming and linking to an instance in one XIB while having the layout defined in another. View controllers are alloced and inited when something that has a reference to them is alloced and inited. But the view is only loaded when it is going to be presented, and may be unloaded and reloaded while the app is running (though not while it is showing). Generally speaking, views will be loaded when needed and unnecessary views will be unloaded upon a low memory warning. That's all automatic, even if you don't put anything in the XIBs and just create a view programmatically within loadView or as a result of viewDidLoad.

I've made that all sound more complicated than your solution, but it's actually simpler because of the amount you can do in Interface Builder, once you're past the curve of learning it. It may actually be worth jumping straight to the Xcode 4 beta, as it shakes things up quite a lot in this area and sites have reported that a gold master was seeded at one point, so is likely to become the official thing very soon.

With respect to catching the double tap, the easiest thing is a UITapGestureRecognizer (see here). You'd do something like:

// create a tap gesture recogniser, tell it to send events to this instance // of this class, and to send them via the 'handleGesture:' message, which // we'll implement below... UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)]; // we want double taps tapGestureRecognizer.numberOfTapsRequired = 2; // attach the gesture recogniser to the view we want to catch taps on [labelView addGestureRecognizer:tapGestureRecognizer]; // we have an owning reference to the recogniser but have now given it to // the label. We don't intend to talk to it again without being prompted, // so should relinquish ownership [tapGestureRecognizer release]; /* ... elsewhere ... */ // the method we've nominated to receive gesture events - (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer { // could check 'gestureRecognizer' against tapGestureRecognizer above if // we set the same message for multiple recognisers // just make sure we're getting this because the gesture occurred if(gestureRecognizer.state == UIGestureRecognizerStateRecognized) { // do something to present the other view } } 

Gesture recognisers are available as of iOS 3.2 (which was for iPad only; so iOS 4.0 on iPhone and iPod Touch).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.