I am trying to change views when I swipe. I have the swipe working find as I have tested this by changing the background color.
Since then however I have added a new view.nib and set the class to be the same as the current view.
Inside this classes .h file I have done this
#interface MasterViewController : UIViewController <UIGestureRecognizerDelegate>{
UIView *myView;
UIView *secondView;
}
#property (strong, nonatomic) IBOutlet UIView *myView; // attached to Viewcontroller nib
#property (strong, nonatomic) IBOutlet UIView *secondView; // attached to the secondView
- (void)swipedScreen;
MyView is the main view that appears first, secondView is the view of the nib that I have created and changed its class to relate to this view.
From there I have done this in the .m file
- (void) setupSwipeGestureRecognizer {
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipedScreen)];
swipeGesture.direction = (UISwipeGestureRecognizerDirectionRight|UISwipeGestureRecognizerDirectionLeft);
[myView addGestureRecognizer:swipeGesture];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.title = #"Prototype";
[self setupSwipeGestureRecognizer];
}
- (void)swipedScreen
{
// Not sure what to do here.
[[NSBundle mainBundle] loadNibNamed:#"SecondView" owner:self options:nil];
}
I just dont know what to do in swipedScreen method to get the secondView to appear.. I would like to animate this view to slid in from the right.. but at the moment that comes secondary to actually just getting the view to appear... not sure what I am doing wrong here but obviously its something quite fundamental.
any help would be greatly appreciated.
As I commented:
- (void)swipedScreen
{
[UIView animateWithDuration:3.0f delay:0 options:UIViewAnimationOptionCurveLinear
animations:^{
secondView.frame = CGRectMake(180, secondView.frame.origin.y, secondView.frame.size.width, secondView.frame.size.height);
}
completion:^(BOOL finished){
myView.hidden = YES;
}];
}
Actually, you'll have to change the X, Y, Width and height values as you want to animate, and when it's completed, I set the main view - myView - hidden.
Related
I looked for a few articles on SO and on other sources, but can't find answer. This question will be a complex one. First, what i have: two view controllers (let's call them VC1 and VC2), and two buttons for one on each VC (let's call them in the same way as B1 and B2).
Here is image
When app start, B1 slide from right border of screen to middle position like on screenshot;
I'll add code of this below. I want make this: when I click on B1, B1 slide left behind the border of the screen, segue is performed and then B2 button slide from right to centre(like B! button does). How can I make this? I must do this in custom segue class, or in some UIView method?
And on more question, if we click B1 (it slides beyond the left border), we at the VC2. If I click back button (bottom button on screenshot), I'll see white screen (because B1 have center coordinates about - 100). How i can prevent this too?
VC1 code
#import "ViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIButton *buttonOne;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
CGPoint startPossitionForButton = CGPointMake(345, 220);
self.buttonOne.center = startPossitionForButton;
[self slideButton];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
[self slideButtonOffScreen];
}
-(void)slideButton
{
[UIView animateWithDuration:0.3 animations:^{
CGPoint endPossitionForButton = CGPointMake(155, 220);
self.buttonOne.center = endPossitionForButton;
}];
}
-(void)slideButtonOffScreen
{
[UIView animateWithDuration:0.3 animations:^{
CGPoint endPossitionForButton = CGPointMake(-100, 220);
self.buttonOne.center = endPossitionForButton;
}];
}
VC2 code
#interface VC2 ()
#property (weak, nonatomic) IBOutlet UIButton *backButton;
#property (weak, nonatomic) IBOutlet UIButton *buttonTwo;
#end
#implementation VC2
- (IBAction)back:(id)sender {
[self.navigationController popViewControllerAnimated:NO];
}
-(void)slideButton
{
[UIView animateWithDuration:0.3 animations:^{
CGPoint endPossitionForButton = CGPointMake(155, 220);
self.buttonTwo.center = endPossitionForButton;
}];
}
- (void)viewDidLoad
{
[super viewDidLoad];
CGPoint startPossitionForButton = CGPointMake(345, 220);
self.buttonTwo.center = startPossitionForButton;
[self slideButton];
}
Custom Segue class:
-(void)perform
{
UIViewController *src = (UIViewController *) self.sourceViewController;
UIViewController *dst = (UIViewController *) self.destinationViewController;
[src.navigationController pushViewController:dst animated:NO];
}
Any help will be useful
Instead of calling the segue when pressing B1 call a helper action method. Inside this method perform the sliding and call the segue using performSegueWithIdentifier.
To slide the button back check its position in viewWillAppear and move it back if necessary.
Two really quick questions, I searched the web but couldn't find answers..
Is there any way to call block animations to a view from a class that is different from the viewController of that view. I also couldn't figure out how to add a subview to that view in a method that exists in a different class than the viewController ( the only way I can do it is [self.view addSubview:xxxxx]; in the viewController for my view)
Any help would be greatly appreciated and helpful.
Thank you!!
Keep a reference to YourViewController instance on ApplicationDelegate, and modify its subviews in OtherClass.
//in ApplicationDelegate.h
#property (strong, nonatomic) YourViewController *ref;
//in ApplicationDelegate.m
#synthesize ref;
self.ref = [[YourViewController alloc] initWithNibName:nil bundle:nil];
//in YourViewController.h
#property (retain, nonatomic) UIImageView *myImageView;
//in YourViewController.m
#synthesize myImageView;
//in OtherClass.m
[UIView animateWithDuration:DURATION delay:DELAY
options:OPTION
animations:^(void)
{
[[UIApplication sharedApplication] delegate].ref.myImageView.center=CGPointMake(100,100);
}
completion:^(BOOL finished)
{
[[UIApplication sharedApplication] delegate].ref.myImageView.center=CGPointMake(200,200);
}];
Well if the view that you're calling on the animation on also has a view controller then what you could do is create a method in that view controller that makes that animation. then in the other view that you want to call that animation you could do
[otherViewController animationMethod];
Honestly that's the best i can think of.
I have a viewcontroller which contains an instance variable containing a dictionary object with a bunch of data. The view is fairly complex and contains several subviews that i instantiate and embed from seperate view files(To avoid having a thousand lines of UI code in the actual viewcontroller) - But how do these subviews, which exists in their own files, get access to my dictionary object from the viewcontroller?
So when im editing the DescriptionView.m file - How do i get access to the contents of the locationData dictionary object from the ViewController?
Hope you understand what i mean.
Here's a snippet from the ViewController:
CaseViewController.h
#import "DescriptionView.h"
#interface CaseViewController : UIViewController {
NSDictionary *locationData;
DescriptionView *descriptionView;
}
#property (nonatomic, retain) NSDictionary *locationData;
#property (nonatomic, retain) DescriptionView *descriptionView;
#end
CaseViewController.m
- (void)loadView {
UIView *view = [[UIView alloc] init];
descriptionView = [[DescriptionView alloc] initWithFrame:CGRectMake(0, 130, 320, 237)];
descriptionView.hidden = NO;
[view addSubview:descriptionView];
self.view = view;
[view release];
}
Ideally you should never access any properties of viewcontroller from the view.
The main idea of MVC architecture is that viewcontroller tells it's views what to render and not vise versa.
So you just have to provide all the data that your view needs for rendering during it's initialization:
- (void)loadView {
UIView *view = [[UIView alloc] init];
descriptionView = [[DescriptionView alloc] initWithFrame:CGRectMake(0, 130, 320, 237) paramDict: self.locationData]; descriptionView.hidden = NO;
[view addSubview:descriptionView];
[descriptionView release]; // BTW add this line here (or in dealloc) or you'll have a leak
self.view = view; [view release];
}
If you need to update your view dynamically, then you should add some methods to your view and call them from viewcolnroller.
E.g.:
DescriptionView.m:
-(void) updateWithDict:(NSDictionary*) udict;
If you need to perform some actions when some button in DescriptionView is pressed (or any other user interaction) a good idea would be declaring a protocol like DescriptionViewDelegate (or smth like that):
-(void) descriptionViewButton1Pressed:(DescriptionView*) dview;
-(void) descriptionViewButton2Pressed:(DescriptionView*) dview;
then make your CaseViewController a delegate and implement that methods there.
The simpliest way to have a reference to its viewcontroller from a view is to extend UIView:
#interface MyView: UIView {
UIViewController *mViewController;
}
Then in loadView
MyView *view = [[MyView alloc] init];
view.mViewController = self;
In my viewbased application i loaded oneview as mainview and another view as subview of mainview. Its work well the code snippet is ,
In mainviewcontroller,
IBOutlet UIView *subView;
#property(nonatomic,retain) UIView *subView;
#synthesize subView;
[subView release];
//add subview
[self.view addSubview:subView];
//removefromsubview
[subView removeFromSuperview];
This code works fine.....
I dont want to create subview in mainviewcontroller, so i created a new UIView class and its named as subView, now i deleted all declarations of subView from mainviewcontroller and just import subView class in mainviewcontroller. And using this [self.view addSubview:subView];
This things not work great. Can anyone help me ... How can i interact a separate UIView class with UIViewcontroller.One more thing is that UIView class have labels and textboxes can i set values from UIViewController to UIView labels and textboxes ......
Is it possible ?
Thanks in advance.......Sorry for my bad english
You have a sub-class called Subview which is declared as a UIView, i.e.
#interface Subview : UIView {
UILabel *foo;
}
#property (nonatomic, retain) UILabel *foo;
#end
Now you want to use this sub-class inside of your main UIView, which you had from the start. There are a few things you need to do.
#import the Subview in your header file, and add an instance of it to your class.
#import "Subview.h"
and inside of your #interface's {}'s,
Subview *mySubview;
In the viewDidLoad class for your main view controller, around the bottom, add something like:
mySubview = [[Subview alloc] init];
[self.view addSubview:mySubview];
[mySubview release];
First line will allocate a new "Subview" for you, second line will add this to your view so you get the stuff it has, and third line will release it. It's okay to release it here, because "self.view" will now be responsible for it, so it won't vanish.
Lastly you need to set the view up in the init method for Subview. In Subview.m, do something like:
- (id)init
{
if (self = [super init]) {
foo = [[UILabel alloc] init];
foo.text = #"Hello!";
[self addSubview:foo];
}
return self;
}
And I think that should take care of it. You also want to release foo in -dealloc for Subview but you probably know how to do that stuff already.
EDIT: This question is due to a big lack of understanding how Interface Builder and properties in classes works.
Why can't i just set self.mySubView = anoterhView; like one can set self.view = anotherView; ?
## .h
#interface TestController : UIViewController {
IBOutlet UIView *mySubView;
}
#property (nonatomic, retain) IBOutlet UIView *mySubView;
##.m
#implements TestController
#synthesize mySubView;
- (void)viewDidLoad {
AnotherController *anotherController = [[AnotherController alloc] initWithNibName:nil bundle:nil];
anotherView = anotherController.view;
// if i do
self.view = anotherView;
// result: replaces whole view with anotherView
// if i instead do
self.mySubView = anotherView;
// result: no change at all
// or if i instead do:
[self.mySubView addSubview:anotherView];
// result: mySubView is now displaying anotherView
}
NOTE: I'm using interfacebuilder. I'm sure everything is hooked up allright because self.view, and self.mySubView addSubview: is working allright..
To make it automatically appear on your self.view you need to overwrite your setter method, e.g.:
- (void)setMySubView:(UIView *)view {
[mySubView removeFromSuperview]; // removing previous view from self.view
[mySubView autorelease];
mySubView = [view retain];
[self.view addSubview: mySubView]; // adding new view to self.view
}
mySubview is a property which is a reference to an UIView object. So when you assign an UIView object to it, you are merely changing what mySubview is referring to and no more as in this case,
self.mySubview = anotherView;
The original UIView object that mySubview was referring to is still referred to within view's subviews property. Nothing changes.
But when you add anotherView as a subview of mySubview, anotherView belongs to the view hierarchy and is displayed on screen. So this works.
view (parent of) mySubview (parent of) anotherView
However when you assign anotherView directly to the view, You not only change the UIView object view was referring to but it also adds itself to the parentView. This is handled by UIViewController.
self.view = anotherView;
Your setCurrentView should be more or so like this,
- (void) replaceSubview:(UIView *)newView {
CGRect frame = mySubview.frame;
[mySubview removeFromSuperview];
self.mySubview = newView;
[self.view addSubview:newView];
newView.frame = frame;
}
As a response to what #beefon said. This works kind of as expected, but background-color is transparent. It doesen't respond either... buttons do not get pressed etc..
- (void)setCurrentView:(UIView *)newView {
/* 1. save current view.frame: CGRect mySubViewFrame = [mySubView frame];
2. remove and put new subview - I have wrote how to do it
3. set new frame for new view: [mySubView setFrame:mySubViewFrame]; */
CGRect currentViewFrame = [currentView frame];
[currentView removeFromSuperview];
[currentView autorelease];
currentView = [newView retain];
[self.view addSubview:currentView];
[currentView setFrame:currentViewFrame];
}
Your instance variable needs to be a property in order to use the dot. syntax, use:
#Property (nonatomic, retain) IBOutlet UIView* subview;
in the header, and use:
#synthesize subview;
in the main file.
In order to set a UIView using the dot. syntax you need to make it a property. This also allows you to set the subview's properties outside the class.