UIImageView shifts left before animating to the right - objective-c

Newbie here,
With this code in the .m file I aimed to animate an UIImageView to the right
#interface ViewController ()
#property (strong, nonatomic) IBOutlet UIImageView *myImageView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[UIView animateWithDuration:1
delay:0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
self.myImageView.center = CGPointMake(self.myImageView.center.x + 100, self.myImageView.center.y);
}
completion:^(BOOL finished){
}];
}
But what actually happens is that the image view shifts 100 points to the left and then animates to the right by 100 points back to its original position. I don't know why this happens. How can I achieve an animation that moves directly to the right?
Note: I'm not sure if this has to do with anything, but I added constraints in the interface builder to center this UIImageView in the middle.

Create IBOutlets for the constraints you want change. Just like you would for any other UIKit element. Then in your code instead of doing:
self.myImageView.center = CGPointMake(self.myImageView.center.x + 100, self.myImageView.center.y);
Do something like this:
self.imageViewTralingSpaceConstraint.constant = 100; //Or whatever value makes sense
Then in your animateWithDuration block add [self.view layoutSubViews];

you probably want to put this code in your viewDidAppear method rather than your viewDidLoad. this would make the animation happen after the view appears rather than before it. the viewDidLoad method is called after the view hierarchy is loaded into memory but not neccessarily after it is all laid out.
here is a link to the uiviewcontroller reference. https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/
check out these two methods there. if you continue doing iOS development you will get to know these methods really well.

Related

Set Scroll Boundaries UIWebView

I have a UIWebView which displays a webpage. The problem is I only want it to display a part of the webpage. I tried using [[_menuWebView scrollView] setContentOffset:CGPointMake(0, 100)]; to set the content offset to where I want it, but the problem is that I don't want the user to be able to scroll around the rest of the webpage. I also cannot set the webpage to not be scrollable because the part that I need to be able to be seen is slightly bigger than the space available. Is there a way to either:
Resize the view to only show one small portion so I can set it to not be scrollable
Set the scrolling boundaries in some way so that the user cannot scroll to the top of the page and not too far to the bottom either.
Thanks in advance!
EDIT:
I have used the code in the answer to get the UIWebView to not scroll past the top, the problem is getting it not to scroll past the bottom. I use this code to check where the contentOffset should be if it has hit the bottom: _bottom_y = [[_menuWebView scrollView] contentSize].height - 20 - [_menuWebView frame].size.height;. When I NSLog _bottom_y it comes up with 68 as where the bottom offset should be. The problem is that the top offset I know to be 115 and that works. What is wrong with the code above? Why is it giving me this weird number?
Thanks
I think this will be a good answer to your question. UIWebView in its structure contains an UIScrollView, that is why you can set your UIViewController to be a delegate of UIScrollView. Thus you can implement a method called scrollViewDidScroll: where you check if the UIWebView reached its y offset and if yes -> not let it scroll past that point.
Here is an example, that I have used:
#interface ViewController : UIViewController <UIScrollViewDelegate>
#property (weak, nonatomic) IBOutlet UIWebView *webView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_webView.scrollView.delegate = self;
[_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com"]]];
_webView.scrollView.contentOffset = CGPointMake(0, 50);
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y < 50) {
scrollView.contentOffset = CGPointMake(0, 50);
}
}
#end
Hope this helps, cheers!

UIView inside a UIViewController or better way to do it?

