Is it possible to animate a NSTextField - animation

I´m trying a pretty simple thing for testing and can´t get it to work, sorry.
What I want to achieve is that the changes in the textfield label are seen on the screen as well as the color changes.
I already tried several things without success and I´m pretty sure I haven´t got the clue yet.
Any ideas what I´m doing wrong?
I have this right now:
- (IBAction) writeTextToLabel:(id)sender
{
NSAnimation *animation;
[animation setDuration:10];
int n = 100;
NSString *string1 = #"";
[animation startAnimation];
for (int i = 1 ; n >= i ; i++) {
[label setTextColor:[self ccRandom:1.0 :0.0]];
string1 = [NSString stringWithFormat:#"Hello World %.3i\n",i];
[label setStringValue:string1];
}
[animation stopAnimation];
}

You can use AnimTextFieldUsingNSAnimationContext by ipmcc
This code makes fadeIn/fadeOut effect of changing text.
But you can add changing color code after [self setStringValue: aString]; to change your color.
Don't forget to include Quartz.framework to your project.

Related

NSTextView undo/redo attribute changes (when not first responder)

I'm building a basic text editor with custom controls. For my text alignment control, I need to cover two user scenarios:
the text view is the first responder - make the paragraph attribute changes to textView.rangesForUserParagraphAttributeChange
the text view is not the first responder - make the paragraph attribute changes to the full text range.
Here's the method:
- (IBAction)changedTextAlignment:(NSSegmentedControl *)sender
{
NSTextAlignment align;
// ....
NSRange fullRange = NSMakeRange(0, self.textView.textStorage.length);
NSArray *changeRanges = [self.textView rangesForUserParagraphAttributeChange];
if (![self.mainWindow.firstResponder isEqual:self.textView])
{
changeRanges = #[[NSValue valueWithRange:fullRange]];
}
[self.textView shouldChangeTextInRanges:changeRanges replacementStrings:nil];
[self.textView.textStorage beginEditing];
for (NSValue *r in changeRanges)
{
#try {
NSDictionary *attrs = [self.textView.textStorage attributesAtIndex:r.rangeValue.location effectiveRange:NULL];
NSMutableParagraphStyle *pStyle = [attrs[NSParagraphStyleAttributeName] mutableCopy];
if (!pStyle)
pStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[pStyle setAlignment:align];
[self.textView.textStorage addAttributes:#{NSParagraphStyleAttributeName: pStyle}
range:r.rangeValue];
}
#catch (NSException *exception) {
NSLog(#"%#", exception);
}
}
[self.textView.textStorage endEditing];
[self.textView didChangeText];
// ....
NSMutableDictionary *typingAttrs = [self.textView.typingAttributes mutableCopy];
NSMutableParagraphStyle *pStyle = typingAttrs[NSParagraphStyleAttributeName];
if (!pStyle)
pStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[pStyle setAlignment:align];
[typingAttrs setObject:NSParagraphStyleAttributeName forKey:pStyle];
self.textView.typingAttributes = typingAttrs;
}
So both scenarios work fine... BUT undo/redo doesn't work when the change is applied in the 'not-first-responder' scenario. The undo manager pushes something onto its stack (i.e Undo is available in the Edit menu), but invoking undo doesn't change the text. All it does is visibly select the full text range.
How do I appropriately change text view attributes so that undo/redo works regardless of whether the view is first reponder or not?
Thank you in advance!
I'm not sure, but I have two suggestions. One, check the return value from shouldChangeTextInRanges:..., since perhaps the text system is refusing your proposed change; a good idea in any case. Two, I would try to make the not-first-responder case more like the first-responder case in order to try to get it to work; in particular, you might begin by selecting the full range, so that rangesForUserParagraphAttributeChange is then in fact the range that you change the attributes on. A further step in this direction would be to actually momentarily make the textview be the first responder, for the duration of your change. In that case, the two cases should really be identical, I would think. You can restore the first responder as soon as you're done. Not optimal, but it seems that AppKit is making some assumption behind the scenes that you probably just have to work around. Without getting into trying to reproduce the problem and play with it, that's the best I can offer...
The issue is a typo on my part in the code that updates the typingAttributes afterwards. Look here:
//...
NSMutableParagraphStyle *pStyle = typingAttrs[NSParagraphStyleAttributeName];
// ...
Doh! Needs to be really mutable...
//...
NSMutableParagraphStyle *pStyle = [typingAttrs[NSParagraphStyleAttributeName] mutableCopy];
// ...

