At the moment I have an NSTableView with a custom NSTextFieldCell that holds an NSAttributedString with some ranges with the NSLinkAttribute. I tried to integrate code from Apple's TableViewLinks example and Toomas Vather's HyperlinkTextField.
I implemented the -trackMouse Function like this:
- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag {
BOOL result = YES;
NSUInteger hitTestResult = [self hitTestForEvent:theEvent inRect:cellFrame ofView:controlView];
if ((hitTestResult & NSCellHitContentArea) != 0) {
result = [super trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:flag];
theEvent = [NSApp currentEvent];
hitTestResult = [self hitTestForEvent:theEvent inRect:cellFrame ofView:controlView];
if ((hitTestResult & NSCellHitContentArea) != 0) {
NSAttributedString* attrValue = [self.objectValues objectForKey:#"theAttributedString"];
NSMutableAttributedString* attributedStringWithLinks = [[NSMutableAttributedString alloc] initWithAttributedString:attrValue];
//HOW TO GET A RIGHT INDEX?
NSTableView* myTableView = (NSTableView *)[self controlView];
NSPoint eventPoint = [myTableView convertPoint:[theEvent locationInWindow] fromView:nil];
NSInteger myRow = [myTableView rowAtPoint:eventPoint];
NSRect myBetterViewRect = [myTableView rectOfRow:myRow];
__block NSTextView* myTextView = [[NSTextView alloc] initWithFrame:myBetterViewRect];
[myTextView.textStorage setAttributedString:attributedStringWithLinks];
NSPoint localPoint = [myTextView convertPoint:eventPoint fromView:myTableView];
NSUInteger index = [myTextView.layoutManager characterIndexForPoint:localPoint inTextContainer:myTextView.textContainer fractionOfDistanceBetweenInsertionPoints:NULL];
if (index != NSNotFound)
{
NSMutableArray* myHyperlinkInfos = [[NSMutableArray alloc] init];
NSRange stringRange = NSMakeRange(0, [attrValue length]);
[attrValue enumerateAttribute:NSLinkAttributeName inRange:stringRange options:0 usingBlock:^(id value, NSRange range, BOOL* stop)
{
if (value)
{
NSUInteger rectCount = 0;
NSRectArray rectArray = [myTextView.layoutManager rectArrayForCharacterRange:range withinSelectedCharacterRange:range inTextContainer:myTextView.textContainer rectCount:&rectCount];
for (NSUInteger i = 0; i < rectCount; i++)
{
[myHyperlinkInfos addObject:#{kHyperlinkInfoCharacterRangeKey : [NSValue valueWithRange:range], kHyperlinkInfoURLKey : value, kHyperlinkInfoRectKey : [NSValue valueWithRect:rectArray[i]]}];
}
}
}];
for (NSDictionary* info in myHyperlinkInfos)
{
NSRange range = [[info objectForKey:kHyperlinkInfoCharacterRangeKey] rangeValue];
if (NSLocationInRange(index, range))
{
NSURL* url = [NSURL URLWithString:[info objectForKey:kHyperlinkInfoURLKey]];
[[NSWorkspace sharedWorkspace] openURL:url];
}
}
}
}
}
return result;}
The character-Index when clicking into the cell's (nstextview's) text appears not to fit. So even if there are more than one link in the text, usually the last link is opened. My guess is that I donĀ“t get the nsrect of the clicked cell. If so, how could I get the right NSRect?
I am glad for any suggestions, comments, code pieces - or simpler solutions (even if this would include switching to a view-based tableview).
Thanks.
Related
I have been trying to figure this issue out for days now with no luck, any advice would be greatly appreciated.
I have a uitableviewcontroller that loads data from core data. When the tableview loads, the first 6 (no matter how many objects are actually saved) are loaded. When I begin to scroll down, all of the following cells are labeled "(null)". When I go back up to the top, the data in the original 6 cells are replaced with "(null)". When I logged the contents of the array from the fetch, all of the objects from core data get logged, but when I log the contents of the cell, the first 6 contents get logged, the a long list of rows with (null) get logged.
I've tried a lot of differnet things to debug this, but nothing has worked so far.
Here is the tableviewcontroller file
-(void)viewWillAppear:(BOOL)animated
{
[self setTitle:#"My Safe"];
self.dictionaryWithContent = [[NSMutableDictionary alloc] init];
self.search = #0;
[self fetchDataFromCoreData];
[self.tableView setFrame:CGRectMake(0, 88, self.tableView.bounds.size.width, self.tableView.bounds.size.height)];
self.searchResults = [[NSMutableArray alloc] init];
self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.tableView.bounds.size.width, 44.0f)];
UIBarButtonItem *changeViewsButton = [[UIBarButtonItem alloc] initWithTitle:#"Tweets By User"
style:UIBarButtonItemStylePlain
target:self
action:#selector(switchViewControllers)];
self.navigationItem.rightBarButtonItem = changeViewsButton;
self.tableView.delegate = self;
self.tableView.dataSource = self;
// CGRect searchView = CGRectMake(0, 44, self.tableView.bounds.size.width, 44);
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
[self.searchController loadViewIfNeeded];
self.tableView.tableHeaderView = self.searchController.searchBar;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.searchBar.barTintColor = twitter_blue;
self.searchController.delegate = self;
self.searchController.searchBar.delegate = self;
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated];
self.navigationController.navigationBar.barTintColor = twitter_blue;
self.navigationController.navigationBar.translucent = NO;
self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
[self.navigationController.navigationBar setTitleTextAttributes:#{NSForegroundColorAttributeName : [UIColor whiteColor]}];
}
-(void)fetchDataFromCoreData
{
AppDelegate *del = [[AppDelegate alloc] init];
NSManagedObjectContext *context = del.managedObjectContext;
NSString *entity;
entity = [NSString stringWithFormat:#"Tweet"];
NSFetchRequest *fet = [NSFetchRequest fetchRequestWithEntityName:entity];
NSError *e;
NSArray *array = [context executeFetchRequest:fet error:&e];
self.arrayWithContent = [[NSArray alloc] initWithArray:array];
for (Tweet *t in self.arrayWithContent) {
NSLog(#"array %#", t.messageOfTweet);
}
}
-(void)switchViewControllers
{
PCRSavedTweetByUserTableViewController *vc = [[PCRSavedTweetByUserTableViewController alloc] init];
PCRNavigationBarController *navBarControllerOfSafeSide = [[PCRNavigationBarController alloc] initWithRootViewController:vc];
[self.navigationController presentViewController:navBarControllerOfSafeSide animated:YES completion:nil];
}
#pragma mark Status bar
- (void)willPresentSearchController:(UISearchController *)searchController {
// do something before the search controller is presented
self.navigationController.navigationBar.translucent = YES;
}
-(void)willDismissSearchController:(UISearchController *)searchController
{
self.navigationController.navigationBar.translucent = NO;
searchController = self.searchController;
}
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
searchController = self.searchController;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
self.search = #1;
[self.searchResults removeAllObjects];
NSString *searchBarString = self.searchController.searchBar.text;
for (Tweet *tweet in self.arrayWithContent){
if ([tweet.messageOfTweet containsString:searchBarString] || [tweet.userNameOfTweetUser containsString:searchBarString] || [tweet.whoPosted.name containsString:searchBarString]) {
[self.searchResults addObject:tweet];
}
}
[self.tableView reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
[self.searchController.searchBar resignFirstResponder];
self.search = #0;
[self.tableView reloadData];
}
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
self.searchController.searchBar.text = #"";
}
#pragma mark Table
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
return [self.arrayWithContent count];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 120.0f;
}
- (PCRTweetFeedCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
PCRTweetFeedCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PCRSavedTweetFeedCell"];
PCRTweet *tweetLocal = [[PCRTweet alloc] init];
if (cell == nil) {
cell = [[PCRTweetFeedCell alloc] initWithTweet:tweetLocal reuseIdentifier:#"PCRSavedTweetFeedCell"];
}
Tweet *tweetForIndex;
NSArray *arrayForCell = [[self.arrayWithContent reverseObjectEnumerator] allObjects];
NSArray *searchArrayForCell = [[self.searchResults reverseObjectEnumerator] allObjects];
if ([self.search isEqual:#0]){
tweetForIndex = [arrayForCell objectAtIndex:indexPath.row];
} else if ([self.search isEqual:#1]){
tweetForIndex = [searchArrayForCell objectAtIndex:indexPath.row];
}
NSString *date = [NSString stringWithFormat:#"%#", tweetForIndex.dateOfTweet];
TweetUser *tweetUser = tweetForIndex.whoPosted;
cell.t = tweetForIndex;
UIImage *imageOfTweetUser;
if (tweetUser.profilePicture) {
imageOfTweetUser = [UIImage imageWithData:tweetUser.profilePicture];
} else {
NSURL *urlWithProfilePicture = [NSURL URLWithString:tweetUser.profilePictureURL];
NSData *dataWithPic = [NSData dataWithContentsOfURL:urlWithProfilePicture];
imageOfTweetUser = [UIImage imageWithData:dataWithPic];
}
self.imageOfTweetUserGlobal = imageOfTweetUser;
cell.tweetMessage.text = tweetForIndex.messageOfTweet;
cell.tweetDate.text = date;
cell.tweetUserNameLabel.text = tweetForIndex.userNameOfTweetUser;
cell.profilePictureOfTwitterUserImageView.image = imageOfTweetUser;
cell.nameForPassing = [NSString stringWithFormat:#"%#'s Tweet", tweetUser.name];
return cell;
}
Well maybe this is your problem.
if ([self.search isEqual:#0]){
I think you are initially fetching the data but than once you init the searchController it starts looking for the searchResults.
The code you are looking is:
if ([self.search isActive]){
I found the solution. I changed
AppDelegate *del = [[AppDelegate alloc] init];
NSManagedObjectContext *context = del.managedObjectContext;
to
AppDelegate *del = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context =[del managedObjectContext];
and it works perfectly.
How can I change this UITableViewController custom class to dynamically change the height of the Table View Cells? I have specified different font sizes for the iPad and iPhone size classes.
(This is a continuation of a previous discussion with #rdelmar)
#import "CREWFoodWaterList.h"
#interface CREWFoodWaterList ()
#end
#implementation CREWFoodWaterList
#define VIEW_NAME #"FoodWaterList" // add to database for this view and notes view
#define VIEW_DESCRIPTION #"Food Water - items to keep available" // to add to the database
#define RETURN_NC #"NCSuggestedContentsMenu" // where to return to when complete processing should be specified there
#define NOTES_TITLE #"Food and Water Notes" // pass to notes VC
#define THIS_NC #"NCFoodWaterList" // pass to next VC (so returns to the NC for this view)
- (IBAction)changedSwitch:(UISwitch *)sender {
if (sender.tag == 0) {
[self saveSwitch: #"switchWater" toValue:[NSNumber numberWithBool:sender.on]];
} else if (sender.tag == 1) {
[self saveSwitch: #"switchCanned" toValue:[NSNumber numberWithBool:sender.on]];
} else if (sender.tag == 2) {
[self saveSwitch: #"switchComfort" toValue:[NSNumber numberWithBool:sender.on]];
} else if (sender.tag == 3) {
[self saveSwitch: #"switchSpecial" toValue:[NSNumber numberWithBool:sender.on]];
}
} // end of changedSwitch
-(void)loadSavedSwitches {
// now set the switches to previously stored values
NSNumber *switchValue;
switchValue = [self getSwitch: #"switchWater"];
if ([switchValue intValue] == 0) {
self.switchWater.on = NO;
} else {
self.switchWater.on = YES;
}
self.textWater.text = [self getDescription:#"switchWater"];
switchValue = [self getSwitch: #"switchCanned"];
if ([switchValue intValue] == 0) {
self.switchCanned.on = NO;
} else {
self.switchCanned.on = YES;
}
self.textCanned.text = [self getDescription:#"switchCanned"];
switchValue = [self getSwitch: #"switchComfort"];
if ([switchValue intValue] == 0) {
self.switchComfort.on = NO;
} else {
self.switchComfort.on = YES;
}
self.textComfort.text = [self getDescription:#"switchComfort"];
// self.textComfort.textColor = [UIColor whiteColor];
switchValue = [self getSwitch: #"switchSpecial"];
if ([switchValue intValue] == 0) {
self.switchSpecial.on = NO;
} else {
self.switchSpecial.on = YES;
}
self.textSpecial.text = [self getDescription:#"switchSpecial"];
}
- (void) createNewSwitches {
// set create all switches and set to off
[self newSwitch: #"switchWater" toValue:#"At least three litres of bottle water per person per day"];
[self newSwitch: #"switchCanned" toValue:#"Canned foods, dried goods and staples"];
[self newSwitch: #"switchComfort" toValue:#"Comfort foods"];
[self newSwitch: #"switchSpecial" toValue:#"Food for infants, seniors and special diets"];
}
// COMMON Methods
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 50;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// set font size for table headers
[[UIDevice currentDevice] model];
NSString *myModel = [[UIDevice currentDevice] model];
NSInteger nWords = 1;
NSRange wordRange = NSMakeRange(0, nWords);
NSArray *firstWord = [[myModel componentsSeparatedByString:#" "] subarrayWithRange:wordRange];
NSString *obj = [firstWord objectAtIndex:0];
if ([obj isEqualToString:#"iPad"]) {
[[UILabel appearanceWhenContainedIn:[UITableViewHeaderFooterView class], nil] setFont:[UIFont boldSystemFontOfSize:26]];}
else if ([obj isEqualToString:#"iPhone"]) {
[[UILabel appearanceWhenContainedIn:[UITableViewHeaderFooterView class], nil] setFont:[UIFont boldSystemFontOfSize:16]];
};
[defaults setObject:NOTES_TITLE forKey: #"VCtitle"]; // pass to notes VC
[defaults setObject:VIEW_NAME forKey: #"VCname"]; // pass to notes VC to use to store notes
[defaults setObject:THIS_NC forKey: #"CallingNC"]; // get previous CallingNC and save it for use to return to in doneAction
[self initializeView];
} // end of viewDidLoad
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.tableView reloadData]; // this was necessary to have the cells size correctly when the table view first appeared
}
- (void) initializeView {
CREWAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"View" inManagedObjectContext:context];
NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(viewName = %#)", VIEW_NAME];
[request setPredicate:pred];
NSError *error = nil;
NSArray * objects = [context executeFetchRequest:request error:&error];
if ([objects count] == 0) { // create new view instance
NSManagedObject * newView;
newView = [NSEntityDescription insertNewObjectForEntityForName:#"View" inManagedObjectContext:context];
[newView setValue:VIEW_NAME forKey:#"viewName"];
[newView setValue:VIEW_DESCRIPTION forKey:#"viewDescription"];
// create all switches and set to off
[self createNewSwitches];
}
// load all switches
[self loadSavedSwitches];
} // end of initializeView
// create a new switch
- (void) newSwitch:(NSString*)switchName toValue:(NSString*)switchDescription {
NSError *error = nil;
CREWAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject * newSwitch;
newSwitch = [NSEntityDescription insertNewObjectForEntityForName:#"Switch" inManagedObjectContext:context];
[newSwitch setValue:VIEW_NAME forKey:#"viewName"];
[newSwitch setValue:switchName forKey:#"switchName"];
[newSwitch setValue:switchDescription forKey:#"switchDescription"];
[newSwitch setValue:[NSNumber numberWithInt:0] forKey:#"switchValue"];
if (! [context save:&error])
// NSLog(#"**** START entering %#",VIEW_NAME);
NSLog(#"newSwitch Couldn't save new data! Error:%#", [error description]);
} // end of newSwitch
// read existing switch settings
- (NSNumber *) getSwitch:(NSString*)switchName {
CREWAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"Switch" inManagedObjectContext:context];
NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(viewName = %#) AND (switchName = %#)", VIEW_NAME, switchName];
[request setPredicate:pred];
// Execute Fetch Request
NSManagedObjectContext * matches = nil;
NSError *fetchError = nil;
NSArray *objects = [appDelegate.managedObjectContext executeFetchRequest:request error:&fetchError];
if (fetchError) {
};
NSNumber *switchValue;
if (! [objects count] == 0) {
matches = objects [0];
switchValue = [matches valueForKey : #"switchValue"];
}
return switchValue;
} // end of getSwitch
- (NSString *) getDescription:(NSString*)switchName {
CREWAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"Switch" inManagedObjectContext:context];
NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(viewName = %#) AND (switchName = %#)", VIEW_NAME, switchName];
[request setPredicate:pred];
// Execute Fetch Request
NSManagedObjectContext * matches = nil;
NSError *fetchError = nil;
NSArray *objects = [appDelegate.managedObjectContext executeFetchRequest:request error:&fetchError];
if (fetchError) {
// NSLog(#"**** START entering %#",VIEW_NAME);(#"getSwitch Fetch error:%#", fetchError); // no
};
NSString *switchDescription;
if (! [objects count] == 0) {
matches = objects [0];
switchDescription = [matches valueForKey : #"switchDescription"];
}
return switchDescription;
} // end of getDescription
- (void)saveSwitch:(NSString*)switchName toValue:(NSNumber*)newSwitchValue {
CREWAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"Switch" inManagedObjectContext:context]; // get switch entity
NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"(viewName = %#) AND (switchName = %#)", VIEW_NAME, switchName ];
[request setPredicate:pred];
NSManagedObject *matches = nil;
NSError *fetchError = nil;
NSArray * objects = [context executeFetchRequest:request error:&fetchError];
if (![objects count] == 0) {
matches = objects[0];
}
[matches setValue:newSwitchValue forKey:#"switchValue"];
if (! [context save:&fetchError])
// NSLog(#"**** START entering %#",VIEW_NAME);
NSLog(#"saveSwitch Couldn't save data! Error:%#", [fetchError description]); // perhaps this can be Done later
} // end of saveSwitch
// set alternate cells to different colors
- (UIColor *)getUIColorObjectFromHexString:(NSString *)hexStr alpha:(CGFloat)alpha
{
// Convert hex string to an integer
unsigned int hexint = [self intFromHexString:hexStr];
// Create color object, specifying alpha as well
UIColor *color =
[UIColor colorWithRed:((CGFloat) ((hexint & 0xFF0000) >> 16))/255
green:((CGFloat) ((hexint & 0xFF00) >> 8))/255
blue:((CGFloat) (hexint & 0xFF))/255
alpha:alpha];
return color;
}
// Helper method..
- (unsigned int)intFromHexString:(NSString *)hexStr
{
unsigned int hexInt = 0;
// Create scanner
NSScanner *scanner = [NSScanner scannerWithString:hexStr];
// Tell scanner to skip the # character
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:#"#"]];
// Scan hex value
[scanner scanHexInt:&hexInt];
return hexInt;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *grayishCyan = #"#a3c9ca";
NSString *grayishRed = #"#caa4a3";
UIColor *colorCyan = [self getUIColorObjectFromHexString:grayishCyan alpha:.9];
UIColor *colorPink = [self getUIColorObjectFromHexString:grayishRed alpha:.9];
// // NSLog(#"**** START entering %#",VIEW_NAME);(#"UIColor: %#", colorPink);
if (indexPath.row == 0 || indexPath.row%2 == 0) {
cell.backgroundColor = colorCyan;
}
else {
cell.backgroundColor = colorPink;
}
}
- (IBAction)doneAction:(id)sender {
// NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
UIViewController *viewController = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:RETURN_NC]; // previous Navigation controller
[self presentViewController:viewController animated:YES completion:nil];
};
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
I animate my character like that :
-(void) createHero
{
_batchNode = [CCSpriteBatchNode batchNodeWithFile:#"Snipe1.png"];
[self addChild:_batchNode];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"Snipe1.plist"];
//gather list of frames
NSMutableArray *runAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 7; ++i)
{
[runAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"run000%d.png", i]]];
}
//create sprite and run the hero
self.hero = [CCSprite spriteWithSpriteFrameName:#"run0001.png"];
_hero.anchorPoint = CGPointZero;
_hero.position = self.heroRunningPosition;
//create the animation object
CCAnimation *runAnim = [CCAnimation animationWithFrames:runAnimFrames delay:1/30.0f];
self.runAction = [CCRepeatForever actionWithAction: [CCAnimate actionWithAnimation:runAnim restoreOriginalFrame:YES]];
[_hero runAction:_runAction];
[_batchNode addChild:_hero z:0];
}
This works fine an my character is running, but now i want a second animation when he jumps. At the moment i make it like that:
-(void)changeHeroImageDuringJump
{
[_hero setTextureRect:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"run0007.png"].rect];
}
But now i want a second plist with a second png, so i get a whole new animation when the character jumps. How can i implement that ?
In my case, i implemented an AnimatedSprite class that will handle this for me. This way, I add files like so:
NSDictionary* anims = [NSDictionary dictionaryWithObjectsAndKeys:
#"Animations/Character/idle_anim.plist", #"Idle",
#"Animations/Character/walk_anim.plist", #"Walk",
#"Animations/Character/run_anim.plist", #"Run", nil];
CCNode* myNode = [[AnimatedSprite alloc] initWithDictionary:anims
spriteFrameName: #"character_idle_01.png"
startingIndex:#"Idle"];
Changing the animation is as simple as:
[myNode setAnimation: #"Run"];
Heres my implementation This is the .h
#interface AnimatedSprite : CCSprite
{
NSMutableDictionary* _spriteAnimations;
CCAction* _currentAnimation;
NSString* _currentAnimationName;
bool _initialized;
}
- (id) initWithTextureName:(NSString*) textureName;
- (id) initWithArray: (NSArray*) animList spriteFrameName: (NSString*) startingSprite startingIndex: (int)startingIndex;
- (id) initWithDictionary:(NSDictionary *)anims spriteFrameName:(NSString *)startingSprite startingIndex:(NSString *)startingAnim;
- (void) addAnimation: (NSString*) animationName andFilename: (NSString*) plistAnim;
- (void) setAnimationIndex: (int) index;
- (void) setAnimation: (NSString*) animationName;
#end
And this is the .m
#import "AKHelpers.h"
#implementation AnimatedSprite
NSMutableDictionary* _spriteAnimations;
- (id) initWithTextureName:(NSString*) textureName
{
CCTexture2D* texture = [[CCTextureCache sharedTextureCache] addImage:textureName];
CCSpriteFrame* frame = [CCSpriteFrame frameWithTexture:texture rect: CGRectMake(0, 0, 1, 1)];
if ((self=[super initWithSpriteFrame:frame]))
{
_currentAnimationName = nil;
_currentAnimation = nil;
_spriteAnimations = [[NSMutableDictionary alloc] init ];
_initialized = true;
}
return self;
}
- (id) initWithArray: (NSArray*) animList spriteFrameName: (NSString*) startingSprite startingIndex: (int)startingIndex
{
_initialized = false;
_spriteAnimations = [[NSMutableDictionary alloc] init];
// Add animations as numbers from 0 to animList.count
int i = 0;
for (NSString* anim in animList)
{
[self addAnimation: [NSString stringWithFormat:#"%d", i] andFilename:anim];
i++;
}
if ((self = [super initWithSpriteFrameName:startingSprite]))
{
_currentAnimationName = nil;
_currentAnimation = nil;
[self setAnimationIndex: startingIndex];
_initialized = true;
}
return self;
}
- (id) initWithDictionary:(NSDictionary *)anims spriteFrameName:(NSString *)startingSprite startingIndex:(NSString *)startingAnim
{
_initialized = false;
_spriteAnimations = [[NSMutableDictionary alloc] init];//[[NSMutableArray alloc] init];
// Add animations
for (NSString* key in anims)
{
[self addAnimation: key andFilename: [anims objectForKey: key] ];
}
if ((self = [super initWithSpriteFrameName:startingSprite]))
{
_currentAnimationName = nil;
_currentAnimation = nil;
[self setAnimation: startingAnim];
_initialized = true;
}
return self;
}
- (void) dealloc
{
[_currentAnimationName release];
[_spriteAnimations release];
[super dealloc];
}
- (void) setAnimation: (NSString*) animationName
{
if (![_currentAnimationName isEqualToString:animationName])
{
[_currentAnimationName release];
_currentAnimationName = [animationName copy];
// Stop current animation
if (_currentAnimation != nil)
[self stopAction:_currentAnimation];
//[self stopAllActions];
// Apply animation
NSDictionary* clip = [_spriteAnimations objectForKey: animationName];
if (clip)
{
_currentAnimation = [AKHelpers actionForAnimationClip:clip];
if (_currentAnimation)
[self runAction:_currentAnimation];
}
else
{
_currentAnimation = nil;
}
}
}
- (void) setAnimationIndex: (int) index
{
[self setAnimation: [NSString stringWithFormat:#"%d", index]];
}
- (void) addAnimation: (NSString*) animationName andFilename: (NSString*) plistAnim
{
NSDictionary *clip = [AKHelpers animationClipFromPlist:plistAnim];
if (clip)
{
[_spriteAnimations setObject:clip forKey:animationName];
if (_initialized && [_spriteAnimations count] == 1)
{
[self setAnimation:animationName];
}
}
}
#end
Create two different animation actions for running and jumping. Run those actions on need basis.
I downloaded a dome about UIScorllView and UIPageControl. Why UIPageControl is not display?
Here is the code ,I am new in Iphone .Any help will be appreciated!
ScrollView.M I put the ResultViewController into ScrollView. I want scroll the resultViewController with PageController.
- (void)loadScrollViewWithPage:(int)page
{
if (page < 0)
return;
if (page >= pageNumber)
return;
ResultViewController *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null])
{
controller = [[ResultViewController alloc] initWithPageNumber:page locations:existLocations];
[viewControllers replaceObjectAtIndex:page withObject:controller];
[controller release];
}
if (controller.view.superview == nil)
{
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
existLocations = [FileManagerUtil readPlistFileForDictionary:#"Locations" fileName:#"CloudCheckLocations.plist"];
pageNumber = [existLocations count];
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < pageNumber; i++)
{
[controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
[self.navigationItem setTitle:#"NetWork condition"];
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * pageNumber, scrollView.frame.size.height);
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.scrollsToTop = NO;
scrollView.delegate = self;
pageContronl.numberOfPages = pageNumber;
pageContronl.currentPage = 0;
[pageContronl addTarget:self action:#selector(changePage:) forControlEvents:UIControlEventValueChanged];
[pageContronl setBackgroundColor:[UIColor blackColor]];
[self loadScrollViewWithPage:0];
[self loadScrollViewWithPage:1];
[scrollView addSubview:pageContronl];
[self.view addSubview:scrollView];
}
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
if (pageControlUsed)
{
return;
}
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageContronl.currentPage = page;
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
pageControlUsed = NO;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
pageControlUsed = NO;
}
- (IBAction)changePage:(id)sender
{
int page = pageContronl.currentPage;
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
pageControlUsed = YES;
}
ScrollView.h
#interface ScrollViewController : UIViewController<UIScrollViewDelegate>
{
NSMutableArray *viewControllers;
NSString *currectNetWork;
NSString *flag;
NSString *locationName;
IBOutlet UIScrollView *scrollView;
IBOutlet UIPageControl *pageContronl;
BOOL pageControlUsed;
int pageNumber;
NSMutableDictionary *existLocations;
}
#property (nonatomic,retain) NSString *currectNetWork;
#property (nonatomic,retain) NSString *flag;
#property (nonatomic,retain) NSString *locationName;
#property (nonatomic,retain) UIPageControl * pageContronl;
#property (nonatomic,retain) UIScrollView * scrollView;
#property (nonatomic,retain) NSMutableArray *viewControllers;
#property (nonatomic,retain) NSMutableDictionary *existLocations;
(IBAction)changePage:(id)sender;
ResultViewControl.M
This method will call by ScrollView.M
- (id)initWithPageNumber:(int)page locations :(NSMutableDictionary *) locations
{
titilArray = [[NSArray alloc] initWithObjects:#"Today", #"Past 7 Day",#"Past 30 Day",nil];
if (self = [super initWithNibName:#"ResultViewController" bundle:nil])
{
pageNumber = page;
existLocations = locations;
}
return self;
}
Check the background colour of pageControl and parent view. If both have same colour (default white) page control will not display.
In IOS6, you have new methods pageIndicatorTintColor and currentPageIndicatorTintColor.
Hope this will help.
Check your top and bottom constraints of container view/ tableView(if present). Both must not be attached with Top/Bottom Layout Guide. Attach them with container Margins.
I want to toggle rich text formatting in NSTextView. I have tried following:
[contentView setRichText:NO];
[contentView setImportsGraphics:NO];
but, that didn't changed the NSTextView content and still allowing to do the text formatting.
Please let me know the simple way to toggle/switch rich text formatting in NSTextView just like TextEdit.
I already check the "TextEdit" sample project, but it seems to be very hard to find the usable code from it.
Thanks
Found some help from following link.
click here to see solution
Based on solution given in above link, i have created category for my view controller as follows:
#define TabWidth #"TabWidth"
#interface MyViewController (Helper)
- (NSDictionary *)defaultTextAttributes:(BOOL)forRichText;
- (void)removeAttachments;
- (void)setRichText:(BOOL)flag;
#end
#implementation MyViewController (Helper)
- (NSDictionary *)defaultTextAttributes:(BOOL)forRichText {
static NSParagraphStyle *defaultRichParaStyle = nil;
NSMutableDictionary *textAttributes = [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease];
if (forRichText) {
[textAttributes setObject:[NSFont userFontOfSize:0.0] forKey:NSFontAttributeName];
if (defaultRichParaStyle == nil) { // We do this once...
NSInteger cnt;
NSString *measurementUnits = [[NSUserDefaults standardUserDefaults] objectForKey:#"AppleMeasurementUnits"];
CGFloat tabInterval = ([#"Centimeters" isEqual:measurementUnits]) ? (72.0 / 2.54) : (72.0 / 2.0); // Every cm or half inch
NSMutableParagraphStyle *paraStyle = [[[NSMutableParagraphStyle alloc] init] autorelease];
[paraStyle setTabStops:[NSArray array]]; // This first clears all tab stops
for (cnt = 0; cnt < 12; cnt++) { // Add 12 tab stops, at desired intervals...
NSTextTab *tabStop = [[NSTextTab alloc] initWithType:NSLeftTabStopType location:tabInterval * (cnt + 1)];
[paraStyle addTabStop:tabStop];
[tabStop release];
}
defaultRichParaStyle = [paraStyle copy];
}
[textAttributes setObject:defaultRichParaStyle forKey:NSParagraphStyleAttributeName];
} else {
NSFont *plainFont = [NSFont userFixedPitchFontOfSize:0.0];
NSInteger tabWidth = [[NSUserDefaults standardUserDefaults] integerForKey:TabWidth];
CGFloat charWidth = [#" " sizeWithAttributes:[NSDictionary dictionaryWithObject:plainFont forKey:NSFontAttributeName]].width;
if (charWidth == 0) charWidth = [[plainFont screenFontWithRenderingMode:NSFontDefaultRenderingMode] maximumAdvancement].width;
// Now use a default paragraph style, but with the tab width adjusted
NSMutableParagraphStyle *mStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease];
[mStyle setTabStops:[NSArray array]];
[mStyle setDefaultTabInterval:(charWidth * tabWidth)];
[textAttributes setObject:[[mStyle copy] autorelease] forKey:NSParagraphStyleAttributeName];
// Also set the font
[textAttributes setObject:plainFont forKey:NSFontAttributeName];
}
return textAttributes;
}
/* Used when converting to plain text
*/
- (void)removeAttachments {
NSTextStorage *attrString = [contentView textStorage];
NSUInteger loc = 0;
NSUInteger end = [attrString length];
[attrString beginEditing];
while (loc < end) { /* Run through the string in terms of attachment runs */
NSRange attachmentRange; /* Attachment attribute run */
NSTextAttachment *attachment = [attrString attribute:NSAttachmentAttributeName atIndex:loc longestEffectiveRange:&attachmentRange inRange:NSMakeRange(loc, end-loc)];
if (attachment) { /* If there is an attachment and it is on an attachment character, remove the character */
unichar ch = [[attrString string] characterAtIndex:loc];
if (ch == NSAttachmentCharacter) {
if ([contentView shouldChangeTextInRange:NSMakeRange(loc, 1) replacementString:#""]) {
[attrString replaceCharactersInRange:NSMakeRange(loc, 1) withString:#""];
[contentView didChangeText];
}
end = [attrString length]; /* New length */
}
else loc++; /* Just skip over the current character... */
}
else loc = NSMaxRange(attachmentRange);
}
[attrString endEditing];
}
- (void)setRichText:(BOOL)flag {
NSDictionary *textAttributes;
BOOL isRichText = flag;
if (!isRichText) [self removeAttachments];
[contentView setRichText:isRichText];
[contentView setUsesRuler:isRichText]; /* If NO, this correctly gets rid
of the ruler if it was up */
if (isRichText && NO)
[contentView setRulerVisible:YES]; /* Show ruler if rich, and desired */
[contentView setImportsGraphics:isRichText];
textAttributes = [self defaultTextAttributes:isRichText];
if ([[contentView textStorage] length]) {
[[contentView textStorage] setAttributes:textAttributes range: NSMakeRange(0,[[contentView textStorage] length])];
}
[contentView setTypingAttributes:textAttributes];
}
#end
Where contentView is IBOutlet of NSTextView. Hope this will help someone or let me know if someone has shorter method.
Thanks