Remove labels using WhirlyGlobe - iphone

I am using the (really cool) WhirlyGlobe (https://code.google.com/p/whirlyglobe/) 3D globe display for iPhone in a new application. I can add labels at certain locations using the code shown below. I want to be able to go back and remove a label I added earlier. The Documentation (http://whirlyglobedocs.s3-website-us-east-1.amazonaws.com/html/interface_label_layer.html#ac17e1ec72e70eec416cb2cac833f46fa) shows a removeLabel method but I cannot seem to get it to work. I can add but not remove Labels. I tried looping through all subviews but cannot find these SimpleLabel instances. Can someone please help me understand how to remove a label? I haven't had much luck finding many examples. Thank you!
// Current position
float lat = [[values objectAtIndex:8] floatValue];
flaot lon = [[values objectAtIndex:9] floatValue];
// Create a SingleLabel at this Lat / Lon pair location
SingleLabel *interimLabel = [[[SingleLabel alloc] init] autorelease];
interimLabel.text = [NSString stringWithFormat:#"PRN %d",[[values objectAtIndex:1] intValue]];
[interimLabel setLoc:GeoCoord::CoordFromDegrees(lon, lat)];
[locationArray addObject:interimLabel];
[allLabels addObject:interimLabel];

When you add a single label or a group of labels to the label layer, you'll get back a SimpleIdentity. Keep that around somewhere. Then, when you want to delete the label (or group of labels) from the label layer, you pass back in that SimpleIdentity.
What's going on is this. WhirlyGlobe batches drawable data like a mofo. Your SingleLabel objects no longer exist as soon as the Label Layer has crunched them down into as few Drawables and it can get away with. So to refer to those labels, you have to keep around the unique ID.
Now if you want to delete these labels separately or individually change their appearances, then you've got to add them one by one. One label to one SimpleIdentity. Otherwise there's no way to refer to them individually.
For speed, I recommend grouping as many of them together as you can get away with. If that's just too complex for now, add them one by one and then make a note to come back. So when you say "Why isn't this running as fast as I'd like" you can then say "Ooooo, right."

Related

Objective c - Text indentation

This question is about implementing text indentation ("The placement of text farther to the right to separate it from surrounding text") in iOS.
Take for example the following text:
This is the first section.
This is the second one,
with two lines.
This is the third.
Notice that the second row in section 2 begin farther to the right and just below the line above.
My code contains an array of NSString, each one should be display as a section with numeric bullet like above. for example:
NSArray *array = [NSArray arrayWithObjects:#"1. This is the first section.", #"2. This is the second one, with two lines.", #"3. This is the third.", nil];
I use UILable to display the text on screen.
To set the text from the array to the label, and to separate each string in a new line I use
myLabel.text = [array componentsJoinedByString:#"\n"];
Any ideas how to get this effect?
This is possible to some degree in iOS6 with - [UILabel setAttributedText:].
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.headIndent = 29;
myLabel.attributedText = [[NSAttributedString alloc] initWithString:
#"1.\tShort line.\n2.\tLong line with content that triggers wrapping.\n3.\tShort line."
attributes:#{NSParagraphStyleAttributeName: paragraphStyle}];
This adds indentation to the subsequent lines. It looks like iOS doesn't support tab stops in the same way as OSX so I'm not seeing a way to adjust the gap between the number and the text. This is probably possible in CoreText.
Of course, you could also just replace the label with a UIWebView and have full formatting control on all versions of iOS at the cost of performance.
Well I decided to implement it my self without using Core Text, I just created a view strcture that make all the indentation work by itself, and let you customize it as you want.
For all of you interested in the implementation, you can see the source code and an example project here:
ECListView Project
UILabel is not going to cut it if you have any kind of specific layout requirements. For that, you're going to need to dig into Core Text. The good news is that Core Text will let you do any kind of text layout you can imagine. The bad news is that all that power brings with it some complexity, so to use it you're going to have to invest some time learning how the framework works.
An alternative that's suitable in some situations is to use a web view to display your text. UIWebView will let you do whatever text layout you can manage using HTML and CSS.

Adding and removing annotations from MapView leads to a blink

in my app I'm adding and removing annotations to my map view, but actually even if I first add the new ones and then remove the old ones there is a blink of the annotations
The new annotations are received from the internet and so I can't just remove them from the array of the new ones...
My question is how does it come to the blink behavior and how I can avoid this?
I don't want to iterate through the annotations and compare each's location...
So I tried to delay the remove and ended up at 0.2 seconds. With exactly this delay there is no visible blink, but this isn't desirable at all.
Thanks
NSMutableArray *annotationsToRemove = [[NSMutableArray alloc] initWithArray:[_mapView annotations]];
[annotationsToRemove removeObject:[_mapView userLocation]];
[_mapView addAnnotations:locations];
// [_mapView performSelector:#selector(removeAnnotations:) withObject:annotationsToRemove afterDelay:0.2];
[_mapView removeAnnotations:annotationsToRemove];
("locations" is my array of new annotations)
The blink always happens when adding an annotation just after removing one. If you have control of the web service, add a unique id, check if an annotation with that id already exists on your map and only add a new annotation if it doesn't. If you can't add an id, check using the latitude and longitude (which should probably be unique). Iterating through them won't be expensive.

Update UILabel with Global NSString

In my delegate i have an NSInteger healthInt; and NSMutableString * healthString. In appDelegate.m i have set healthString to hold the changing value of healthInt. Then in a different view i have UILabel * healthLabel. And I have set healthLabel to display healthString with the following code.
healthLabel.text = [NSString stringWithFormat:#"%#", appDelegate.healthString];
This works and displays the number 100, which is what i have set healthInt to in the appDelegate. But when a UIImageView mainSprite collides with a different ImageView healthInt should decrease by two. Which it does, i can tell because i can see it happen in the log. The log may change and display the values of the slowly decreasing healthInt, but the healthLabel doesn't update as healthInt decreases. My question is how can i get this healthLabel to update as healthInt decreases? I have tried just putting in that code for the collision detection between mainSprite and the other ImageView that causes damage but that doesn't seem to work. Thanks!
If you want to get your UILabel to update every time healthInt or healthString changes, there's a couple ways to do this.
One way is to go into the setter method for healthInt (or create one instead of using #synthesize) and broadcast a NSNotification for each time your healthInt number changes. And then when the view with that label is visible, have an observer registered pick up on that notification and make a change to your label.
Another way is to use Key Value Coding & bind the UILabel's text field to healthString. Here is a related question that may help you use this possible solution.

How do I adjust a UIButton relative to its current position?

I'm trying to work with a scroll view controller that needs to adjust it's contents based on user interaction -- specifically, by adding a 'done' button while the user is working with a UITextView, then removing it when they are done. The problem is making room for the button in question. What I'd like to do is...
control.layer.position.x-=50;
for every single control that is 'below' the one I'm working with. Unfortunately, that doesn't work. As far as I can tell, I'm going to have to do something more like...
control.layer.position=CGPointMake(newX, newY);
This creates a maintainability nightmare; instead of being able to rearrange buttons inside UIBuilder at will, I'm going to have to change their positions in the code as well. Unfortunately, no matter what variant of the first type of code I use, the result doesn't work; I'm informed that I need an lvalue to the left of the assign or that I'm trying to manipulate incompatible types.
It'll be more verbose than the -= solution, but why don't you just calculate newX and newY based on their old values?
e.g.
CGPoint oldPosition = control.layer.position;
control.layer.position = CGPointMake(oldPosition.x - 50, oldPosition.y);
The button comes with a center property, so:
button.center = CGPointMake(button.center.x - 50, button.center.y);
should do the trick

Trouble with sprites (loading and removing)-cocos2d iphone

Basically i have an array of Sprites to be loaded and removed one by one in an order.
I have a list of animal names in an array like
const NSString *Animal1[30] = {#"Lion .png",#"Zebra .png",...........
To load a sprite i use the following code
image[i]= [Sprite spriteWithFile: [NSString stringWithFormat:#"%#",Animal1[i]]];
image[i].position = ccp( 240,180 );
[self addChild: image[i]];
Then to remove the sprite after use I use the following code
[self removeChild:image[i] cleanup:YES];
What happens when i run the code in simulator is the sprite loads one after other till 20th animal. After the 20th animals the application crashes.
I dont know what is the problem.If i have the array less than 20 it works fine but when it exceed the application crashes.
Can anyone plz help to resolve the issue.
If it works for the first 20, it sounds like you may have a bad image or an erroneous filename for that 21st image. If you try to create a sprite from an unsupported or nonexistent image, then you'll get a crash.
Check and make sure all the filenames listed are actually inside your package (check case, too, since they're case sensitive!). Make sure the filenames match exactly - in the code sample you pasted above, it looks like there are spaces in the titles.
If the files are all there, make sure you didn't save one of them as a Photoshop document instead of as a .png or something. Even if the filename ends in .png, it doesn't mean that it was saved in that format.
From your description of the problem it could even be a bad index and you're just incrementing out of bounds or something. The best way to clear it up is to do some basic debugging.
place the last item in the middle of
the array. Does it still blow up on
the last one or on the same entry no
mater what position it's in?
remove the offending item to see if
the code works without it
trace thru the code and see the
entry point where it's blowing up,
check your stack trace, etc.
To verify all your files are ok try to load each one manually not using an array like(put a break point on each line and use Build & Debug):
(pseudo code)
add the lion sprite
add the tiger sprite
add the bear sprite
...etc...
If that works then test your array by not using a loop to load the sprites, load each one by calling it's index like(put a break point on each line and use Build & Debug):
(pseudo code)
add image[1]
add image[2]
add image[3]
...etc...
Then if that works fine I would setup your sprites into and array of sprites like:
(pseudo code)
create the sprite with image[i]
add the sprite to spriteArray
---repeat for each sprite---
Then do another loop to add the sprites to the layer like:
CGSize size = [[CCDirector sharedDirector] winSize];
for CCSprite *aSprite in SpriteArray {
aSprite.position = ccp((size.width - (aSprite.contentSize.width / 2)), (aSprite.contentSize.height / 2)); //positions the sprite to the lower right corner
[self addChild aSprite];
}
I like to put my sprites in an array, that way it's easier to just traverse the array when I need to work with them. Also, instead of using absolute coordinates, I like to use coordinates that are relative to the size of the window and the size of the sprite. By positioning them this way, it will convert the coordinates no matter what type of display or orientation or sprite size you are working with.
Hope this helps!