I have enabled my Cocoa Touch app to be navigable by swiping left or right to alter positions in history. The animation is kind of done like Android's "card" style. Where swiping to the left (<--) just moves the current screen image out of the way, while showing the previous view beneath it.
This works fine, but when I want to swipe the other way (-->), to go back, I need to get the previous image, and move that over the current view. Now, I had this working if I only store the previous image, but what if I go <-- a few times, then I will not have enough images.
So, the solution is obvious, use an NSMutableArray and just throw the latest image at the front of the array, and when you swipe the other way, just use the first image in the array. However, the image never shows when I start the animation. It just shows nothing. Here's the required methods you should see:
-(void)animateBack {
CGRect screenRect = [self.view bounds];
UIImage *screen = [self captureScreen];
[imageArray insertObject:screen atIndex:0]; //Insert the screenshot at the first index
imgView = [[UIImageView alloc] initWithFrame:screenRect];
imgView.image = screen;
[imgView setHidden:NO];
NSLog(#"Center of imgView is x = %f, y = %f", imgView.center.x, imgView.center.y);
CGFloat startPointX = imgView.center.x;
CGFloat width = screenRect.size.width;
NSLog(#"Width = %f", width);
imgView.center = CGPointMake(imgView.center.x, imgView.center.y);
[self.view addSubview: imgView];
[self navigateBackInHistory];
[UIView animateWithDuration:.3 animations:^{
isSwiping = 1;
imgView.center = CGPointMake(startPointX - width, imgView.center.y);
} completion:^(BOOL finished){
// Your animation is finished
[self clearImage];
isSwiping = 0;
}];
}
-(void)animateForward {
CGRect screenRect = [self.view bounds];
//UIImage *screen = [self captureScreen];
UIImage *screen = [imageArray objectAtIndex:0]; //Get the latest image
imgView = [[UIImageView alloc] initWithFrame:screenRect];
imgView.image = screen;
[imgView setHidden:NO];
NSLog(#"Center of imgView is x = %f, y = %f", imgView.center.x, imgView.center.y);
CGFloat startPointX = imgView.center.x;
CGFloat width = screenRect.size.width;
NSLog(#"Width = %f", width);
imgView.center = CGPointMake(imgView.center.x - width, imgView.center.y);
[self.view addSubview: imgView];
[UIView animateWithDuration:.3 animations:^{
isSwiping = 1;
imgView.center = CGPointMake(startPointX, imgView.center.y);
} completion:^(BOOL finished){
// Your animation is finished
[self navigateForwardInHistory];
[self clearImage];
isSwiping = 0;
}];
}
-(void)clearImage {
[imgView setHidden:YES];
imgView.image = nil;
}
-(void)navigateBackInHistory {
[self saveItems:self];
[self alterIndexBack];
item = [[[LEItemStore sharedStore] allItems] objectAtIndex:currentHistoryIndex];
[self loadItems:self];
}
-(void)navigateForwardInHistory {
[imageArray removeObjectAtIndex:0]; //Remove the latest image, since we just finished swiping this way.
[self saveItems:self];
[self alterIndexForward];
item = [[[LEItemStore sharedStore] allItems] objectAtIndex:currentHistoryIndex];
[self loadItems:self];
}
Note that imgView is a class-level UIImageView and imageArray is a class level array.
Any ideas? Thanks.
Edit
Here's the code at the top of my .m to initalize it. Still does not work.
.....
NSMutableArray *imageArray;
- (void)viewDidLoad
{
[super viewDidLoad];
imageArray = [imageArray initWithObjects:nil];
It looks like you forgot to create the array. Something like this at the appropriate time would do (assuming ARC):
imageArray = [NSMutableArray array];
Glad that worked out.
Related
I made a view which holds a UIScrollview:
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(10, 65, 300, 188)];
//BackViews will hold the Back Image
BackViews = [[NSMutableArray alloc] init];
for (int i=0; i<BigPictures.count; i++) {
[BackViews addObject:[NSNull null]];
}
FrontViews = [[NSMutableArray alloc] initWithCapacity:BigPictures.count];
[self.pageControl setNumberOfPages:BigPictures.count];
Then I add several UIImageviews containing images:
//BigPictures holds objects of type UIImage
for (int i = 0; i < BigPictures.count; i++) {
UIImageView *ImageView = [[UIImageView alloc] initWithImage:[BigPictures objectAtIndex:i]];
ImageView.frame = [self.scrollView bounds];
[ImageView setFrame:CGRectMake(self.scrollView.frame.size.width * i, ImageView.frame.origin.y, ImageView.frame.size.width, ImageView.frame.size.height)];
//this saves the FrontView for later (flip)
[FrontViews insertObject:ImageView atIndex:i];
[self.scrollView addSubview:test];
}
// Detect Single Taps on ScrollView
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(flip)];
[self.scrollView addGestureRecognizer:tap];
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * BigPictures.count, self.scrollView.frame.size.height);
self.scrollView.pagingEnabled = YES;
self.scrollView.delegate = self;
Ok so far so good. Now the method which does the flipImage part:
- (void)flip {
int currentPage = self.pageControl.currentPage;
UIView *Back = nil;
if ([BackViews objectAtIndex:currentPage] == [NSNull null]) {
//CreateBackView is just creating an UIView with text in it.
Back = [self CreateBackView];
[BackViews replaceObjectAtIndex:currentPage withObject:Back];
[UIView transitionFromView:[[self.scrollView subviews] objectAtIndex:currentPage] toView:[BackViews objectAtIndex:currentPage] duration:0.8 options:UIViewAnimationOptionTransitionFlipFromLeft completion:NULL];
} else {
[UIView transitionFromView:[[self.scrollView subviews] objectAtIndex:currentPage] toView:[FrontViews objectAtIndex:currentPage] duration:0.8 options:UIViewAnimationOptionTransitionFlipFromRight completion:NULL];
[BackViews replaceObjectAtIndex:currentPage withObject:[NSNull null]];
}
[self.view addSubview:Back];
[self rebuildScrollView];
}
This is what rebuildScrollView does:
- (void)rebuildScrollView
{
for (UIView *subview in self.scrollView.subviews) {
[subview removeFromSuperview];
}
for (int i = 0; i < BigPictures.count; i++) {
if ([BackViews objectAtIndex:i] == [NSNull null]) {
[self.scrollView addSubview:[FrontViews objectAtIndex:i]];
} else {
[self.scrollView addSubview:[BackViews objectAtIndex:i]];
}
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * BigPictures.count, self.scrollView.frame.size.height);
self.scrollView.pagingEnabled = YES;
self.scrollView.delegate = self;
}
So the behavior is the following:
If I click on the first image (1 of 3 in scrollview) the effect is the way I want it, meaning the frontimage turns around and shows the empty (white) back with some text in the middle
If I click on the second image, the image turns but the back is completely empty showing the grey background of the window. If I scroll to the other images, the still show the front image (as expected)
Now I click on the third image and its the same as 1) great.
Current layout is now [BackView, Nothing, Backview)
Lets run that again. But now I click on the last image and its the same as 2) :(
Any ideas whats going wrong here?
EDIT: Some new findings. I doubled the amount of pictures and this is how Front and Backviews are placed (after flipping each one). P = Picture & B = Backview.
P_1(B_1) - actually the only correct one
P_2(empty - should be B_2)
P_3(B_2 - should be B_3)
P_4(empty - should be B_4)
P_5(B_3 - should be B_5)
P_6(empty - should be B_6)
Did a complete rebuild and now it works. Really strange because I used the exact same code.
After some research on here I found a solution to creating a slide show of images in an iphone app. All working fine, currently the images show one after another.
My question is, can I make the images cross dissolve/fade rather than just appearing, and if so could I get some advice on that.
My Code
.m
}
int topIndex = 0, prevTopIndex = 1;
- (void)viewDidLoad
{
imagebottom = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,160,240)];
[self.view addSubview:imagebottom];
imagetop = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,160,240)];
[self.view addSubview:imagetop];
imageArray = [NSArray arrayWithObjects:
[UIImage imageNamed:#"image1.png"],
[UIImage imageNamed:#"image2.png"],
[UIImage imageNamed:#"image3.png"],
[UIImage imageNamed:#"ip2.png"],
nil];
NSTimer *timer = [NSTimer timerWithTimeInterval:5.0
target:self
selector:#selector(onTimer)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[timer fire];
[super viewDidLoad];
}
-(void)onTimer{
if(topIndex %2 == 0){
[UIView animateWithDuration:5.0 animations:^
{
imagebottom.alpha = 0.0;
}];
imagetop.image = [imageArray objectAtIndex:prevTopIndex];
imagetop.image = [imageArray objectAtIndex:topIndex];
}else{
[UIView animateWithDuration:5.0 animations:^
{
imagetop.alpha = 1.0;
}];
imagetop.image = [imageArray objectAtIndex:topIndex];
imagebottom.image = [imageArray objectAtIndex:prevTopIndex];
}
prevTopIndex = topIndex;
if(topIndex == [imageArray count]-1){
topIndex = 0;
}else{
topIndex++;
}
You have a bunch of options. If you have a "container" view, you can make a new UIImageView transparent (alpha = 0), then use a UIView animation block to fade one image in and the other out (or leave alpha = 1 on both and slide one in from any side you want.
For instance, you have your main view, self.view. You have one UIImageView *oldView, that is now at rect (0,0,320,100) and you want to slide it to the right as you slide a newView imageView in. First you set the newView frame to (-320,0,320,100) then [self.view addSubview newView]. To animate the change:
[UIView animateWithDuration:2 animations:^
{
oldView.frame = CGRectMake(320, 0, 320, 100);
newView.frame = CGRectMake(0,0,320, 100);
}
completion:^(BOOL finished)
{
[oldView removeFromSuperView];
} ];
You also have the option of using UiView's
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion
which gives you more/different options (and its less work too!). For instance, using the same basic objects in the first example, but the newView having the same frame as the oldView:
transitionFromView:oldView toView:newView duration:2 options: UIViewAnimationOptionTransitionCrossDissolve completion:^(BOOL finished)) { /*whatever*/}];
I am using this code to show scrolling images but I am only getting a white screen. I drag drop uiscrollview, created the iboutlet, synthesized it and rest of the code is here
#synthesize scrollView1;
const CGFloat kScrollObjHeight = 199.0;
const CGFloat kScrollObjWidth = 280.0;
const NSUInteger kNumImages = 5;
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[scrollView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
scrollView1 = [[UIScrollView alloc]init];
bgArray = [NSArray arrayWithObjects:#"Bg", #"Bg1.png", #"Bg2.png", #"Bg3.png", #"Bg4.png", #"Bg5.png", #"Bg6.png", #"Bg7.png", #"Bg8.png", nil];
[scrollView1 setBackgroundColor:[UIColor blackColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView1.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
scrollView1.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 0; i < [bgArray count]; i++)
{
NSString *imageName = [NSString stringWithFormat:#"%#", [bgArray objectAtIndex:i]];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = 199.0;
rect.size.width = 280.0;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollView1 addSubview:imageView];
[scrollView1 setShowsHorizontalScrollIndicator:NO];
[scrollView1 setShowsVerticalScrollIndicator:NO];
}
[self layoutScrollImages];
}
I think if you are create UIScrollView from code
scrollView1 = [[UIScrollView alloc]init];
then please add the scrollView1 in view
Example:-[self.view addSubview:scrollView1];
if you are create UIScrollView from nib then
not use this code
scrollView1 = [[UIScrollView alloc]init];
solve your probem
This is my code for adding sound while UIScrollview is scrolling in iPhone SDK. In this code, how to add the sound while using touch-events in scrolling?
Please give me your idea and suggestion or sample.
const CGFloat kScrollObjHeight = 151.0;
const CGFloat kScrollObjWidth =320.0;
const NSUInteger kNumImages = 5;
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
[scrollView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
- (void)viewDidLoad
{
self.view.backgroundColor = [UIColor clearColor];
[scrollView1 setBackgroundColor:[UIColor whiteColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES;
scrollView1.scrollEnabled = YES;
scrollView1.pagingEnabled = YES;
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"snap%d.jpg", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i;
[scrollView1 addSubview:imageView];
[imageView release];
[self layoutScrollImages];
}
[super viewDidLoad];
}
add UIScrollViewDelegate to your interface and then play sound while the scrolling is in task in scrollViewWillBeginDragging state and stop scrolling while in scrollViewDidEndDragging state.
You can use AVAudioPlayer to play sound on iOS devices
UPDATE:
Tells the delegate when the scroll view is about to start scrolling the content.
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
Also, Tells the delegate when dragging ended in the scroll view.
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
Implement these in your code & put in your custom behavior
you mast use UIScrollViewDelegate method
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
//play sound here
}
I have a scroll view that contains image view sized 68x78:
As you could see, all that images except from the centered one have a shadow. It changes when user scrolls, center image is always clear. It goes perfect until for the left edge image:
Here is the code:
-(void) buildSlideView{
fotosJugadores = [[NSArray alloc] initWithObjects:#"cara5.png", #"cara7.png", #"cara8.png", #"cara9.png", #"cara11.png", #"cara13.png", #"cara14.png", #"cara15.png", #"cara18.png",#"cara19.png", #"cara20.png", #"cara32.png",#"cara44.png",#"cara51.png", #"cara100.png", #"cara101.png", #"cara102.png",#"cara103.png", #"cara104.png", #"cara105.png",#"cara106.png",#"cara107.png", nil];
numberOfViews = [fotosJugadores count];
for (int i = 0; i < [fotosJugadores count]; i++) {
UIImage *myImage = [UIImage imageNamed:[fotosJugadores objectAtIndex:i]];
CGFloat yOrigin = i * (myImage.size.width+3) + 120;
UIImageView *awesomeView = [[UIImageView alloc] initWithFrame:CGRectMake(yOrigin, 0, myImage.size.width, myImage.size.height)];
awesomeView.tag = i;
awesomeView.image = myImage;
awesomeView.alpha = 0.5f;
awesomeView.backgroundColor = [UIColor blackColor];
[self.jugadorSlide addSubview:awesomeView];
awesomeView=nil;
}
[jugadorSlide setBackgroundColor:[UIColor blackColor]];
jugadorSlide.contentSize = CGSizeMake(68 * numberOfViews+240,78);
jugadorSlide.layer.cornerRadius = 11;
jugadorSlide.layer.masksToBounds = YES;
[jugadorSlide setContentOffset:CGPointMake(((68 * numberOfViews)/2), 0)];
//jugadorSlide.decelerationRate = UIScrollViewDecelerationRateNormal;
[self scrollViewDidEndDragging:jugadorSlide willDecelerate:NO];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
currentIndex = roundf(scrollView.contentOffset.x / 68);
NSLog(#"current end %d", currentIndex);
UIImageView *currentImage = [scrollView viewWithTag:currentIndex];
if (currentIndex>0&¤tIndex<=21){
if (currentIndex==currentImage.tag){
currentImage.alpha=1.0f;
[self changePerfilImage:currentImage.tag];}
CGPoint pointZero= CGPointMake(scrollView.contentOffset.x, currentImage.frame.origin.y);
[jugadorSlide setContentOffset:pointZero animated:YES];
}else {
UIImageView *currentImage = [scrollView viewWithTag:0];
NSLog(#"end dragging image tag %d", currentImage.tag);
currentImage.alpha=1.0f;
[self changePerfilImage:currentImage.tag];}
CGPoint pointZero= CGPointMake(currentImage.frame.origin.x+15, 0);
//[jugadorSlide setContentOffset:pointZero animated:YES];
}
As you can see, in the scrollViewDidEndDragging: "else" , I forced the tag as a desesperate solution, but images doesn't get clear.
You are incrementing the tag twice...
awesomeView.tag = i++;
Should just be:
awesomeView.tag = i+1;
I use i+1 because I never use a tag of 0 since any subview that hasn't been assigned a tag will have a tag of 0.
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
NSInteger currentIndex = roundf(scrollView.contentOffset.x / 68.0) + 1;
UIImageView *currentImage = [scrollView viewWithTag:currentIndex];
...
}
If this doesn't work you should NSLog the currentIndex each time you land on a new image and see what is happening when you land on the first one.