I have a problem on how to properly do a certain kind of action.
The image below shows a UIViewController, but the second part of the view is a custom UIView (the one with the profile pic, name and Show View button).
The subclassed UIView is allocated using this code:
profileView = [[GPProfileView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)];
profileView.myTripGradientColor = YES;
[self.view addSubview:profileView];
The problem is of course, that the button on the UIView can't show any view, since it's only the UIViewController that can push another ViewController to the window(correct?).
The UIView is used in several places in the app and needs to be added easily and have the same behavior across the application.
This worked great until I added the button, and I'm starting to think I've made this wrong, and there has to be a better way to do it (maybe change the UIView to something else?).
I was thinking I should be able to call:
self.superview
And then somehow get the ViewController so I can push another ViewController into the view hierarchy, but nope.
Any suggestions and a tips on how to do this correctly?
UPDATE:
I have no idea on how to push another UIViewController from the button.
What should I do in this method when pressing the button in the UIView:
- (void) showViewButtonTouched:(UIButton*)sender {
GPProfileSocialFriendsViewController *friendsSettings = [[GPProfileSocialFriendsViewController alloc] init];
}
How do I push GPProfileSocialFriendsViewController?
Your - (void) showViewButtonTouched:(UIButton*)sender method should be in your controller and would probably be better named - (void) showView:(UIButton*)sender or - (void) showProfile:(UIButton*)sender so it clearly denotes what it does (not how you got there).
It's not the view's responsibility to manage transitions from a state to another. If you move your method to your controller, your problem is no more (you can easily access self.navigationController or push directly if you don't have an navigation controller like this:
[self presentViewController:vcThatNeedsToBePushed animated:YES completion:nil];
I think you can create weak reference in GPProfileView on UIViewController. Like this:
#property (weak, nonatomic) UIViewController *rootController;
when you create GPProfileView, assign rootController-property:
profileView = [[GPProfileView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)];
profileView.myTripGradientColor = YES;
profileView.rootController = self; // if view created in view controller
[self.view addSubview:profileView];
and in implementation of button selector:
self.rootController push... // or pop
May be this not correct, but you can try
You could let the view controller push the next view controller when the button is pushed. The view controller can add a target/action on the button, so that the action method in the view controller is called on the touch up inside event.

Default view (as UIScrollView) of UIViewController - Can't set its content offset

According to my project, I changed the default view that tied to one UIViewController from UIView to UIScrollView as it has to be changed its offset and content size. The way I change from UIView to UIScrollView was by Interface Builder > Custom Class
If I want to change its offset and content size programmatically within The Controller, It can't be done in usual way unless I cast it
[((UIScrollView *)self.view) setContentSize:CGSizeMake(1024, 2000)];
[((UIScrollView *)self.view) setContentOffset:CGPointMake(0, 150)];
But with other UIScrollView within the app, changing their offset and content size can be done like any other,
// Assume that sv is scroll view object
[sv setContentSize:CGSizeMake(1027, 2000)];
[sv setContentOffset:CGPointMake(0, 150)];
When I print that scroll view object, it shown as a UIScrollView
NSLog(#"%#", self.view);
NSLog(#"%#", [self.view class]);
-> <UIScrollView: 0x6d3d3f0; frame = (0 0; 1024 768); autoresize = RM+BM; layer = <CALayer: 0x6d52ce0>; contentOffset: {0, 0}>
-> UIScrollView
Anyone know what I did missing or forgot to do rather than change the view's custom class?
Best and Thank you,
Tar
P.S. Besides the extra code needed, everything works fine. But, I can't take the chance of possible bug in the future. This client is super crazy, no error will be accepted
An alternative to this (that would avoid the need for casting) would be to set the UIViewController custom class back to UIView in interface builder. Then, insert a new UIScrollView as a subview (simply drag and drop in Interface Builder), connecting the UIScrollView to the UIViewController subclass via an IBOutlet that looks something like:
#property (nonatomic, weak) IBOutlet UIScrollView *scrollView;
(When you connect the outlet that property declaration should be generated for you by XCode).
Then, in your UIViewController subclass, you can do something like:
[[self scrollView] setContentSize:CGSizeMake(1024, 2000)];
[[self scrollView] setContentOffset:CGPointMake(0, 150)];
I'm not sure what the best solution is but a quick workaround is to create a method that casts the view in the UIViewController. That is:
- (UIScrollView *)scrollView {
return (UIScrollView *)self.view;
}
Then, instead of referring to the view in the ViewController as self.view, refer to it as self.scrollView.

How do I speed up iOS transitions and segues?

Is it possible to set a property application-wide to double the speed of transitions within an iOS app?
Application-wide?
Try setting the speed property on the backing layer for your view controllers' content views. speed=2 would be double-speed. You could probably set this in the viewDidLoad method for all your view controllers.
You might also be able to create a custom subclass of UIWindow, and have that window object set the speed property on it's view layer to 2.0 in a bottleneck method like makeKeyWindow. You'd need to make all your app's UIWindow objects use your custom class. I'd have to do some digging to figure out how to do that.
##Edit:
Or, better idea, set self.window.layer.speed = 2.0 in your app delegate after creating the window, as suggested by #Costique in the comment below.
Note that this approach will speed up ALL animations, not just transitions and segues. If you only want to speed up segues you would have to figure out how to target just those animations. I'd have to think about that.
Apple does not have a simple way to change that since it would make transitions too heterogenous amongst different apps. You could double the layer's speed, but that would mess up the timing on the rest of your animations. The best way is to implement your own transition using a category on UIViewControler.
UIViewController+ShowModalFromView.h
#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>
#interface UIViewController (ShowModalFromView)
- (void)presentModalViewController:(UIViewController *)modalViewController fromView:(UIView *)view;
#end
UIViewController+ShowModalFromView.m
#import "UIViewController+ShowModalFromView.h"
#implementation UIViewController (ShowModalFromView)
- (void)presentModalViewController:(UIViewController *)modalViewController fromView:(UIView *)view {
modalViewController.modalPresentationStyle = UIModalPresentationFormSheet;
// Add the modal viewController but don't animate it. We will handle the animation manually
[self presentModalViewController:modalViewController animated:NO];
// Remove the shadow. It causes weird artifacts while animating the view.
CGColorRef originalShadowColor = modalViewController.view.superview.layer.shadowColor;
modalViewController.view.superview.layer.shadowColor = [[UIColor clearColor] CGColor];
// Save the original size of the viewController's view
CGRect originalFrame = modalViewController.view.superview.frame;
// Set the frame to the one of the view we want to animate from
modalViewController.view.superview.frame = view.frame;
// Begin animation
[UIView animateWithDuration:1.0f
animations:^{
// Set the original frame back
modalViewController.view.superview.frame = originalFrame;
}
completion:^(BOOL finished) {
// Set the original shadow color back after the animation has finished
modalViewController.view.superview.layer.shadowColor = originalShadowColor;
}];
}
#end
This can easily be changed to use whatever animated transition you want. Hope this helps!

Objective-C: Adding UIButtons programmatically from another class

I'm having trouble connecting the dots between code and .xib files.
If I want to add a series of UIButtons programmatically to my view controller, how would I go about doing this from a separate class?
For instance, if I have MainViewController.m, which is set as the root view controller in Xcode, how can I add a UIButton to that view controller from SecondViewController.m? Is this even possible?
I would essentially like to place all of my "user interface" code in a separate class.
Thanks
To do this, create a UIButton *myButton programmatically and then call [mainViewController addSubview:myButton];. This may mean you need to store a MainViewController * property in your SecondViewController class.
Important methods and properties for a UIButton instance (essentially, just take a look at the documentation, but here's a minimal set of stuff to get you started):
+[UIButton buttonWithType:buttonType] - Make sure if you're doing anything remotely custom to use UIButtonTypeCustom here (it doesn't give you any default background images or otherwise to have to nil out)
setFrame: - Position the button relative to its container and set the size, for usability reasons the width and height should be at least 44 pixels (as mentioned here).
setTitle:forState: - UIControlStateNormal will act as the default properties for other states too, so you may only need to set the text here
setBackgroundImage:forState: - use UIControlStateNormal and UIControlStateHighlighted/UIControlStateSelected primarily, UIControlStateDisabled if you wish to show it grayed out or inaccessible at any point.
setImage:forState: - Use for an icon next to the button text (like an arrow pointing down for Save or up for Load, etc)
setEnabled:, setHidden:, setSelected: - Transition between different button states. setHighlighted: happens automatically when you tap the button.
addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside - TouchUpInside is almost always what you want for a simple button press, I'm using a method named buttonClicked: here to handle my button press.
Oh, and if you use [[UIButton alloc] initWith...] don't forget to [myButton release] once it's added to the mainViewController :)
use this
#import "MainViewController.h"
#interface SecondViewController
{
MainViewController *mainView;
}
#property(nonatomic, retain) MainViewController *mainView;
-(void)addButtons;
In your implementation
#synthesize mainView;
-(void)addButtons
{
UIButton *add = [UIButton alloc] init];
//do necessary stuff on button here
[self.mainView addSubview:add];
[add release];
}
In your MainViewcontroller.m
#import "SecondViewController.h"
-(void)viewDidLoad
{
[self superViewDidLoad];
SecondViewController *second = [SecondViewController alloc] init];
second.mainView = self;
[second addButton];
[second release];
}