UITextView setText should not jump to top in ios8

Following iOS 8 code is called every second:
- (void)appendString(NSString *)newString toTextView:(UITextView *)textView {
textView.scrollEnabled = NO;
textView.text = [NSString stringWithFormat:#"%#%#%#", textView.text, newString, #"\n"];
textView.scrollEnabled = YES;
[textView scrollRangeToVisible:NSMakeRange(textView.text.length, 0)];
}
The goal is to have the same scrolling down behaviour as the XCode console when the text starts running off the bottom. Unfortunately, setText causes the view to reset to the top before I can scroll down again with scrollRangeToVisible.
This was solved in iOS7 with the above code and it worked, but after upgrading last week to iOS8, that solution no longer seems to work anymore.
I can't figure out how to get this going fluently without the jumping behaviour?
I meet this problem too. You can try this.
textView.layoutManager.allowsNonContiguousLayout = NO;
refrence:http://hayatomo.com/2014/09/26/1307
The following two solutions don't work for me on iOS 8.0.
textView.scrollEnabled = NO;
[textView.setText: text];
textView.scrollEnabled = YES;
and
CGPoint offset = textView.contentOffset;
[textView.setText: text];
[textView setContentOffset:offset];
I setup a delegate to the textview to monitor the scroll event, and noticed that after my operation to restore the offset, the offset is reset to 0 again. So I instead use the main operation queue to make sure my restore operation happens after the "reset to 0" option.
Here's my solution that works for iOS 8.0.
CGPoint offset = self.textView.contentOffset;
self.textView.attributedText = replace;
[[NSOperationQueue mainQueue] addOperationWithBlock: ^{
[self.textView setContentOffset: offset];
}];
Try just to add text to UITextView (without scrollRangeToVisible/scrollEnabled). It seams that hack with scroll enabled/disabled is no more needed in iOS8 SDK. UITextView scrolls automatically.

SpriteKit - Change Animation at SKPhysicsContact

I am very new to Sprite Kit game development. I am currently developing my first game - a simple game where the player must navigate a simple object past obstacles. If the object collides with an obstacle - GAME OVER.
I got that to work fine but I have been stuck for over a week on an animation problem. I've literally searched for an answer for days now ... without success. So basically ... when my object is being navigated past the obstacles I have one animation pattern (that works fine). Once it hits an obstacle however, I want the animation pattern to change (into an explosion). And for some reason that is NOT HAPPENING! :( It is basically completely IGNORING the two lines of code ([self stopBeeAnimation]; and [self defeatedAnimation];) I added and the game is over right away.
Any help I might get on this, is really appreciated (this is driving me nuts) :)
Thank you so much.
Here my code:
-(void)didBeginContact:(SKPhysicsContact *)contact {
SKSpriteNode *firstSprite;
SKSpriteNode *secondSprite;
firstSprite = (SKSpriteNode *)contact.bodyA.node;
secondSprite = (SKSpriteNode *)contact.bodyB.node;
if ((contact.bodyA.categoryBitMask == beeCategory) && (contact.bodyB.categoryBitMask = obstacleCategory)) {
[self stopBeeAnimation];
[self defeatedAnimation];
[obstacleArray removeAllObjects];
[bee.physicsBody setAffectedByGravity:NO];
[timer invalidate];
scoreLabel.fontSize = 30;
scoreLabel.text = [NSString stringWithFormat:#"GAME OVER %d", score/2];
[self removeFromParent];
SKTransition *transition = [SKTransition fadeWithDuration:5];
[self.scene.view presentScene:[[NPMyScene alloc]initWithSize:self.size] transition:transition];
}}
and:
-(void) defeatedAnimation {
SKAction *defeatedAnimation;
NSMutableArray *textures2 =[NSMutableArray arrayWithCapacity:5];
for (int a = 1; a < 6; a++) {
NSString *textureName2 = [NSString stringWithFormat:#"defeated%d", a];
SKTexture *texture2 = [SKTexture textureWithImageNamed:textureName2];
[textures2 addObject:texture2];
}
defeatedAnimation = [SKAction animateWithTextures:textures2 timePerFrame:0.2];
}
Look here:
SKTransition *transition = [SKTransition fadeWithDuration:5];
[self.scene.view presentScene:[[NPMyScene alloc]initWithSize:self.size] transition:transition];
You're presenting a different scene (or maybe another instance of the same scene class?) in the view after trying to run your animations. Any animation changes in the current scene won't be visible because the new scene replaces the current scene.
But even before that...
- (void)defeatedAnimation {
// ...
defeatedAnimation = [SKAction animateWithTextures:textures2 timePerFrame:0.2];
}
You're creating an SKAction but not doing anything with it. For an action to take effect you need to run it on a node with runAction:.

Creating a label dynamically on a view controller makes it reset in Xcode

I've been searching about the addsubview function and I've found someone saying that the usage of that function actually makes the view controller to reset itself and of course all the previous created objects.
Here is my code:
- (IBAction)CrearEst:(id)sender {
for(int i=0; i< 10; i++)
{
float x = arc4random() %300;
//float x = arc4random() %300;
UILabel *estrella = [[UILabel alloc] initWithFrame:CGRectMake(0, 100, 4, 4)];
estrella.tag = i;
estrella.center = CGPointMake(x,100);
estrella.text = #".";
estrella.textColor = [UIColor whiteColor];
[self.view insertSubview:(estrella) atIndex: 0];
}
}
That works great, but the problem is that, like I said before, all the previous created objects, and it's positions are reseted so when I move my Character and I execute that function, the object come backs to the middle of the screen again and again.
If there's actually another way of doing this I would be pleased to hear it!
SOLUTION: I've find after hours of trying that the solution is to replace "self.view" with "self.view.superview" so you'll have something like this
[self.view.superview insertSubview:(estrella) atIndex: 0]
The usage of "superview" instead of view resolved the problem.
See you!

How to move to the right the label Core Plot?

I use the following method to display the labels for my plot:
-(CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)index{
...
CPTTextLayer *label=[[CPTTextLayer alloc] initWithText:stringValue style:textStyle];
}
which for every index should return the label
I know that it's possible to move label up or down using:
plot.labelOffset=10;
The question is: how can i move the label a bit to the right?
I tried to use
label.paddingLeft=50.0f;
but it doesn't work.
Adding padding as in your example does work, but maybe not in the way you expect. Scatter and bar plots will center the label above each data point (with a positive offset). The padding makes the whole label wider so when centered, the test appears off to the side. It's hard to control, especially if the label texts are different lengths.
There is an outstanding issue to address this (issue 266). No guarantees when it will be fixed, but it is something we're looking at.
I ran into the same problem and came up with a different solution.
What I decided to do was to create the label using the CPTAxisLabel method initWithContentLayer:
CPTTextLayer *textLayer = [[CPTTextLayer alloc] initWithText:labelStr style:axisTextStyle];
CGSize textSize = [textLayer sizeThatFits];
// Calculate the padding needed to center the label under the plot record.
textLayer.paddingLeft = barCenterLeftOffset - textSize.width/2.0;
CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithContentLayer:textLayer];
Here barCenterLeftOffset is the offset of the center of the plot record.
I wrote an article about this:
http://finalize.com/2014/09/18/horizontal-label-positioning-in-core-plot-and-other-miscellaneous-topics/
A demo project I created that uses this solution can be found at:
https://github.com/scottcarter/algorithms
You can subclass CPTTextLayer and include an offset.
#interface WPTextLayer : CPTTextLayer
#property (nonatomic) CGPoint offset;
#end
#implementation WPTextLayer
-(void)setPosition:(CGPoint)position
{
CGPoint p = CGPointMake(position.x + self.offset.x, position.y + self.offset.y);
[super setPosition:p];
}
Then Use:
WPTextLayer *tLayer = [[WPTextLayer alloc] initWithText:#"blah" style:textStyle];
tLayer.offset = CGPointMake(3, -3);
return tLayer;
There may be consequences of this that I'm not aware of, but it seems to be working so far.

Resources