UIScrollView with UIImageview and gestures using transitionFromView acting strange - objective-c

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.

Related

Using ELCImagePickerController to select images

I am trying to use the ELCImagePickerController , and it works but i have a few things that i would like to change .
i want it to show me a matrix of images from the main album right away, without picking albums and stuff. just show a matrix, with a done button . now it lets you pick an album first .
i cant understand where exactly the picked images where saved ?
how can i change the buttons cancel and done graphics ?
this is how i add it (to cocos2d scene )
albumController = [[ELCAlbumPickerController alloc] initWithNibName:#"ELCAlbumPickerController" bundle:[NSBundle mainBundle]];
elcPicker = [[ELCImagePickerController alloc] initWithRootViewController:albumController];
[albumController setParent:elcPicker];
[elcPicker setDelegate:self];
[[[CCDirector sharedDirector] view] addSubview:elcPicker.view];
this is the done button :
- (void)elcImagePickerController:(ELCImagePickerController *)picker didFinishPickingMediaWithInfo:(NSArray *)info
{
//[self removeFromParentAndCleanup:YES];
for (UIView *v in [scrollview subviews])
{
[v removeFromSuperview];
}
CGRect workingFrame = scrollview.frame;
workingFrame.origin.x = 0;
for(NSDictionary *dict in info)
{
UIImageView *imageview = [[UIImageView alloc] initWithImage:[dict objectForKey:UIImagePickerControllerOriginalImage]];
[imageview setContentMode:UIViewContentModeScaleAspectFit];
imageview.frame = workingFrame;
[scrollview addSubview:imageview];
[imageview release];
workingFrame.origin.x = workingFrame.origin.x + workingFrame.size.width;
}
[scrollview setPagingEnabled:YES];
[scrollview setContentSize:CGSizeMake(workingFrame.origin.x, workingFrame.size.height)];
}

NSMutableArray not holding UIImages properly?

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.

UIScrollView flickering with fixed subviews

I use the following code to make "fixed" row headers in my UIScrollView descendant. It works well with the Simulator, but unfortunately, it flickers on the iPad. (To the left of the row header views, a white 1px line appears and disappears.) What can be improved?
- (void)initSubviews
{
const int ROW_COUNT = 20;
rowHeaderViews = [[NSMutableArray alloc]initWithCapacity:ROW_COUNT];
rowViews = [[NSMutableArray alloc]initWithCapacity:ROW_COUNT];
[self setContentSize:CGSizeMake(2000, [self frame].size.height)];
for (int i = 0; i < ROW_COUNT; i++)
{
UIView *header = [self createRowHeaderViewForRowNum:i];
[rowHeaderViews addObject:header];
UIView *row = [self createRowViewForRowNum:i];
[rowViews addObject:row];
[self addSubview:row];
[self addSubview:header];
}
[self layoutSubviews];
}
- (void)layoutSubviews
{
int x = [self contentOffset].x;
for (UIView *view in rowHeaderViews) {
[view setFrame:CGRectMake(x, view.frame.origin.y, view.frame.size.width, view.frame.size.height)];
}
}
- (UIView *)createRowHeaderViewForRowNum: (int)rowNum
{
UILabel *view = [[UILabel alloc]initWithFrame:CGRectMake(0, rowNum * 20, 200, 20)];
[view setBackgroundColor:[UIColor colorWithWhite:0.8*(20-rowNum)/20 alpha:1]];
[view setText:[NSString stringWithFormat:#"Row Header %d", rowNum]];
return view;
}
- (UIView *)createRowViewForRowNum: (int)rowNum
{
UILabel *view = [[UILabel alloc]initWithFrame:CGRectMake(200, rowNum * 20, 1800, 20)];
[view setBackgroundColor:[UIColor colorWithRed:rowNum/20.0 green:0 blue:0 alpha:1]];
[view setText:[NSString stringWithFormat:#"Row Content %d", rowNum]];
return view;
}
Thank you very much for any help!
EDIT: The iPad has got a Retina display. When using the Simulator with a "normal" iPad, it does not flicker. When switching the Simulator to a "Retina display" iPad, there is this flickering, too. Maybe this is something about the points/pixels difference?
I found the bug on my own. Sorry for bothering you.
In case anybody else has got the same problem:
contentOffset.x is a float value and contains .5 values for Retina displays.
Assigning it to an int variable in layoutSubviews caused the problem.
This is the fix (note I replaced 'int' with 'CGFloat'):
- (void)layoutSubviews
{
CGFloat x = [self contentOffset].x;
for (UIView *view in rowHeaderViews) {
[view setFrame:CGRectMake(x, view.frame.origin.y, view.frame.size.width, view.frame.size.height)];
}
}

Why images are not showing in UIScrollView?

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

Issue with scroll view and accessing its subviews

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&&currentIndex<=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.