SKLabelNode sometimes disappear in iOS 9.2 - objective-c

I have a node with a picture of a box added right on top of another node with image of an airship:
SKSpriteNode *box = [SKSpriteNode spriteNodeWithImageNamed:#"Box"];
box.position = airshipNode.position;
box.physicsBody = [SKPhysicBody bodyWithRectangleOfSize:box.size];
box.physicsBody.categoryBitMask = 1;
box.physicsBody.collisionBitMask = 0;
box.zPosition = airship.zPosition - 1;
[box setScale:0.7];
Now I added a label on top of the box:
SKLabelNode *label = [SKLabelNode labelNodeWithFontNamed:#"Arial"];
CGPoint *position = box.centerRect.origin;
position.y -= 55;
label.position = box.centerRect.origin;
label.text = #"a";
label.fontSize = 70;
label.fontColor = [SKColor blackColor];
Then I added the label onto the box and box onto the main scene:
[box addChild:label];
// self is the main scene.
[self addChild:box];
Then I call these code every 1 second. But the label only appears on some of them and the others are just the box, no label. I also added a fade out action for when the box was tapped. But when the fade out animation is going, the label on the box without the text starts to appear. Any ideas on why the label is not appearing on initializations? Thanks.

After a bits of researching, I found iOS 9's Sprite Kit handle default z position a bit different than iOS 8. So by adding this line will make all of the labels appear:
label.zPosition = box.zPosition + 1

Related

How to shrink a rectangular round cornered UIButton to a circular UIButton?

With the help of this i was able to shrink the UIButton but atlast i want the UIButton to get rounded.Please help me to get the desired animation in sign up button. The code snippet is :
Follow the link : https://www.dropbox.com/s/rh4tdub3zabxp2j/shot.gif?dl=0
self.buttonShrink = [CAKeyframeAnimation animationWithKeyPath:#"transform"];
self.buttonShrink.duration = .2f;
self.buttonShrink.values = #[[NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(.9,1,1)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(.8,1,1)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(.7,1,1)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(.6,1,1)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(.5,1,1)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(.4,1,1)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(.3,1,1)]];
self.buttonShrink.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
self.sampleButton.transform = CGAffineTransformMakeScale(0,0);
self.sampleButton.alpha = 1;
[self.sampleButton.layer addAnimation:self.buttonShrink forKey:#"buttonScale"];
[self.sampleButton setUserInteractionEnabled:NO];
I did some tinkering and got pretty decent results.
EDIT:
I just uploaded a demo project to GitHub called MorphingButton (link) that generates the animation below:
Here's what I did:
I created a normal iOS 8 button in IB (no outline at all) and connected an outlet and an action to it.
I added height and width constraints.
I added code to set the borderColor, borderWidth, and cornerRadius of the button's layer to give it a rounded corner look. This would take some adjustment to make it look like a real rounded rectangle button.
In the IBAction for the button, switch back and forth between making it round and making it rectangular.
To make the button round:
Use a UIView animateWithDuration method call to set the button's
height constraint to it's width constraint (making it square) and invoke layoutWithNeeded()
Use aCABasicAnimation to animate the button's layer's corner radius to 1/2
the button width.
To make the button rectangular:
Use a UIView animateWithDuration method call to set the button's
height constraint to it's starting height constraint
Use aCABasicAnimation to animate the button's layer's corner radius to 10 (which looks pretty good for a rounded rectangle button.)
The IBAction and viewDidLoad code would look like this in Objective-C:
- (void)viewDidLoad
{
oldHeight = buttonHeightConstraint.constant;
buttonIsRound = FALSE;
[super viewDidLoad];
animationDuration = 0.5;
}
- (IBAction)handleButton:(id)sender
{
CGFloat newHeight;
CGFloat newCornerRadius;
NSLog(#"Entering %s", __PRETTY_FUNCTION__);
if (buttonIsRound)
{
//If the button is currently round,
//go back to the old height/corner radius
newHeight = oldHeight;
newCornerRadius = 10;
}
else
{
//It isn't round now,
//so make it's height and width the same
//and set the corner radius to 1/2 the width
newHeight = buttonWidthConstraint.constant;
newCornerRadius = buttonWidthConstraint.constant/2;
}
[UIView animateWithDuration: animationDuration
animations:^
{
buttonHeightConstraint.constant = newHeight;
[button layoutIfNeeded];
}];
CABasicAnimation *cornerAnimation = [[CABasicAnimation alloc] init];
cornerAnimation.keyPath = #"cornerRadius";
cornerAnimation.fromValue = #(button.layer.cornerRadius);
cornerAnimation.toValue = #(newCornerRadius);
cornerAnimation.duration = animationDuration;
[button.layer addAnimation: cornerAnimation forKey: #"woof"];
button.layer.cornerRadius = newCornerRadius;
buttonIsRound = !buttonIsRound;
}
The Swift IBAction code for the button looks like this:
#IBAction func handleButton(sender: AnyObject)
{
if !buttonIsRound
{
UIView.animateWithDuration(animationDuration)
{
self.buttonHeightConstraint.constant = self.buttonWidthConstraint.constant
self.button.layoutIfNeeded()
self.buttonIsRound = true
}
let cornerAnimation = CABasicAnimation(keyPath: "cornerRadius")
cornerAnimation.fromValue = button.layer.cornerRadius
cornerAnimation.toValue = self.buttonWidthConstraint.constant / 2.0
cornerAnimation.duration = animationDuration
button.layer.addAnimation(cornerAnimation, forKey: "woof")
button.layer.cornerRadius = self.buttonWidthConstraint.constant / 2.0
}
else
{
UIView.animateWithDuration(animationDuration)
{
self.buttonHeightConstraint.constant = self.oldHeight
self.button.layoutIfNeeded()
self.buttonIsRound = false
}
let cornerAnimation = CABasicAnimation(keyPath: "cornerRadius")
cornerAnimation.fromValue = self.buttonWidthConstraint.constant / 2.0
cornerAnimation.toValue = 10
cornerAnimation.duration = animationDuration
button.layer.addAnimation(cornerAnimation, forKey: "woof")
button.layer.cornerRadius = 10
}
}
I never used this for shrinking but as you are using button layer so why can not you use it cornerRadius. I'm not sure suggestion is ok or not??

UILabel text layout when wrapping is "wrong" in iOS 7

The screen shot below is in iOS 7. label1 (yellow, top) is drawn with the text origin below the top left of the its frame and clipped at the bottom. In iOS 5/6 the text origin is the top left of the label frame. label2 and label3 render and layout as expected.
Here is the code to generate this view:
- (void)loadView
{
UIView *view = [[UIView alloc] initWithFrame:UIScreen.mainScreen.applicationFrame];
view.backgroundColor = UIColor.blueColor;
self.view = view;
UILabel *label1 = [UILabel new];
label1.backgroundColor = UIColor.yellowColor;
label1.font = [UIFont systemFontOfSize:16.0f];
label1.numberOfLines = 0;
label1.lineBreakMode = NSLineBreakByWordWrapping;
label1.frame = CGRectMake(50, 100, 200, 18);
label1.text = #"This text is too long to fit on one line.";
[self.view addSubview:label1];
UILabel *label2 = [UILabel new];
label2.backgroundColor = UIColor.greenColor;
label2.font = [UIFont systemFontOfSize:16.0f];
label2.numberOfLines = 0;
label2.lineBreakMode = NSLineBreakByWordWrapping;
label2.frame = CGRectMake(50, 150, 200, 36);
label2.text = #"This text is too long to fit on one line.";
[self.view addSubview:label2];
UILabel *label3 = [UILabel new];
label3.backgroundColor = UIColor.orangeColor;
label3.font = [UIFont systemFontOfSize:16.0f];
label3.numberOfLines = 0;
label3.lineBreakMode = NSLineBreakByWordWrapping;
label3.frame = CGRectMake(50, 200, 200, 18);
label3.text = #"This text is short.";
[self.view addSubview:label3];
}
QUESTION: Why is this different in iOS 7 and what label properties do I need to change to have the text in label1 render starting from the top left of its frame as expected.
I figured it out. Rather than delete my question, I'll answer it here so if anyone else runs into this they know what to do.
The label frames are hardcoded to specific sizes. In the case of label1, the height is 18. This bound is not tall enough to render a line of text with a system font at 16 points. iOS 5/6 apparently top align the text rect whereas in iOS 7 this causes unpredictable behavior. This fix is to ensure the label bounds are tall enough to display at least one line of text.
The sample code in the question was for the purposes of reproducing this problem. My actual app code calculates label heights based on desired number of lines with various other views positioned around the label so the frame is changed dynamically at run time. I fixed the problem in my app by ensuring the minimum label height can fit a single line of text.

How to show several subviews?

I'm having what I think is a bit of a newbie problem...
I've made a dynamic scroll view where images and labels are programmatically added as subviews. Problem is that only the last one I'm adding as a subview is showing.
Also when I read about "addSubview:" it says "Adds a view to the end of the receiver’s list of subviews." Does this mean only the last added subview is supposed show? In that case how do I make both visible?
Thanks in advance,
Tom
CODE:
for(int i = 0; i < [famorableArray count]; i++){
UIButton *famorableButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[famorableButton setFrame:CGRectMake(0.0f, 5.0f, 57.0f, 57.0f)];
[famorableButton setImage:personLogo forState:UIControlStateNormal];
NSString *famString = [NSString stringWithFormat:#"%#", [[[famorableArray objectAtIndex:i] substringFromIndex:8] capitalizedString]];
NSLog(#"%#", famString);
UILabel *famLabel = [[UILabel alloc] initWithFrame:CGRectZero];
famLabel.text = famString;
NSLog(#"Test2 %#", famLabel.text);
// Move the buttons position in the x-demension (horizontal).
CGRect btnRect = famorableButton.frame;
btnRect.origin.x = totalButtonWidth;
[famorableButton setFrame:btnRect];
CGRect labelRect = famLabel.frame;
labelRect.origin.x = totalButtonWidth + 28.5f;
[famLabel setFrame:btnRect];
// Add the button to the scrollview
[famScroll addSubview:famLabel];
[famScroll addSubview:famorableButton];
// Add the width of the button to the total width.
totalButtonWidth += famorableButton.frame.size.width + 30;
}
[famScroll setContentSize:CGSizeMake(totalButtonWidth, 79.0f)];
For each added subview you have to set the frame property. The frame is the view's position in the superview. "Adding to the list of subviews" does not imply any automatic layout. So I assume that all your subviews are visible but overlap.
My bad... It was a fail editing after copy paste. Accidentally used btnRect as a frame for the label too. Thanks for your effort anyways #Martin :)

How to add text on moving sprites in Cocos2D?

This is my first game in Cocos2D. I am using Cocos2D 1.0.1. I want to add text on moving sprites which should be center aligned. I've taken a CCLabelTTF with a text on it but I cannot make it center aligned. This is what I've done so far:-
-(void)addTarget {
int enType= arc4random() % 11;
CCSprite *target=[CCSprite spriteWithFile:[NSString stringWithFormat:#"balloon%d.png",enType] rect:CGRectMake(0, 0, 100, 119)];
label = [[CCLabelTTF alloc] initWithString:#"H!" dimensions:CGSizeMake([target contentSize].width, [target contentSize].height)
alignment:UITextAlignmentCenter fontName:#"verdana" fontSize:20.0f];
label.color = ccc3(60,60,60);
[target addChild:label z: 10];
// Create the actions
id actionMove = [CCMoveTo actionWithDuration:rangeDuration position:ccp(actualX,winSize.height+target.contentSize.height)];
[target runAction:[CCSequence actions:actionMove, nil]];
//[label setPosition:target.position];
// Add to targets array
[targets addObject:target];
}
Somewhere I've read that adding "[label setPosition:target.position];" in action of sprite will make it center aligned but in vain.
Try setting your label position here instead:
label = [[CCLabelTTF alloc] initWithString:#"H!" dimensions:CGSizeMake([target contentSize].width, [target contentSize].height)
alignment:UITextAlignmentCenter fontName:#"verdana" fontSize:20.0f];
//LABEL POSITION HERE
label.position = ccp(0, 40);
label.color = ccc3(60,60,60);
You may have to play with the position values until you get it where you want.
You don't need to change position of the label, everything is placed based on the center of the image. Also, with this
[target addChild:label z: 10];
try setting the button to z: 11, and keep the label at z:10

Scrolling view like app details screen

I am trying to figure out the best way to create a view like the app details screen in the AppStore app. I want a thumbnail and text content under it that all scrolls if the content is too long. Is this done in a tableview or a scrollview?
I've made one in a scrollview. I calculated the size of each element's frame from this method:
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode
I kept a running total of the y size by adding it on after each label. At the end, if the scroll view was over a certain size (the length of my page) I gave that size to the scroll view, adding a little on the end so it wouldn't bump against the bottom.
Here's some code:
int currentYPos;
CGSize maximumSize = CGSizeMake(300, 9999);
[scrollView setCanCancelContentTouches:NO];
scrollView.indicatorStyle = UIScrollViewIndicatorStyleDefault;
scrollView.clipsToBounds = YES;
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = NO;
// set the title frame size
self.titleLabel.text = self.title;
CGSize titleSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font
constrainedToSize:maximumSize
lineBreakMode:self.titleLabel.lineBreakMode];
currentYPos = titleSize.height + 20;
CGRect titleFrame = CGRectMake(10, 0, 300, currentYPos);
self.titleLabel.frame = titleFrame;
Note that many of the titleLabel properties were set on a label in IB.