I'm having some problems with UIView subview animations. What I'm trying to do is that when you press the main view, a subview will slide down from the top and on the next tap it will slide up and be removed. But in the current state, it just does the first tap commands and on the second tap, it displays a nslog, but the removal of the view and the animation doesn't work.
Here is the code in the event handling function:
- (void)tapGestureHandler: (UITapGestureRecognizer *)recognizer
{
NSLog(#"tap");
CGRect frame = CGRectMake(0.0f, -41.0f, self.view.frame.size.width, 41.0f);
UIView *topBar = [[UIView alloc] initWithFrame:frame];
UIColor *background = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"topbar.png"]];
topBar.backgroundColor = background;
if (topBarState == 0) {
[self.view addSubview:topBar];
[UIView animateWithDuration:0.5 animations:^{topBar.frame = CGRectMake(0.0f, 0.0f, self.view.frame.size.width, 41.0f);}];
topBarState = 1;
} else if (topBarState == 1){
[UIView animateWithDuration:0.5 animations:^{topBar.frame = CGRectMake(0.0f, -41.0f, self.view.frame.size.width, 41.0f);} completion:^(BOOL finished){[topBar removeFromSuperview];}];
NSLog(#"removed");
topBarState = 0;
}
}
How do i make it so that the subview animate and is removed properly?
Best Regards
FreeSirenety
you are always set the topBar frame with y = -41, so for topBarState = 1, animation works for y=-41 to y=-41 and seems to be as not working
CGRect frame = CGRectMake(0.0f, -41.0f, self.view.frame.size.width, 41.0f);
UIView *topBar = [[UIView alloc] initWithFrame:frame];
every time you are creating the view topBar.
Declare topBar in .h and alloc init in viewDidLoad.
- (void)viewDidLoad {
CGRect frame = CGRectMake(0.0f, -41.0f, self.view.frame.size.width, 41.0f);
topBar = [[UIView alloc] initWithFrame:frame];
UIColor *background = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"topbar.png"]];
topBar.backgroundColor = background;
[self.view addSubview:topBar];
topBarState = 0;
}
- (void)tapGestureHandler: (UITapGestureRecognizer *)recognizer
{
if (topBarState == 0) {
[UIView animateWithDuration:0.5 animations:^{topBar.frame = CGRectMake(0.0f, 0.0f, self.view.frame.size.width, 41.0f);}];
topBarState = 1;
} else if (topBarState == 1){
[UIView animateWithDuration:0.5 animations:^{topBar.frame = CGRectMake(0.0f, -41.0f, self.view.frame.size.width, 41.0f);} completion:^(BOOL finished){[topBar removeFromSuperview];}];
topBarState = 0;
}
}
Related
Hi i am beginner in ios and in my project i am adding UIImage on UIScrollview and i have added tap gesture on UIImage
When we double click on UIImage then image should be zooming full screen size on view controller
After the full screen size image we can zoom it like any way what we want(i mean using like pinch zoom effect)here my requirement is when we double click on image then image need to set it's original position i have tried my level best but i did not get result please help me
my code is below:
#import "ViewController2.h"
#interface ViewController2 ()
{
UIScrollView * myScroll;
UITapGestureRecognizer *tap;
BOOL isFullScreen;
CGRect prevFrame;
UIImageView * _imageView;
}
#end
#implementation ViewController2
- (void)viewDidLoad
{
[super viewDidLoad];
isFullScreen = FALSE;
myScroll = [[UIScrollView alloc] init];
myScroll.frame = self.view.bounds;
myScroll.contentSize = CGSizeMake(_imageView.frame.size.width, _imageView.frame.size.height);
myScroll.maximumZoomScale = 4.0;
myScroll.minimumZoomScale = 1.0;
myScroll.clipsToBounds = YES;
myScroll.delegate = self;
myScroll.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:myScroll];
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 300, 200)];
_imageView.contentMode = UIViewContentModeScaleAspectFill;
[_imageView setClipsToBounds:YES];
_imageView.userInteractionEnabled = YES;
_imageView.image = [UIImage imageNamed:#"ram.jpeg"];
UITapGestureRecognizer *tapper = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imgToFullScreen:)];
tapper.numberOfTapsRequired = 1;
[_imageView addGestureRecognizer:tapper];
[myScroll addSubview:_imageView];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return _imageView;
}
-(void)imgToFullScreen:(UITapGestureRecognizer*)sender {
if (!isFullScreen) {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
prevFrame = _imageView.frame;
[_imageView setFrame:[[UIScreen mainScreen] bounds]];
}completion:^(BOOL finished){
isFullScreen = TRUE;
}];
return;
}
else{
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
[_imageView setFrame:prevFrame];
}completion:^(BOOL finished){
isFullScreen = FALSE;
}];
return;
}
}
#end
I did some modifications in your code as like below try it .Check it give your wanted output or not.
#interface ScrollViewController ()<UIScrollViewDelegate>{
UIScrollView * myScroll;
UITapGestureRecognizer *tap;
BOOL isFullScreen;
CGRect prevFrame;
UIImageView * _imageView;
CGAffineTransform trans;
}
#end
#implementation ScrollViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
isFullScreen = FALSE;
myScroll = [[UIScrollView alloc] init];
myScroll.frame = [UIScreen mainScreen].bounds;
myScroll.contentSize = CGSizeMake(prevFrame.size.width, prevFrame.size.height);
myScroll.maximumZoomScale = 4.0;
myScroll.minimumZoomScale = 1.0;
myScroll.clipsToBounds = YES;
myScroll.delegate = self;
myScroll.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:myScroll];
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 300, 200)];
_imageView.contentMode = UIViewContentModeScaleAspectFill;
[_imageView setClipsToBounds:YES];
_imageView.userInteractionEnabled = YES;
_imageView.image = [UIImage imageNamed:#"img.png"];
UITapGestureRecognizer *tapper = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imgToFullScreen:)];
tapper.numberOfTapsRequired = 2;
[_imageView addGestureRecognizer:tapper];
[myScroll addSubview:_imageView];
prevFrame = _imageView.frame;
trans = _imageView.transform;
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return _imageView;
}
-(void)imgToFullScreen:(UITapGestureRecognizer*)sender {
if (!isFullScreen) {
myScroll.contentSize = prevFrame.size;
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
_imageView.frame = [UIScreen mainScreen].bounds;
}completion:^(BOOL finished){
isFullScreen = TRUE;
}];
return;
}
else{
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
myScroll.contentSize = CGSizeMake(prevFrame.size.width, prevFrame.size.height);
_imageView.transform = trans;
_imageView.frame = prevFrame;
NSLog(#"%# %#",NSStringFromCGSize(myScroll.contentSize),NSStringFromCGRect(prevFrame));
}completion:^(BOOL finished){
isFullScreen = FALSE;
}];
return;
}
}
I'm trying to make a animation that is done in Skype iOS application. The animation can be seen in this link Animation Section 3:Add a Contact
I tried with UIBezierPath but I can't do it. Any ideas?
Thanks!
My code
#implementation CustomView
#pragma mark - Lifecycle and initialize components
- (instancetype) initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if ( self ) {
self.alpha = 0;
[self configureCancelButton];
[self configureCollectionView];
[self addSubview:self.cancelButton];
[self addSubview:self.collectionView];
}
return self;
}
- (void) configureCancelButton {
self.cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.cancelButton setTitle:#"Cancel" forState:UIControlStateNormal];
self.cancelButton.titleLabel.font = [UIFont systemFontOfSize:20];
[self.cancelButton addTarget:self action:#selector (cancelView) forControlEvents:UIControlEventTouchUpInside];
self.cancelButton.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.8];
self.cancelButton.layer.cornerRadius = 7.f;
self.frameForCancelButton = CGRectMake (self.bounds.origin.x+5, self.bounds.size.height - kCancelButtonHeight - 5, self.bounds.size.width-10, kCancelButtonHeight);
self.cancelButton.frame = CGRectMake (self.frameForCancelButton.origin.x, self.frameForCancelButton.origin.y + kAnimationOffset, self.frameForCancelButton.size.width, self.frameForCancelButton.size.height);
}
- (void) configureCollectionView {
UICollectionViewFlowLayout *layout= [[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(kItemSize, kItemSize);
layout.minimumInteritemSpacing = 3.0;
layout.sectionInset = UIEdgeInsetsMake(0, 7, 7, 10);
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.frameForCollectionView = CGRectMake(self.cancelButton.frame.origin.x, self.frame.size.height - (self.cancelButton.frame.size.height + 10 + kCollectionHeight), self.cancelButton.bounds.size.width, kCollectionHeight);
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake (self.frameForCollectionView.origin.x, self.frameForCollectionView.origin.y + kAnimationOffset, self.frameForCollectionView.size.width, self.frameForCollectionView.size.height)
collectionViewLayout:layout];
self.collectionView.backgroundColor = [UIColor colorWithWhite:1 alpha:.8];
[self.collectionView registerClass:[RAShareCell class] forCellWithReuseIdentifier:#"Cell"];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
self.collectionView.layer.cornerRadius = 7.f;
}
#pragma mark - Public Methods
- (void) present {
[UIView animateWithDuration:0.35 animations:^{
self.alpha = 1;
self.darkView.alpha = .5;
}];
[UIView animateWithDuration:1.0 delay:0.45 options:(UIViewAnimationOptions) UIViewAnimationCurveEaseInOut animations:^{
[self setupAnimation];
} completion:nil];
}
- (void) cancelView {
[UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationCurveEaseInOut animations:^{
self.cancelButton.frame = CGRectMake (self.frameForCancelButton.origin.x, self.frameForCancelButton.origin.y + kAnimationOffset, self.frameForCancelButton.size.width, self.frameForCancelButton.size.height);
self.collectionView.frame= CGRectMake(self.frameForCollectionView.origin.x, self.frameForCollectionView.origin.y + kAnimationOffset, self.frameForCollectionView.size.width, self.frameForCollectionView.size.height);
} completion:^(BOOL finished) {
[self removeFromSuperview];
}];
;
}
- (void) setupAnimation {
self.cancelButton.alpha = 1;
self.collectionView.alpha = 1;
self.cancelButton.frame = self.frameForCancelButton;
self.collectionView.frame = self.frameForCollectionView;
[self addShapeLayer];
}
- (void)addShapeLayer
{
self.shapeLayer = [CAShapeLayer layer];
self.shapeLayer.path = [[self pathAtInterval:0.0] CGPath];
self.shapeLayer.fillColor = [[UIColor redColor] CGColor];
self.shapeLayer.lineWidth = 3.0;
self.shapeLayer.strokeColor = [[UIColor redColor] CGColor];
[self.collectionView.layer insertSublayer:self.shapeLayer atIndex:0];
}
- (UIBezierPath *) pathAtInterval:(NSTimeInterval) interval {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(self.collectionView.frame.origin.x,self.collectionView.frame.origin.y)];
[path addQuadCurveToPoint:CGPointMake(self.collectionView.frame.size.width, self.collectionView.frame.origin.y) controlPoint:CGPointMake(self.collectionView.frame.size.width/2, self.collectionView.frame.origin.y-30)];
return path;
}
Your animation block does not contain any animations. You should move your setup outside of the animation block and then animate within it.
[self setupAnimation];
[UIView animateWithDuration:1.0 delay:0.45 options:(UIViewAnimationOptions) UIViewAnimationCurveEaseInOut animations:^{
// animate something
} completion:nil];
In addition to this, your intended animation does not have a linear progression, meaning that you'l want to use animateKeyframesWithDuration instead.
[UIView animateKeyframesWithDuration:1.0 delay:0.45 options:UIViewAnimationCurveEaseInOut animations:^{
for (NSInteger i = 0; i < 10; i++) {
[UIView addKeyframeWithRelativeStartTime:i/10.0
relativeDuration:1.0/10.0
animations:^{
self.shapeLayer = [self pathAtInterval:i/10.0];
}];
}
} completion:nil];
1, add the path you created to CAShaperLayer object;
2, see the "strokeStart" and "strokeEnd" properties in CAShapeLayer class;
3, add a animation which called "CABasicAnimation" to your Layer obj.
Alright, I'm almost positive I'm just doing something stupid, but I'm new to this, so please excuse my incompetence. I have a nested animation block, and it changes the view controller once it's finished - one problem. It fires prematurely. I don't know if it's me incorrectly changing the view controller, or the block is incorrect. Any help would be great. Thanks in advance.
SplashViewController.m
#import "SplashViewController.h"
#import "MenuViewController.h"
#interface SplashViewController ()
#end
#implementation SplashViewController
-(void) drawColoredBars
{
UIView *greenBar = [[UIView alloc] initWithFrame:CGRectMake(75.0, -self.view.bounds.size.height, 3.0, self.view.bounds.size.height)];
UIView *orangeBar = [[UIView alloc] initWithFrame:CGRectMake(87.5, -self.view.bounds.size.height - 25, 3.0, self.view.bounds.size.height)];
UIView *yellowBar = [[UIView alloc] initWithFrame:CGRectMake(100.0, -self.view.bounds.size.height - 50, 3.0, self.view.bounds.size.height)];
UIColor *green = [UIColor colorWithRed:142.0/255.0f green:149.0/255.0f blue:31.0/255.0f alpha:0.6f];
UIColor *orange = [UIColor colorWithRed:204.0/255.0f green:82.0/255.0f blue:29.0/255.0f alpha:0.6f];
UIColor *yellow = [UIColor colorWithRed:254.0/255.0f green:190.0/255.0f blue:16.0/255.0f alpha:0.6f];
greenBar.backgroundColor = green;
orangeBar.backgroundColor = orange;
yellowBar.backgroundColor = yellow;
greenBar.tag = 1;
orangeBar.tag = 2;
yellowBar.tag = 3;
[self.view addSubview:greenBar];
[self.view addSubview:orangeBar];
[self.view addSubview:yellowBar];
}
-(void) animate
{
MenuViewController *menu = [[MenuViewController alloc] init];
double delay = 0.0;
double x = 75.0;
for (int i = 1; i < 4; i++) {
CGRect frame = CGRectMake(x, 0.0, 3.0, self.view.bounds.size.height);
[UIView animateWithDuration: 2.5
delay: delay
options: UIViewAnimationOptionCurveEaseIn
animations:^{
[self.view viewWithTag:i].frame = frame;
}
completion:^(BOOL finished){
[UIView animateWithDuration: 2.5
delay: 2.5
options: UIViewAnimationOptionCurveEaseIn
animations:^{
self.view.alpha = 0.0;
}
completion:^(BOOL finished){
[self presentViewController:menu animated:NO completion:nil];
}];
}];
delay = delay + 0.5;
x = x + 12.5;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
CAGradientLayer *layer = [GradientBackground drawGradient];
layer.frame = self.view.bounds;
[self.view.layer insertSublayer:layer atIndex:0];
[self drawColoredBars];
[self animate];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
Once again, thanks!
The viewDidLoad method is too early to set up animations. Try putting [self animate] in viewDidAppear: instead.
Also, make sure [self.view viewWithTag:i] doesn't return nil. If it returns nil, the outer animation block doesn't have anything to animate and will fire its completion block immediately.
I implemented the feature to display a fullscreen image when it is tapped. However this only enlarge the image but does not show it with a black background (the other elements of the view are still in the bakcground). How can I do this?
//Setup touch up inside of the imageview (in viewdidload)
userPictImageView.userInteractionEnabled = YES;
userPictImageView.contentMode = UIViewContentModeScaleAspectFit;
UITapGestureRecognizer *tapper = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageViewFullScreenTouchHandler:)];
tapper.numberOfTapsRequired = 1;
[userPictImageView addGestureRecognizer:tapper];
//present a full screen image (without black background)
-(IBAction)imageViewFullScreenTouchHandler:(id)sender {
//goto new ViewController and set the image
UIImageView *imageView = userPictImageView;
if (!imageIsFullScreen) {
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
//save previous frame
prevFrame = imageView.frame;
blackView=[[UIView alloc]initWithFrame:self.view.frame];
[blackView setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:blackView];
CGRect frame = self.view.frame;
[imageView setFrame:frame];
[blackView addSubview:imageView]; }
completion:^(BOOL finished){
imageIsFullScreen = TRUE;
}];
return;
}
else{
self.view.backgroundColor = [UIColor clearColor];
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
[imageView setFrame:prevFrame];
}completion:^(BOOL finished){
imageIsFullScreen = FALSE;
}];
return;
}
}
You could change to UIViewContentModeScaleToFill, or, probably better, build a UIView with a black background whose frame matches the view frame. Make the image view a subview of that black view.
I'd do it something like this. Create a method that I can call to zoom and unzoom the imageView. To zoom, build a background view and attach the image. To unzoom, do the reverse, and then destroy the background view.
Since the background view will be full screen, attach a gesture recognizer to it so the user can tap to dismiss.
- (void)setUserPictImageViewZoomed:(BOOL)zoom animated:(BOOL)animated {
UIView *blackView = [self.view viewWithTag:128];
BOOL isZoomed = blackView != nil;
// if our current state (isZoomed) matches the desired state (zoomed), then we're done
if (isZoomed == zoom) return;
NSTimeInterval duration = (animated)? 0.3 : 0.0;
if (zoom) {
blackView = [[UIView alloc] initWithFrame:self.view.frame];
blackView.backgroundColor = [UIColor blackColor];
blackView.tag = 128;
blackView.alpha = 0.0;
[self.view addSubview:blackView];
UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(unzoom:)];
[blackView addGestureRecognizer:tapGR];
UIImageView *zoomImageView = [[UIImageView alloc] initWithImage:self.userPictImageView.image];
zoomImageView.contentMode = UIViewContentModeScaleAspectFit;
zoomImageView.tag = 129;
zoomImageView.frame = [self.userPictImageView convertRect:self.userPictImageView.frame toView:blackView];
[blackView addSubview:zoomImageView];
[UIView animateWithDuration:duration animations:^{
zoomImageView.frame = blackView.bounds;
blackView.alpha = 1.0;
}];
} else {
UIImageView *zoomImageView = (UIImageView *)[blackView viewWithTag:129];
[UIView animateWithDuration:duration animations:^{
zoomImageView.frame = self.userPictImageView.frame;
blackView.alpha = 0.0;
} completion:^(BOOL finished) {
[blackView removeFromSuperview];
}];
}
}
- (void)unzoom:(UIGestureRecognizer *)gr {
[self setUserPictImageViewZoomed:NO animated:YES];
}
I tested this quickly in a simulator and it looked pretty slick.
I have subclassed UIView to contain basically a UIPickerView and a UIToolbar.
When the user selects a particular row in the picker I will then add a UIImageView over the picker. However this image is not visible when I have animated my UIView to slide up the screen. If I don't animate the UIView then it will display properly.
I'm displaying the UIImageView like this (in the UIView):
- (void)showMailSetupPopover {
if (self.popoverMailSetupImageView == nil) {
UIImageView *popoverMailSetupImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"popover-mail-setup-addreminder"]];
popoverMailSetupImageView.alpha = 0.0;
popoverMailSetupImageView.frame = CGRectMake(8, self.frame.origin.y + 65, popoverMailSetupImageView.bounds.size.width, popoverMailSetupImageView.bounds.size.height);
self.popoverMailSetupImageView = popoverMailSetupImageView;
}
[self addSubview:self.popoverMailSetupImageView];
[UIView animateWithDuration:0.5 animations:^{
self.popoverMailSetupImageView.alpha = 1.0;
} completion:^(BOOL finished) {}];
}
This is how I add theUIView to self.view:
RMMessageTypePickerView *messageTypePickerView = [[RMMessageTypePickerView alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height, 320, 260) reminderMessageType:RMReminderMessageTypeText delegate:self];
self.messageTypePickerView = messageTypePickerView;
[self.view addSubview:self.messageTypePickerView];
[UIView animateWithDuration:0.2 animations:^{
self.messageTypePickerView.frame = messageTypePickerViewTargetFrame;
self.addReminderTableView.frame = addReminderTableViewTargetFrame;
} completion:^(BOOL finished) {
if (firstShow) {
[self processSelectedMessageTypeRow:RMReminderMessageTypeText];
}
}];
Found out the issue,
Replaced
popoverMailSetupImageView.frame = CGRectMake(8, self.frame.origin.y + 65, popoverMailSetupImageView.bounds.size.width, popoverMailSetupImageView.bounds.size.height);
with
popoverMailSetupImageView.frame = CGRectMake(8, 65, popoverMailSetupImageView.bounds.size.width, popoverMailSetupImageView.bounds.size.height);
self.frame.origin.y is not needed.