Issues with SpriteKit in Xcode 7 and IOS 9 - objective-c

My game app that was working perfectly fine on IOS 8 (built with Xcode 6) is all of sudden experiencing many issues when built using Xcode 7 with IOS 9.
Here is how the game used to look. (How it should look).
Here is it running on IOS 9 (broken)
GAME SCENE CODE
Code for creating the Game Board in Game Scene
-(void) createBoard {
self.buttons=[NSMutableArray new];
if (self.boardBlur != nil ) {
[self.boardBlur removeAllChildren];
}
self.backgroundColor=[UIColor clearColor];
// Use for Christmas Easter egg
/* NSString *snowPath = [[NSBundle mainBundle] pathForResource:#"SnowParticle" ofType:#"sks"];
SKEmitterNode *snow = [NSKeyedUnarchiver unarchiveObjectWithFile:snowPath];
snow.particlePositionRange=CGVectorMake(self.frame.size.width, 20);
snow.position=CGPointMake(self.frame.size.width/2,self.frame.size.height);
snow.zPosition=-3;
[self addChild:snow];*/
if (self.boardFrame != nil) {
[self.boardFrame removeFromParent];
[self.boundingBox removeFromParent];
}
self.boardFrame = [SKSpriteNode spriteNodeWithImageNamed:#"gameBoard2"];
self.boardFrame.color= self.level.baseColor;
self.boardFrame.colorBlendFactor=1.0;
self.boardFrame.alpha = .7;
self.boardFrame.zPosition=-1;
// self.boardFrame.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)+40);
self.boardFrame.size=self.size;
if (self.boardBlur == nil) {
self.boardBlur=[[SKEffectNode alloc]init];
self.boardBlur.filter=[CIFilter filterWithName:#"CIGaussianBlur"];
[self.boardBlur.filter setDefaults];
[self.boardBlur.filter setValue:#5.0 forKey:kCIInputRadiusKey];
self.boardBlur.shouldEnableEffects=NO;
self.boardBlur.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)+40);
[self addChild:self.boardBlur];
}
[self.boardBlur addChild:self.boardFrame];
[self displayMessage:self.level.name color:[UIColor whiteColor]];
[self createHUD];
CGRect playSurface=CGRectInset(self.frame, 36,36);
self.gridSize=fmin(playSurface.size.width,playSurface.size.height)/(fmax(self.level.width,self.level.height));
if (self.gridSize > 60) {
self.gridSize=60;
}
CGRect oldPlaySurface =playSurface;
playSurface=CGRectMake(0,0,self.gridSize*self.level.width,self.gridSize*self.level.height);
self.boardFrame.size=CGRectInset(playSurface, -24, -24).size;
self.boardBlur.zPosition=-2;
self.boundingBox=[SKShapeNode shapeNodeWithRect:CGRectInset(self.boardFrame.frame,self.gridSize/1.7,self.gridSize/1.7) cornerRadius:7.0];
self.boundingBox.strokeColor=[SKColor clearColor];
self.boundingBox.position=self.boardBlur.position;
self.boundingBox.zPosition=-5;
[self addChild:self.boundingBox];
self.ballSize=self.gridSize-6;
self.enlargeAction=[SKAction resizeToWidth:self.ballSize+5 height:self.ballSize+5 duration:0.2];
self.shrinkAction=[SKAction resizeToWidth:self.ballSize height:self.ballSize duration:0.2];
self.enlargeInAction=[SKAction resizeToWidth:self.ballSize height:self.ballSize duration:0.3];
self.shrinkOutAction=[SKAction resizeToWidth:0 height:0 duration:0.3];
CGFloat horizontalSpace = (playSurface.size.width-self.gridSize*self.level.width);
CGFloat verticalSpace = (playSurface.size.height-self.gridSize*self.level.height);
self.topOffset=80+verticalSpace/2+(oldPlaySurface.size.height-playSurface.size.height)/2;
self.leftOffset=40+horizontalSpace/2+(oldPlaySurface.size.width-playSurface.size.width)/2;
for (int y=0; y < self.level.height; y++) {
for (int x = 0; x < self.level.width; x++) {
//SKSpriteNode *backgroundButtonNode = [SKSpriteNode spriteNodeWithTexture:dotTexture];
SKShapeNode *backgroundButtonNode=[SKShapeNode shapeNodeWithCircleOfRadius:0.5];
// backgroundButtonNode.size=ballSize;
backgroundButtonNode.userInteractionEnabled=NO;
backgroundButtonNode.zPosition=0;
backgroundButtonNode.fillColor=[UIColor whiteColor];
// backgroundButtonNode.colorBlendFactor=1.0;
backgroundButtonNode.position=[self.boardFrame convertPoint:CGPointMake(self.leftOffset+(self.gridSize*x)+self.ballSize/2,self.topOffset+(self.gridSize*y)+self.ballSize/2) fromNode:self];
[self.boardFrame addChild: backgroundButtonNode];
}
}
CGFloat menuiconsize=fmin(self.ballSize, 60.0);
CGFloat menuWidth=fmin(self.boardFrame.size.width-40,420);
if (self.menuBar != nil) {
[self.menuBar removeFromParent];
}
self.menuBar=[[MenuBar alloc]initWithSize:CGSizeMake(menuWidth,self.ballSize+12) iconSize:CGSizeMake(menuiconsize,menuiconsize) Level:self.level];
self.menuBar.delegate=self;
[self addChild:self.menuBar];
self.menuBar.position=CGPointMake(self.frame.size.width/2-(menuWidth)/2, self.topOffset-menuiconsize-40);
self.menuBar.userInteractionEnabled=YES;
self.gameOver=NO;
}
Code for the HUD (Stars, Goal...)
-(void) createHUD {
if (self.topHud == nil) {
self.topHud=[SKShapeNode shapeNodeWithRect:CGRectMake(-2,self.frame.size.height-62,self.frame.size.width+2,64)];
self.topHud.fillColor=[UIColor clearColor];
self.topHud.strokeColor=[UIColor clearColor];
self.topHud.lineWidth=0;
[self addChild:self.topHud];
UIColor *textColor=[self.level textColor];
self.scoreLabel=[SKLabelNode labelNodeWithFontNamed:#"Blow"];
self.scoreLabel.fontSize=20;
self.scoreLabel.alpha = 1;
self.scoreLabel.horizontalAlignmentMode=SKLabelHorizontalAlignmentModeRight;
self.scoreLabel.fontColor=textColor;
self.scoreLabel.position=CGPointMake(self.frame.size.width-8,self.frame.size.height-25);
self.score=0;
[self.topHud addChild:self.scoreLabel];
self.highScoreLabel=[SKLabelNode labelNodeWithFontNamed:#"Blow"];
self.highScoreLabel.fontSize=20;
self.highScoreLabel.alpha = 1;
self.highScoreLabel.horizontalAlignmentMode=SKLabelHorizontalAlignmentModeRight;
self.highScoreLabel.fontColor=textColor;
self.highScoreLabel.position=CGPointMake(self.frame.size.width-8,self.frame.size.height-50);
//self.highScore=0;
[self.topHud addChild:self.highScoreLabel];
[self updateScore];
self.doughLabel=[SKLabelNode labelNodeWithFontNamed:#"Blow"];
self.doughLabel.fontColor=textColor;
self.doughLabel.fontSize=20;
self.doughLabel.horizontalAlignmentMode=SKLabelHorizontalAlignmentModeCenter;
self.doughLabel.position=CGPointMake(self.frame.size.width/2, 20);
[self coinBalanceChanged:nil];
[self addChild:self.doughLabel];
self.progressNode=[SKCropNode new];
self.progressNode.zPosition=1;
SKNode *dimStarsNode=[SKNode new];
SKSpriteNode *maskNode=[SKSpriteNode spriteNodeWithColor:[UIColor blackColor] size:CGSizeMake(66,24)];
maskNode.position=CGPointMake(-42, 0);
// self.progressNode.maskNode=maskNode;
for (int i=0;i<3;i++) {
SKSpriteNode *starNode=[SKSpriteNode spriteNodeWithImageNamed:#"SugarCookie"];
starNode.size=CGSizeMake(20,20);
starNode.position=CGPointMake(i*22,0);
[self.progressNode addChild:starNode];
starNode=[SKSpriteNode spriteNodeWithImageNamed:#"SugarCookie"];
starNode.size=CGSizeMake(20,20);
starNode.zPosition=1;
starNode.alpha=0.3;
starNode.position=CGPointMake(i*22,0);
[dimStarsNode addChild:starNode];
}
self.progressNode.maskNode= maskNode;
// self.progressNode.maskNode=maskNode;
self.progressNode.position=CGPointMake(22, self.frame.size.height-18);
dimStarsNode.position=CGPointMake(22, self.frame.size.height-18);
dimStarsNode.zPosition=0;
[self addChild:dimStarsNode];
[self addChild:self.progressNode];
self.goalLabel=[SKLabelNode labelNodeWithFontNamed:#"Blow"];
self.goalLabel.fontSize=20;
self.goalLabel.alpha = 1;
self.goalLabel.fontColor=textColor;
self.goalLabel.position=CGPointMake(12,self.frame.size.height-50);
self.goalLabel.horizontalAlignmentMode=SKLabelHorizontalAlignmentModeLeft;
self.goalLabel.text=[NSString stringWithFormat:#"Goal: %ld",(long)self.level.targetScore];
[self addChild:self.goalLabel];
self.storeButton=[[GameButtonNode alloc]initWithColor:self.level.baseColor strokeColor:[self.level levelColorWithBrightnessDelta:0.3 alpha:1.0] imageName:#"store" radius:25 physics:NO delegate:self];
self.storeButton.position=CGPointMake(self.frame.size.width-40,35);
[self addChild:self.storeButton];
self.menuButton=[[GameButtonNode alloc]initWithColor:self.level.baseColor strokeColor:[self.level levelColorWithBrightnessDelta:0.3 alpha:1.0] imageName:#"menuButton" radius:25 physics:NO delegate:self];
self.bottomMenuNode=[SKShapeNode shapeNodeWithRect:CGRectMake(5, 30, 180, 60) cornerRadius:7.0];
self.bottomMenuNode.strokeColor=[UIColor clearColor];
self.bottomMenuNode.fillColor=[self.level levelColorWithBrightnessDelta:-0.6 alpha:0.2];
self.bottomMenuNode.zPosition=6;
self.homeButton=[[GameButtonNode alloc]initWithColor:self.level.baseColor strokeColor:[self.level levelColorWithBrightnessDelta:0.3 alpha:1.0] imageName:#"homeButton" radius:25 physics:NO delegate:self];
self.homeButton.position=CGPointMake(35,60);
[self.bottomMenuNode addChild:self.homeButton];
self.menuReplayButton=[[GameButtonNode alloc]initWithColor:self.level.baseColor strokeColor:[self.level levelColorWithBrightnessDelta:0.3 alpha:1.0] imageName:#"replayButton" radius:25 physics:NO delegate:self];
self.menuReplayButton.position=CGPointMake(95,60);
[self.bottomMenuNode addChild:self.menuReplayButton];
NSString *soundImage=[self soundImage];
self.soundButton=[[GameButtonNode alloc]initWithColor:self.level.baseColor strokeColor:[self.level levelColorWithBrightnessDelta:0.3 alpha:1.0] imageName:soundImage radius:25 physics:NO delegate:self];
self.soundButton.position=CGPointMake(155,60);
[self.bottomMenuNode addChild:self.soundButton];
self.bottomMenuNode.position=CGPointMake(0, 0);
self.bottomMenuNode.hidden=YES;
self.bottomMenuNode.xScale=0.1;
self.bottomMenuNode.yScale=0.1;
[self.menuButton addChild:self.bottomMenuNode];
self.menuButton.position=CGPointMake(40,35);
self.menuButton.zPosition=7;
[self addChild:self.menuButton];
}
}
Code for GameBoardNode
-(instancetype) initWithColor:(UIColor *)color strokeColor:(UIColor *) strokeColor imageName:(NSString *)imageName radius:(CGFloat)radius physics:(BOOL)physics delegate:(id<GameButtonNodeDelegate>)delegate {
if (self=[super init]) {
self.strokeColor=strokeColor;
self.ball=[SKShapeNode shapeNodeWithCircleOfRadius:radius];
self.ball.fillColor=color;
self.ball.strokeColor=strokeColor;
self.ball.lineWidth=3.0;
self.ball.zPosition=0;
self.touchDelegate=delegate;
[self addChild:self.ball];
self.icon=[SKSpriteNode spriteNodeWithImageNamed:imageName];
self.icon.size=CGSizeMake(30, 30);
self.icon.zPosition=0;
self.enabled=YES;
[self addChild:self.icon];
if (physics) {
self.physicsBody=[SKPhysicsBody bodyWithCircleOfRadius:radius ];
self.physicsBody.affectedByGravity=YES;
}
self.userInteractionEnabled=YES;
self.fadeIn=[SKAction fadeInWithDuration:0.3];
self.fadeOutRemove=[SKAction sequence:#[[SKAction waitForDuration:0.2],[SKAction fadeOutWithDuration:0.3],[SKAction removeFromParent]]];
}
return self;
}
LEVEL SELECT
The only issue with this view is the background image (blue gradient) appears and then fades away.
The background image is set up in the storyboard.
Most Images are coming from Images.xcassets folder.
All images are png.
Bitcode is off (if that makes a difference)
Any other code or images, just ask.
How can I fix this problem and get my game working properly again?

iOS 9 cares more about zPosition than iOS 8 did. In the past if you didn't set the zPosition iOS8 would do a really good job of assuming what you wanted. In iOS9 it doesn't care and will render it however it wants.
I have also noticed leaving it at zero is also very bad. For instance if you have a node at 0 and add a child with a zPosition of 0...they both are 0 and iOS9 will pick which it should render first. If I am correct this should get your top hud showing back up again.
if (self.topHud == nil) {
self.topHud=[SKShapeNode shapeNodeWithRect:CGRectMake(-2,self.frame.size.height-62,self.frame.size.width+2,64)];
self.topHud.fillColor=[UIColor clearColor];
self.topHud.strokeColor=[UIColor clearColor];
self.topHud.lineWidth=0;
self.topHud.zPosition = 100;//added zPosition
[self addChild:self.topHud];
UIColor *textColor=[self.level textColor];
self.scoreLabel=[SKLabelNode labelNodeWithFontNamed:#"Blow"];
self.scoreLabel.fontSize=20;
self.scoreLabel.alpha = 1;
self.scoreLabel.zPosition = 1;//added zPosition
self.scoreLabel.horizontalAlignmentMode=SKLabelHorizontalAlignmentModeRight;
self.scoreLabel.fontColor=textColor;
self.scoreLabel.position=CGPointMake(self.frame.size.width-8,self.frame.size.height-25);
self.score=0;
[self.topHud addChild:self.scoreLabel];
self.highScoreLabel=[SKLabelNode labelNodeWithFontNamed:#"Blow"];
self.highScoreLabel.fontSize=20;
self.highScoreLabel.alpha = 1;
self.highScoreLabel.horizontalAlignmentMode=SKLabelHorizontalAlignmentModeRight;
self.highScoreLabel.fontColor=textColor;
self.highScoreLabel.position=CGPointMake(self.frame.size.width-8,self.frame.size.height-50);
self.highScoreLabel.zPosition = 1;//added zPosition
//self.highScore=0;
[self.topHud addChild:self.highScoreLabel];
Note 4 zPositions added. I hope that helps get things going in the right direction.

Related

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)];
}
}

UIScrollView with UIImageview and gestures using transitionFromView acting strange

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.

How to add sound while UIScrollview is scrolling in iphone sdk?

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
}

Issue in previewing the video using AVFoundation and MPMovieController at a time in iphone sdk

I am Using AVFoundation's AVCaptureSession to capture the video and I am using the MPMoviePlayerController to play the streamed url(video) from server. When I am capturing only video with AVCaptureSession there is no problem. But When I tried to play the streamed url(with MPMoviePlayerController) along with capturing of video with AVCaptureSession at a time the problem occurs as the capturing from AVCaptureSession stops.
This is what I had done:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication ]delegate];
if([appDelegate isIpad] == YES)
controlsView = [[UIView alloc] initWithFrame:CGRectMake(self.view.bounds.origin.x+200, self.view.bounds.origin.y+250, self.view.bounds.size.width, self.view.bounds.size.height)];
else
controlsView = [[UIView alloc] initWithFrame:self.view.bounds];
controlsView.backgroundColor = [UIColor blackColor];
[self.view addSubview:controlsView];
[self.view sendSubviewToBack:controlsView];
//settingsBtn = [[UIButton alloc]initWithFrame:CGRectMake(10,400, 50, 50)];
settingsBtn = [[UIButton alloc]initWithFrame:CGRectMake(10,400, 50, 50)];
[settingsBtn setImage:[UIImage imageNamed:#"settings.png"] forState:UIControlStateNormal];
[settingsBtn addTarget:self action:#selector(settingsAction) forControlEvents:UIControlEventTouchUpInside];
[controlsView addSubview:settingsBtn];
callButton = [[UIButton alloc]initWithFrame:CGRectMake(260,400, 50, 50)];
if(isCallButtonClicked ==NO)
[callButton setImage:[UIImage imageNamed:#"call.png"] forState:UIControlStateNormal];
else
[callButton setImage:[UIImage imageNamed:#"callEnd.png"] forState:UIControlStateNormal];
[callButton addTarget:self action:#selector(callAction) forControlEvents:UIControlEventTouchUpInside];
[controlsView addSubview:callButton];
statusLabel = [[UILabel alloc]initWithFrame:CGRectMake(120, 20, 150, 40)];
statusLabel.textColor = [UIColor whiteColor];
statusLabel.backgroundColor = [UIColor clearColor];
statusLabel.textAlignment = UITextAlignmentLeft;
statusLabel.font = [UIFont boldSystemFontOfSize:20];
dot1 = [[UIView alloc] initWithFrame:CGRectMake(75, 20, 7, 7)];
dot1.layer.cornerRadius = 5;
dot1.backgroundColor = [UIColor whiteColor];
[statusLabel addSubview:dot1];
dot2 = [[UIView alloc] initWithFrame:CGRectMake(84, 20, 7, 7)];
dot2.layer.cornerRadius = 5;
dot2.backgroundColor = [UIColor whiteColor];
[statusLabel addSubview:dot2];
dot3 = [[UIView alloc] initWithFrame:CGRectMake(93, 20, 7, 7)];
dot3.layer.cornerRadius = 5;
dot3.backgroundColor = [UIColor whiteColor];
[statusLabel addSubview:dot3];
downStreamView = [[UIView alloc]initWithFrame:CGRectMake(controlsView.bounds.origin.x, controlsView.bounds.origin.y, controlsView.bounds.size.width, controlsView.bounds.size.height - 70)];
[[controlsView layer] addSublayer:downStreamView.layer];
downStreamView.layer.backgroundColor = [UIColor greenColor].CGColor;
AVCaptureSession *captureSession = [[AVCaptureSession alloc]init];
NSError *error;
/* getting the device input */
AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:[self frontFacingCamera] error:&error];
if(error)
{
NSLog(#"%#",#"Could not create video input");
}
[captureSession addInput:videoInput];
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:[self audioDevice] error:&error];
[captureSession addInput:audioInput];
audioOutput = [[AVCaptureAudioDataOutput alloc]init];
[captureSession addOutput:audioOutput];
previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:captureSession];
[previewLayer setFrame:CGRectMake(controlsView.bounds.origin.x, controlsView.bounds.origin.y, controlsView.bounds.size.width, controlsView.bounds.size.height - 70)];
[previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[[controlsView layer] addSublayer:previewLayer];
[captureSession startRunning];
}
//make call Action
-(void)makeCallAction
{
if(isCallButtonClicked == NO)
{
statusLabel.text = #"Dialling";
[controlsView addSubview:statusLabel];
if(!isAnimationStarted)
[self animate];
[callButton setImage:[UIImage imageNamed:#"callEnd.png"] forState:UIControlStateNormal];
[UIView animateWithDuration:2.0
animations:^{
CGRect frame = CGRectMake(downStreamView.layer.bounds.origin.x, downStreamView.layer.bounds.size.height-100, 100, 100);
previewLayer.frame = frame;
[downStreamView.layer addSublayer:previewLayer];
}
completion:^(BOOL finished){
//Do nothing
}];
isCallButtonClicked = YES;
}
else if(isCallButtonClicked == YES)
{
[statusLabel removeFromSuperview];
[callButton setImage:[UIImage imageNamed:#"call.png"] forState:UIControlStateNormal];
[UIView animateWithDuration:2.0
animations:^{
[previewLayer setFrame:CGRectMake(controlsView.bounds.origin.x, controlsView.bounds.origin.y, controlsView.bounds.size.width, controlsView.bounds.size.height - 70)];
[[controlsView layer] addSublayer:previewLayer];
}
completion:^(BOOL finished){
//Do nothing
}];
isCallButtonClicked = NO;
}
}
//Settings Action
-(void)settingsAction
{
NSString *nibName = nil;
if ([[[UIDevice currentDevice] model] isEqualToString:#"iPhone"] || [[[UIDevice currentDevice] model] isEqualToString:#"iPhone Simulator"]) {
nibName = #"SettingsViewController";
}
else {
nibName = #"SettingsViewController_iPad";
}
SettingsViewController *settingsController = [[SettingsViewController alloc]initWithNibName:nibName bundle:nil];
[self.navigationController presentModalViewController:settingsController animated:YES];
}
-(void)callAction
{
NSURL *theMovieURL = [NSURL URLWithString:#"someURL.m3u8"];
if (theMovieURL)
{
if ([theMovieURL scheme]) // sanity check on the URL
{
/* Play the movie with the specified URL. */
[self playStreamingURL:theMovieURL];
}
}
[self makeCallAction];
}
-(void)playStreamingURL:(NSURL *)aUrlStr
{
MPMovieSourceType movieSourceType = MPMovieSourceTypeUnknown;
/* If we have a streaming url then specify the movie source type. */
if ([[aUrlStr pathExtension] compare:#"m3u8" options:NSCaseInsensitiveSearch] == NSOrderedSame)
{
movieSourceType = MPMovieSourceTypeStreaming;
}
[self createAndPlayMovieForURL:aUrlStr sourceType:movieSourceType];
}
-(void)createAndPlayMovieForURL:(NSURL *)movieURL sourceType:(MPMovieSourceType)sourceType
{
[self createAndConfigurePlayerWithURL:movieURL sourceType:sourceType];
/* making the player to be visible in full screen mode */
//if(!self.moviePlayerController.fullscreen)
// self.moviePlayerController.fullscreen = YES;
/* disabling the controls of the movie player */
self.moviePlayerController.controlStyle = MPMovieControlStyleNone;
/* Play the movie! */
[[self moviePlayerController] play];
}
-(void)createAndConfigurePlayerWithURL:(NSURL *)movieURL sourceType:(MPMovieSourceType)sourceType
{
[controlsView addSubview:downStreamView];
/* Create a new movie player object. */
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
if (player)
{
/* Save the movie object. */
[self setMoviePlayerController:player];
player.contentURL = MPMovieControlStyleNone;
//if(!player.fullscreen)
// player.fullscreen = YES;
/* Register the current object as an observer for the movie
notifications. */
// [self installMovieNotificationObservers];
/* Specify the URL that points to the movie file. */
[player setContentURL:movieURL];
/* If you specify the movie type before playing the movie it can result
in faster load times. */
[player setMovieSourceType:sourceType];
/* Apply the user movie preference settings to the movie player object. */
//[self applyUserSettingsToMoviePlayer];
/* Add a background view as a subview to hide our other view controls
underneath during movie playback. */
//CGRect viewInsetRect = CGRectInset ([self.view bounds],
// kMovieViewOffsetX,
//kMovieViewOffsetY );
/* Inset the movie frame in the parent view frame. */
[[player view] setFrame:downStreamView.bounds];
[player view].backgroundColor = [UIColor redColor];
/* To present a movie in your application, incorporate the view contained
in a movie player’s view property into your application’s view hierarchy.
Be sure to size the frame correctly. */
[downStreamView.layer addSublayer: [player view].layer];
}
}
-(void)installMovieNotificationObservers
{
MPMoviePlayerController *player = [self moviePlayerController];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(loadStateDidChange:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:player];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(mediaIsPreparedToPlayDidChange:)
name:MPMediaPlaybackIsPreparedToPlayDidChangeNotification
object:player];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackStateDidChange:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:player];
}
/* Notification called when the movie finished playing. */
- (void) moviePlayBackDidFinish:(NSNotification*)notification
{
NSNumber *reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
switch ([reason integerValue])
{
/* The end of the movie was reached. */
case MPMovieFinishReasonPlaybackEnded:
/*
Add your code here to handle MPMovieFinishReasonPlaybackEnded.
*/
break;
/* An error was encountered during playback. */
case MPMovieFinishReasonPlaybackError:
NSLog(#"An error was encountered during playback");
[self performSelectorOnMainThread:#selector(displayError:) withObject:[[notification userInfo] objectForKey:#"error"] waitUntilDone:NO];
[self removeMovieViewFromViewHierarchy];
break;
/* The user stopped playback. */
case MPMovieFinishReasonUserExited:
[self removeMovieViewFromViewHierarchy];
break;
default:
break;
}
}
/* Remove the movie view from the view hierarchy. */
-(void)removeMovieViewFromViewHierarchy
{
MPMoviePlayerController *player = [self moviePlayerController];
[player.view removeFromSuperview];
}
- (void)animate {
isAnimationStarted = YES;
//First Animation
[UIView animateWithDuration:0.5 animations:^{
dot1.alpha = 1;
dot2.alpha = 0.5;
dot3.alpha = 0.5;
} completion:^(BOOL finished) {
//2nd Animation
[UIView animateWithDuration:0.5 animations:^{
dot1.alpha = 0.5;
dot2.alpha = 1;
dot3.alpha = 0.5;
} completion:^(BOOL finished) {
//3rd Animation
[UIView animateWithDuration:0.5 animations:^{
dot1.alpha = 0.5;
dot2.alpha = 0.5;
dot3.alpha = 1;
} completion:^(BOOL finished) {
[self performSelector:#selector(animate)];
}];
}];
}];
}
// Find a camera with the specificed AVCaptureDevicePosition, returning nil if one is not found
- (AVCaptureDevice *) cameraWithPosition:(AVCaptureDevicePosition) position
{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for (AVCaptureDevice *device in devices) {
if ([device position] == position) {
return device;
}
}
return nil;
}
// Find a front facing camera, returning nil if one is not found
- (AVCaptureDevice *) frontFacingCamera
{
return [self cameraWithPosition:AVCaptureDevicePositionFront];
}
// Find a back facing camera, returning nil if one is not found
- (AVCaptureDevice *) backFacingCamera
{
return [self cameraWithPosition:AVCaptureDevicePositionBack];
}
- (AVCaptureDevice *) audioDevice
{
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio];
if ([devices count] > 0) {
return [devices objectAtIndex:0];
}
return nil;
}
-(void)audioData:(id)info
{
NSArray *connections = audioOutput.connections;
AVCaptureConnection *connection = [connections objectAtIndex:0];
NSArray *audioChannels = connection.audioChannels;
AVCaptureAudioChannel *audioChannel = [audioChannels objectAtIndex:0];
//[label setText:[NSString stringWithFormat:#"%f", audioChannel.averagePowerLevel]];
}
Guy's Please help me how to resolve this issue :(
Regards