Can someone please explain to me why my variable called activity is 0 when defined as a float, but displays the correct value when defined as an int? I have another float which is used for pretty much the same thing but works perfectly!
#implementation AppPrefsViewController
float age;
int activity;
...
-(void) updateAValues{
if (selectedActivityUnit == 0){
activity = 50;
NSLog(#"activity = %d",activity);
}
if (selectedActivityUnit == 1){
activity = 75;
NSLog(#"activity = %d",activity);
}
}
....
- (void)updateLabel {
if (selectedUnit == 0) {
subView.hidden = YES;
age = 1;
NSLog(#"age = %d",age);
}
if (selectedUnit == 1) {
subView.hidden = YES;
age = 2;
NSLog(#"age = %d",age);
}
if (selectedUnit == 2) {
subView.hidden = NO;
age = 3;
NSLog(#"age = %d",age);
}
}
You're using
NSLog(#"activity = %d", activity);
To display your values. This works if activity is an int type as %d is for displaying ints. If you want to display floats you need the float formater %f, as in:
NSLog(#"activity = %f", activity);
Related
I have a calculator in which i would like to put the decimal point according to the button press for the decimal point. I get the decimal point but if I enter another digit the decimal pint vanishes and is overwritten .
The code is mentioned below for the decimal press:-
-(IBAction)decimalPressed:(id)sender{
calculatorScreen.text = [calculatorScreen.text stringByAppendingString:#"."];
}
For the digit press it is :-
-(IBAction)buttonDigitPressed:(id)sender{
currentNumber = currentNumber*10 + (float)[sender tag];
calculatorScreen.text = [NSString stringWithFormat:#"%g",currentNumber];
}
How can i do something like 23 then "." then 45. The result would be 23.45
I've recently done a calculator app and could understand your problem. Another thing you want to take note about the point is that you do not want to have multiple point in your calculation, e.g. 10.345.1123.5. Simply put, you want it to be a legal float number as well.
With that said, you can use a IBAction (remember to link it to your storyboard or xib file)
-(IBAction)decimalPressed:(UIButton *)sender
{
NSRange range = [self.display.text rangeOfString:#"."];
if (range.location ==NSNotFound){
self.display.text = [ self.display.text stringByAppendingString:#"."];
}
self.userIsInTheMiddleOfEnteringANumber = YES;
}
While it might be possible we are doing on the same project, it could also be entirely different (you starting from scratch by yourself) so i will go through some of the codes
you could replace UIButton with the default id, but it is better to static replace it to make clear clarification for yourself, or anyone else who view your code.
NSRange as the name implies, mark the range, and the range will be ur display text of calculation (e.g. 1235.3568), and the range of string it is targeting in this case is "."
therefore, if NSNotfound (rangeOfString "." is not found in the text range) you will append the current display text with "." with the function stringByAppendingString:#".", there is no else, so no function will take place if "." is already found, which solve the problem of multiple point on the display.
userIsInTheMiddleOfEnteringANumber is a BOOL to solve the problem of having 0 in ur display (e.g. 06357), if you have a method to change it, then replace my method name with your own.
Try with below code:
-(IBAction)buttonDigitPressed:(id)sender
{
UIButton *pressedButton = (UIButton *)sender;
calculatorScreen.text = [calculatorScreen.text stringByAppendingFormat:#"%d",pressedButton.tag];
currentNumber = [calculatorScreen.text floatValue];
}
-(IBAction)ButtonDot
{
decimalChecker = 10;
calculatorScreen.text = [NSString stringWithFormat:#"$ %g.", currentSavings];
decimalChecker=1;
}
-(IBAction)buttonDigitPressed:(id)sender
{
if (decimalChecker ==1)
{
currentDecimal = currentDecimal*10 + (float)[sender tag];
calculatorScreen.text = [NSString stringWithFormat:#"$ %g.%g", currentSavings,currentDecimal];
}
else
{
currentSavings = currentSavings*10 + (float)[sender tag];
calculatorScreen.text = [NSString stringWithFormat:#"$ %g",currentSavings];
}
}
This is my solution:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
float result;
IBOutlet UILabel *TextInput;
int currentOperation;
float currentNumber;
BOOL userInTheMiddleOfEnteringDecimal;
}
- (IBAction)buttonDigitPressed:(id)sender;
- (IBAction)buttonOperationPressed:(id)sender;
- (IBAction)cancelInput;
- (IBAction)cancelOperation;
- (IBAction)dotPressed;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (IBAction)buttonDigitPressed:(id)sender {
if(!userInTheMiddleOfEnteringDecimal)
{
currentNumber = currentNumber*10 + (float)[sender tag];
TextInput.text = [NSString stringWithFormat:#"%d",(int)currentNumber];
}
else{
TextInput.text= [TextInput.text stringByAppendingString:[NSString stringWithFormat:#"%d",[sender tag]]];
currentNumber = [TextInput.text floatValue];
}
}
- (IBAction)buttonOperationPressed:(id)sender {
if (currentOperation == 0) result = currentNumber;
else {
switch (currentOperation) {
case 1:
result = result + currentNumber;
break;
case 2:
result = result - currentNumber;
break;
case 3:
result = result * currentNumber;
break;
case 4:
result = result / currentNumber;
break;
case 5:
currentOperation = 0;
break;
default:
break;
}
}
currentNumber = 0;
TextInput.text = [NSString stringWithFormat:#"%.2f",result];
if ([sender tag] == 0) result = 0;
currentOperation = [sender tag];
userInTheMiddleOfEnteringDecimal = NO;
}
-(IBAction)cancelInput{
currentNumber = (int)(currentNumber/10);
TextInput.text = [NSString stringWithFormat:#"%.2f",currentNumber];;
}
-(IBAction)cancelOperation{
currentNumber = 0;
TextInput.text = #"0";
userInTheMiddleOfEnteringDecimal = NO;
}
- (IBAction)dotPressed{
if(!userInTheMiddleOfEnteringDecimal){
userInTheMiddleOfEnteringDecimal = YES;
TextInput.text= [TextInput.text stringByAppendingString:#"."];
}
}
#end
Hope this helps.. Another way of solution...
after pressing the "." all values after will be divided as following
the first number ur press after pressing "." will be divided by 10 the second by 100 and so on
so editing ur function it would be like this
-(IBAction)buttonDigitPressed:(id)sender{
currentNumber = currentNumber + (float)[sender tag] / 10.0;
calculatorScreen.text = [NSString stringWithFormat:#"%g",currentNumber];
}
i think in that solve your problem
http://www.datasprings.com/resources/articles-information/iphone-sdk-getting-started-example-code
There is sample code of calculator.
As My Screen shot show that i am working on word matching game.In this game i assign my words to different UIButtons in Specific sequence on different loctions(my red arrow shows this sequence)and of rest UIButtons i assign a one of random character(A-Z).when i Click on any UIButtons its title will be assign to UILabel which is in Fornt of Current Section:i campare this UILabel text to below UILabels text which is in fornt of timer.when it match to any of my UILabels its will be deleted.i implement all this process already.
But my problem is that which is show by black lines.if the player find the first word which is "DOG". he click the Two UIButtons in Sequence,but not press the Third one in Sequence.(as show by black line).so here i want that when player press the any UIButtons which is not in Sequence then remove the previous text(which is "DO") of UILabel and now the Text of UILabel is only "G" .
Here is my code to get the UIButtons titles and assign it UILabel.
- (void)aMethod:(id)sender
{
UIButton *button = (UIButton *)sender;
NSString *get = (NSString *)[[button titleLabel] text];
NSString *origText = mainlabel.text;
mainlabel.text = [origText stringByAppendingString:get];
if ([mainlabel.text length ]== 3)
{
if([mainlabel.text isEqualToString: a]){
lbl.text=#"Right";
[btn1 removeFromSuperview];
score=score+10;
lblscore.text=[NSString stringWithFormat:#"%d",score];
words=words-1;
lblwords.text=[NSString stringWithFormat:#"%d",words];
mainlabel.text=#"";
a=#"tbbb";
}
else if([mainlabel.text isEqualToString: c]){
lbl.text=#"Right";
[btn2 removeFromSuperview];
score=score+10;
lblscore.text=[NSString stringWithFormat:#"%d",score];
words=words-1;
lblwords.text=[NSString stringWithFormat:#"%d",words];
mainlabel.text=#"";
c=#"yyyy";
}
else
if([mainlabel.text isEqualToString: d]){
lbl.text=#"Right";
[btn3 removeFromSuperview];
score=score+10;
lblscore.text=[NSString stringWithFormat:#"%d",score];
words=words-1;
lblwords.text=[NSString stringWithFormat:#"%d",words];
mainlabel.text=#"";
d=#"yyyy";
}
else {
lbl.text=#"Wrong";
mainlabel.text=#"";
}
}}
Thanx in advance
Assign tag to each button from left to right.
So you will have,
GButton.tag = 0;
TButton.tag = 1;
DButton.tag = 2;
.
.
.
VButton.tag = 9;
.
.
.
EButton.tag = 18;
.
.
.
CButton.tag = 26;
Now keep the track of previous pressed button and current pressed button.
Call below function when your button delegate hits:
Write below code into your .h file
#define SEQ_TYPE_ANY 0
#define SEQ_TYPE_RIGHT 1
#define SEQ_TYPE_LEFT 2
#define SEQ_TYPE_TOP 3
#define SEQ_TYPE_BOTTOM 4
#define SEQ_TYPE_RIGHT_DIAGONAL_DOWN 5
#define SEQ_TYPE_RIGHT_DIAGONAL_UP 6
#define SEQ_TYPE_LEFT_DIAGONAL_DOWN 7
#define SEQ_TYPE_LEFT_DIAGONAL_UP 8
#define NO_OF_BUTTONS_IN_ROW 9
//Add below variables into your class
int curentSequence;
UILabel *resultLabel;
UIButton *previousButton;
//Declare property for previousButton
#property(nonatomic, retain) UIButton *previousButton;
//Write below code to .m file
#synthesize previousButton;
-(BOOL) isAdjacent:(UIButton *)currentButton
{
if(previousButton == nil)
{
resultLabel.text = currentButton.titleLabel.text;
curentSequence = SEQ_TYPE_ANY;
return TRUE;
}
if((curentSequence == SEQ_TYPE_ANY || curentSequence == SEQ_TYPE_RIGHT) &&
(previousButton.tag + 1 == currentButton.tag))
{
resultLabel.text = [resultLabel.text stringByAppendingString:currentButton.titleLabel.text];
curentSequence = SEQ_TYPE_ANY;
return TRUE;
}
else if((curentSequence == SEQ_TYPE_ANY || curentSequence == SEQ_TYPE_LEFT) &&
(previousButton.tag - 1 == currentButton.tag))
{
resultLabel.text = [resultLabel.text stringByAppendingString:currentButton.titleLabel.text];
curentSequence = SEQ_TYPE_LEFT;
return TRUE;
}
else if((curentSequence == SEQ_TYPE_ANY || curentSequence == SEQ_TYPE_TOP) &&
(previousButton.tag - NO_OF_BUTTONS_IN_ROW == currentButton.tag))
{
resultLabel.text = [resultLabel.text stringByAppendingString:currentButton.titleLabel.text];
curentSequence = SEQ_TYPE_TOP;
return TRUE;
}
else if((curentSequence == SEQ_TYPE_ANY || curentSequence == SEQ_TYPE_BOTTOM) &&
(previousButton.tag + NO_OF_BUTTONS_IN_ROW == currentButton.tag))
{
resultLabel.text = [resultLabel.text stringByAppendingString:currentButton.titleLabel.text];
curentSequence = SEQ_TYPE_BOTTOM;
return TRUE;
}
else if((curentSequence == SEQ_TYPE_ANY || curentSequence == SEQ_TYPE_RIGHT_DIAGONAL_DOWN) &&
(previousButton.tag + NO_OF_BUTTONS_IN_ROW + 1 == currentButton.tag))
{
resultLabel.text = [resultLabel.text stringByAppendingString:currentButton.titleLabel.text];
curentSequence = SEQ_TYPE_RIGHT_DIAGONAL_DOWN;
return TRUE;
}
else if((curentSequence == SEQ_TYPE_ANY || curentSequence == SEQ_TYPE_RIGHT_DIAGONAL_UP) &&
(previousButton.tag - NO_OF_BUTTONS_IN_ROW + 1 == currentButton.tag))
{
resultLabel.text = [resultLabel.text stringByAppendingString:currentButton.titleLabel.text];
curentSequence = SEQ_TYPE_RIGHT_DIAGONAL_UP;
return TRUE;
}
else if((curentSequence == SEQ_TYPE_ANY || curentSequence == SEQ_TYPE_LEFT_DIAGONAL_UP) &&
(previousButton.tag - NO_OF_BUTTONS_IN_ROW - 1 == currentButton.tag))
{
resultLabel.text = [resultLabel.text stringByAppendingString:currentButton.titleLabel.text];
curentSequence = SEQ_TYPE_LEFT_DIAGONAL_UP;
return TRUE;
}
else if((curentSequence == SEQ_TYPE_ANY || curentSequence == SEQ_TYPE_LEFT_DIAGONAL_DOWN) &&
(previousButton.tag + NO_OF_BUTTONS_IN_ROW - 1 == currentButton.tag))
{
resultLabel.text = [resultLabel.text stringByAppendingString:currentButton.titleLabel.text];
curentSequence = SEQ_TYPE_LEFT_DIAGONAL_DOWN;
return TRUE;
}
else
{
resultLabel.text = #"";
curentSequence = SEQ_TYPE_ANY;
return FALSE;
}
}
// Event handler for button event
- (void)aMethod:(id)sender
{
UIButton *currentButton = (UIButton *)sender;
BOOL result = [self isAdjacent:currentButton];
if(result == FALSE)
{
self.previousButton = nil;
resultLabel.text = #"";
curentSequence = SEQ_TYPE_ANY;
}
else
{
self.previousButton = sender;
}
}
Hope it will help.
If I understand correctly, you need to know if the pushed button is adjacent to the previously pushed button? Use this function to test for adjacency in the grid:
bool isAdjacent(UIButton* current, UIButton* previous) {
if( !previous )
return false;
//Create a rectangle around the previous button (assuming all buttons are in a fixed grid)
CGRect previousRect = previous.frame;
CGRect adjacentRect = CGRectMake(previous.frame.origin.x - previous.frame.size.width,
previous.frame.origin.y - previous.frame.size.height,
previous.frame.size.width*3,
previous.frame.size.height*3);
return CGRectIntersectsRect(adjacentRect, previousRect);
}
And only append if they are adjacent, ie:
- (void)aMethod:(id)sender
{
UIButton *button = (UIButton *)sender;
static UIButton* previous = nil;
NSString *get = (NSString *)[[button titleLabel] text];
NSString *origText = mainlabel.text;
if( isAdjacent(button, previous) )
mainlabel.text = [origText stringByAppendingString:get];
previous = button;
//Rest of function
}
Fun question:
In this particular case, I agree with Luke about subclassing the UIButton. This way you could give each button an (X, Y) on your grid, as well as a (Xnext, Ynext) list for all of the possible expected next press locations (if the button itself can be used to make multiple words). Externally you will compare the currently being hit against the expected (Xnext, Ynext). If the two dont match, this is the signal you are looking for.
This is an answer that accounts for all of your situations, forward and backward horizontal (if you choose to implement backware), upward and downward vertical (if you choose to implement upward), and any diagonal, or any other combination you can come up with!
This also accounts for lets say hitting the D, then the O then trying to press the D again versus hitting the G. It also takes care of hitting the incorrect G.
Create a new .m .h pair of files (a new object) and give it your name.
Some example code for implementing a custom UIButton (h file):
#interface myConnectedUIButton : UIButton {
BOOL isAWordBeginCharacter;
unsigned int beginWordKey;
unsigned int myGridX;
unsigned int myGridY;
NSMutableArray * myConnectedSet;
}
-(id)init;
-(void)initWithGridX:(unsigned int)X GridY:(unsigned int)Y BeginChar:(BOOL)yesNo BeginWordKey:(unsigned int)key;
-(void)setGridPosWithX:(unsigned int)X Y:(unsigned int)Y;
-(void)setGridX:(unsigned int)X;
-(void)setGridY:(unsigned int)Y;
-(unsigned int)getGridX;
-(unsigned int)getGridY;
-(void)setIsABeginChar:(BOOL)yesNo;
-(BOOL)getIsABeginChar;
-(void)addPosToConnectedSetGridX:(unsigned int)X GridY:(unsigned int)Y WordKey:(unsigned int)key;
-(NSArray *)getMyConnectedSetArray;
-(void)clearConnectedSet;
#end
In the .m file of your
#implementation myConnectedUIButton
-(id)init{
[super init];
// Lets go ahead and initialize the NSMutableArray here also IFF it hasnt already been allocated
if( nil == myConnectedSet ){
myConnectedSet = [[NSMutableArray alloc] init];
}
// Lets also zero out the x, y position
myGridX = 0;
myGridY = 0;
// Lets also state that this is NOT a begin char for the time being and 0 for the begin char key
isAWordBeginCharacter = NO;
beginWordKey = 0;
return self;
}
-(void)initWithGridX:(unsigned int)X GridY:(unsigned int)Y BeginChar:(BOOL)yesNo BeginWordKey:(unsigned int)key{
// Lets go ahead and initialize the NSMutableArray here also IFF it hasnt already been allocated
if( nil == myConnectedSet ){
myConnectedSet = [[NSMutableArray alloc] init];
}
myGridX = X;
myGridY = Y;
isAWordBeginCharacter = yesNo;
beginWordKey = key;
}
-(void)setGridPosWithX:(unsigned int)X Y:(unsigned int)Y{
myGridX = X;
myGridY = Y;
}
-(void)setGridX:(unsigned int)X{
myGridX = X;
}
-(void)setGridY:(unsigned int)Y{
myGridY = Y;
}
-(unsigned int)getGridX{
return myGridX;
}
-(unsigned int)getGridY{
return myGridY;
}
-(void)setIsABeginChar:(BOOL)yesNo{
isAWordBeginCharacter = yesNo;
}
-(BOOL)getIsABeginChar{
return isAWordBeginCharacter;
}
-(void)addPosToConnectedSetGridX:(unsigned int)X GridY:(unsigned int)Y WordKey:(unsigned int)key{
[myConnectedSet addObject:[GridPointNext GridPointNextWithX:X GridPointY:Y NextWordKey:key]];
}
-(NSArray *)getMyConnectedSetArray{
return myConnectedSet;
}
-(void)clearConnectedSet{
[myConnectedSet removeAllObjects];
}
-(void)dealloc{
[myConnectedSet release];
[super dealloc];
}
#end
You will also now need a "GridPointNext" object.
The Grid Object header should look as follows:
#interface GridPointNext : NSObject {
unsigned int GridPointX;
unsigned int GridPointY;
unsigned int nextWordKey;
}
+(GridPointNext *)GridPointNextWithX:(unsigned int)X GridPointY:(unsigned int)Y NextWordKey:(unsigned int)key;
-(id)initWithX:(unsigned int)X GridPointY:(unsigned int)Y NextWordKey:(unsigned int)key;
-(unsigned int)getGridX;
-(unsigned int)getGridY;
-(unsigned int)getNextWordKey;
#end
The m file for the object should look as follows:
#implementation GridPointNext
+(GridPointNext *)GridPointNextWithX:(unsigned int)X GridPointY:(unsigned int)Y NextWordKey:(unsigned int)key{
GridPointNext * aPoint = [[GridPointNext alloc] initWithX:X GridPointY:Y NextWordKey:key];
[aPoint autorelease];
return aPoint;
}
-(id)initWithX:(unsigned int)X GridPointY:(unsigned int)Y NextWordKey:(unsigned int)key{
GridPointX = X;
GridPointY = Y;
nextWordKey = key;
return self;
}
-(unsigned int)getGridX{
return GridPointX;
}
-(unsigned int)getGridY{
return GridPointY;
}
-(unsigned int)getNextWordKey{
return nextWordKey;
}
#end
You will have to deal with the dealloc portion. This at least give you some tools for creating your custom button and your word list algorithm around it.
If I understand correctly. The user can only have a correct word, if the letters chosen are all sitting next to each other?
Have you tried this:
Keep two references. One UIButton for previousPressedButton and one UIButtonfor lastPressedButton.
First a user presses D. lastPressedButton will refer to the D.
Then a user presses O. previousPressedButton will be D. lastPressedButton will be O.
Now, get the width and height of the UIButtons and compare if the lastPressedButton.frame.origin.x will be less than width or -width away.
Also check if the lastPressedButton.frame.origin.y will be less than height or -height away.
Now you know if it's touching the previous button. Use this to decide if it's a new word or not.
I would put this into a method.
-(BOOL)isAdjacentLetter {
float buttonWidth = lastPressedButton.size.width;
float buttonHeight = lastPressedButton.size.height;
if(lastPressedButton.frame.origin.x>previousPressedButton.frame.origin.x+buttonWidth) return NO;
if(lastPressedButton.frame.origin.y>previousPressedButton.frame.origin.y+buttonHeight) return NO;
if(lastPressedButton.frame.origin.x<previousPressedButton.frame.origin.x-buttonWidth) return NO;
if(lastPressedButton.frame.origin.y<previousPressedButton.frame.origin.y-buttonHeight) return NO;
return YES;
}
Then whenever a button is clicked. you can use
if ([self isAdjacentLetter]) {
//still same word
} else {
//new word. erase
}
Or, if I understand differently. The words can only be made when the letters are in a row.Such as : From left to right. From down to up. From bottom right to top left etc.
In this case, determine all directions.
Such as, top left is 0, top is 1, top right is 2. right is 3. down right is 4. down is 5. down left is 6. left is 7.
When two buttons are clicked, store the directions. For example:
If it's from left to right, direction = 3;
Then when another button is clicked, check the new direction. If it's 3, the word is still in the same direction. if it's something else, then erase and start over.
Hope this helps.
My game center achievements are appearing in Game Center, so I know my implementation is correct in reporting.
Couple of questions on that.
First, in Game Center it is not showing the percentage view on the image... ie 2% complete next to the achievement, even though I have reported .02. I know the achievement is being reported because if I throw the 100 at it, it records the achievement.
Second, my achievements are not appearing to the user upon reward. As I understood, this functionality was suppose to be handled automatically by gamekit. I was under the impression the the small modal would appear letting the user know they completed an achievement. I now think there is something I have to do, because no small modal is appearing.
I will attach my code, but most of it stock.
My last problem is retrieving scores. I believe I am going to have to store my own scores because my current implementation does not look like it will mesh well.
Thanks in advance...
- (void) loadAchievements
{ [GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) {
if (error != nil)
{
// handle errors
}
if (achievements != nil)
{
// process the array of achievements.
}
}];
}
-(float)getAchievementPercentageForIdentifier:(NSString *)identifier {
__block float percentage = 0;
[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) {
if (error != nil)
{
// handle errors
}
if (achievements != nil)
{
// process the array of achievements.
for (GKAchievement *achievement in achievements) {
if ([achievement.identifier isEqualToString:identifier]) {
percentage = achievement.percentComplete;
NSLog(#"percent complete --> %f", achievement.percentComplete);
}
}
}
}];
NSLog(#"Percentage --> %f", percentage);
return percentage;
}
- (void) reportAchievementIdentifier: (NSString*) identifier percentComplete: (float) percent
{
GKAchievement *achievement = [[[GKAchievement alloc] initWithIdentifier: identifier] autorelease];
if (achievement)
{
achievement.percentComplete = percent;
[achievement reportAchievementWithCompletionHandler:^(NSError *error)
{
if (error != nil)
{
// Retain the achievement object and try again later (not shown).
}
}];
}
}
-(void) addCompletedGameToAchievements {
float oneGamePercentage = 0;
float tenGamePercentage = 0;
float fiftyGamePercentage = 0;
float hundredGamePercentage = 0;
float fivehundredGamePercentage = 0;
float thousandGamePercentage = 0;
int gamesComplete = 0;
oneGamePercentage = [self getAchievementPercentageForIdentifier:kAchievementGamesCompletedOne];
tenGamePercentage = [self getAchievementPercentageForIdentifier:kAchievementGamesCompletedTen];
fiftyGamePercentage = [self getAchievementPercentageForIdentifier:kAchievementGamesCompletedFifty];
hundredGamePercentage = [self getAchievementPercentageForIdentifier:kAchievementGamesCompletedHundred];
fivehundredGamePercentage = [self getAchievementPercentageForIdentifier:kAchievementGamesCompletedFivehundred];
thousandGamePercentage = [self getAchievementPercentageForIdentifier:kAchievementGamesCompletedThousand];
if (oneGamePercentage != 100) {
[self reportAchievementIdentifier:kAchievementGamesCompletedOne percentComplete:100];
}
if (tenGamePercentage != 100) {
gamesComplete = tenGamePercentage * 10;
gamesComplete++;
[self reportAchievementIdentifier:kAchievementGamesCompletedTen percentComplete:(gamesComplete * .10)];
}
if (fiftyGamePercentage != 100) {
gamesComplete = fiftyGamePercentage * 50;
gamesComplete++;
NSLog(#"fifty game reported %f ",(gamesComplete * .02));
[self reportAchievementIdentifier:kAchievementGamesCompletedFifty percentComplete:(gamesComplete * .02)];
}
if (hundredGamePercentage != 100) {
gamesComplete = hundredGamePercentage * 100;
gamesComplete++;
[self reportAchievementIdentifier:kAchievementGamesCompletedHundred percentComplete:(gamesComplete * .01)];
}
if (fivehundredGamePercentage != 100) {
gamesComplete = fivehundredGamePercentage * 500;
gamesComplete++;
[self reportAchievementIdentifier:kAchievementGamesCompletedFivehundred percentComplete:(gamesComplete * .002)];
}
if (fivehundredGamePercentage != 100) {
gamesComplete = thousandGamePercentage * 1000;
gamesComplete++;
[self reportAchievementIdentifier:kAchievementGamesCompletedThousand percentComplete:(gamesComplete * .0001)];
}
NSLog(#"100 game percentage -- > %f", hundredGamePercentage);
}
Many problems...
I'm confused by the logic behind incrementing gamesComplete
You should store them locally instead of asking GameCenter every time.
-getAchievementPercentageForIdentifier: will always return 0 because GameKit methods are asynchronous.
GKAchievement.percentageComplete is a percentage. You need to multiply by 100.
I think you have to do your own achievement notifications.
i am new in iphone,i am using horizontal scrollview these are horizontally scrolling properly
but i want these horizontally scrolling on previous and next button action.please help me asap.
Thanks:)
Here are the steps that was worked for me
in .h file write following code.
int scrollMove;
UIScrollView *aScrView;
-(IBAction)nextBtnAction:(id)sender;
-(IBAction)previousBtnAction:(id)sender;
in .m file
- (void)viewDidLoad
{
[super viewDidLoad];
scrollMove=50;
aScrView=[[UIScrollView alloc]init];
aScrView.frame=CGRectMake(25,50, 270, 50);
aScrView.delegate=self;
aScrView.contentSize=CGSizeMake(1200, 0);
[self.view addSubview:aScrView];
// Do any additional setup after loading the view from its nib.
}
-(IBAction)nextBtnAction:(id)sender{
float coordinate = 2.0f;
//scrollMove=50;
[aScrView setContentOffset:CGPointMake(scrollMove * coordinate, 0) animated:YES];
scrollMove=scrollMove+50;
}
-(IBAction)previousBtnAction:(id)sender{
float coordinate = 1.0f;
[aScrView setContentOffset:CGPointMake(scrollMove * coordinate, 0) animated:YES];
scrollMove=scrollMove-50;
}
Hope this helps you!!!
Use this one when you want to go on next visible content of Scroll view:
(Put this one inside next button method)
float coordinate = 2.0f;
[nodeScrollView setContentOffset:CGPointMake(460 * coordinate, 0) animated:YES];
move on previous visible content view:
float coordinate = 1.0f;
[nodeScrollView setContentOffset:CGPointMake(460 * coordinate, 0) animated:YES];
(Put this one inside previous button method)
**You need some mathematical calculation with coordinate
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * pageNumberYouWantToGoTo;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
- (void)viewDidLoad
{
x=0;
y=320;
}
- (IBAction)next:(id)sender
{
y=320;
[scrl_Knot setContentOffset:CGPointMake(x+320,0) animated:YES];
x+=320;
}
- (IBAction)pre:(id)sender
{
x=0;
[scrl_Knot setContentOffset:CGPointMake(y,0) animated:YES];
y-=320;
}
- (IBAction)pre:(id)sender
{
btnNext.enabled = TRUE;
imageID--;
[scrl_venuelist setContentOffset:CGPointMake(imageID*273, 0) animated:YES];
pagecontrol.currentPage=imageID;
if(imageID <= 0)
{
btnPrevious.enabled = FALSE;
}
}
- (IBAction)next:(id)sender
{
btnPrevious.enabled = TRUE;
imageID++;
[scrl_venuelist setContentOffset:CGPointMake(imageID*273, 0) animated:YES];
pagecontrol.currentPage=imageID;
if(imageID >= imageArr.count-1)
{
btnNext.enabled = FALSE;
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
{
imageID = scrollView.contentOffset.x / scrollView.frame.size.width;
pagecontrol.currentPage=imageID;
if(imageID <= 0)
{
btnPrevious.enabled = FALSE;
imageID = 0;
}
else
{
btnPrevious.enabled = TRUE;
}
if(imageID >= imageArr.count-1)
{
btnNext.enabled = FALSE;
imageID = imageArr.count-1;
}
else
{
btnNext.enabled = TRUE;
}
}
- (void)viewDidLoad
{
scrl_venuelist.delegate=self;
scrl_venuelist.contentSize =CGSizeMake(273 * [imageArr count], 137);
if(imageID == 0)
{
btnPrevious.enabled = FALSE;
if(imageID == imageArr.count-1)
{
btnNext.enabled = FALSE;
}
}
else if(imageID == imageArr.count-1)
{
btnNext.enabled = FALSE;
}
else if(imageID > imageArr.count-1)
{
imageID = [imageArr count]-1;
}
scrl_venuelist.pagingEnabled=YES;
pagecontrol.numberOfPages=[imageArr count];
pagecontrol.currentPage=0;
}
If Any one Looking for way of doing in C# for Xamarin
public int CurrentIndex
{
get => (int)Math.Round(this.scrollView.ContentOffset.X / this.scrollView.Frame.Width);
set => this.scrollView.ScrollRectToVisible(new CGRect(new CGPoint(this.scrollView.Frame.Size.Width * value, 0), this.scrollView.Frame.Size), true);
}
This getter and Setter should provide you current page as well let you scroll to the specified page
On Button Actions Just Update Current Index to new Values, Which could current Index +1/-1.
Regarding iPhone Map Kit cluster pinpoints:
I have 1000's of marks that I want to show on the map but it's just too many to handle so I want to cluster them.
Are there frameworks available or proof of concepts? That this is possible or is already been done?
You can use REVClusterMap to cluster
Note: This is a commercial product I'm affiliated with, but it solves this very problem.
I solved this problem in few of my apps and decided to extract it into a reusable framework. It's called Superpin and it is an (commercial, license costs $149) iOS Framework that internally uses quadtrees for annotation storage and performs grid-based clustering. The algorithm is quite fast, the included sample app is showing airports of the world (more than 30k+ annotations) and it's running quite smooth on an 3G iPhone.
This might be a bit like using a chainsaw to mow the lawn, but here is an excerpt from Algorithms in a Nutshell
Creating a KD-Tree...
public class KDFactory {
// Known comparators for partitioning points along dimensional axes.
private static Comparator<IMultiPoint> comparators[ ] ;
// Recursively construct KDTree using median method on input points.
public static KDTree generate (IMultiPoint [ ] points) {
if (points. length == 0) { return null; }
// median will be the root.
int maxD = points[ 0] . dimensionality( );
KDTree tree = new KDTree(maxD) ;
// Make dimensional comparators that compare points by ith dimension
comparators = new Comparator[ maxD+1] ;
for (int i = 1; i <= maxD; i++) {
comparators[ i] = new DimensionalComparator(i) ;
}
tree. setRoot(generate (1, maxD, points, 0, points. length-1) ) ;
return tree;
}
// generate the node for the d-th dimension (1 <= d <= maxD)
// for points[ left, right]
private static DimensionalNode generate (int d, int maxD,
IMultiPoint points[ ] ,
int left, int right) {
// Handle the easy cases first
if (right < left) { return null; }
if (right == left) { return new DimensionalNode (d, points[ left] ) ; }
// Order the array[ left, right] so the mth element will be the median
// and the elements prior to it will all be <=, though they won' t
// necessarily be sorted; similarly, the elements after will all be >=
int m = 1+(right-left) /2;
Selection. select(points, m, left, right, comparators[ d] ) ;
// Median point on this dimension becomes the parent
DimensionalNode dm = new DimensionalNode (d, points[ left+m-1] ) ;
// update to the next dimension, or reset back to 1
if (++d > maxD) { d = 1; }
// recursively compute left and right sub-trees, which translate
// into ' below' and ' above' for n-dimensions.
dm. setBelow(maxD, generate (d, maxD, points, left, left+m-2) ) ;
dm. setAbove(maxD, generate (d, maxD, points, left+m, right) ) ;
return dm;
}
}
Finding nearest neighbors best: O(log n) worst O(n)
// method in KDTree
public IMultiPoint nearest (IMultiPoint target) {
if (root == null) return null;
// find parent node to which target would have been inserted. This is our
// best shot at locating closest point; compute best distance guess so far
DimensionalNode parent = parent(target) ;
IMultiPoint result = parent. point;
double smallest = target. distance(result) ;
// now start back at the root, and check all rectangles that potentially
// overlap this smallest distance. If better one is found, return it.
double best[ ] = new double[ ] { smallest };
double raw[ ] = target. raw( );
IMultiPoint betterOne = root. nearest (raw, best) ;
if (betterOne ! = null) { return betterOne; }
return result;
}
// method in DimensionalNode. min[ 0] contains best computed shortest distance.
IMultiPoint nearest (double[ ] rawTarget, double min[ ] ) {
// Update minimum if we are closer.
IMultiPoint result = null;
// If shorter, update minimum
double d = shorter(rawTarget, min[ 0] ) ;
if (d >= 0 && d < min[ 0] ) {
min[ 0] = d;
result = point;
}
// determine if we must dive into the subtrees by computing direct
// perpendicular distance to the axis along which node separates
// the plane. If d is smaller than the current smallest distance,
// we could "bleed" over the plane so we must check both.
double dp = Math. abs(coord - rawTarget[ dimension-1] ) ;
IMultiPoint newResult = null;
if (dp < min[ 0] ) {
// must dive into both. Return closest one.
if (above ! = null) {
newResult = above. nearest (rawTarget, min) ;
if (newResult ! = null) { result = newResult; }
}
if (below ! = null) {
newResult = below. nearest(rawTarget, min) ;
if (newResult ! = null) { result = newResult; }
}
} else {
// only need to go in one! Determine which one now.
if (rawTarget[ dimension-1] < coord) {
if (below ! = null) {
newResult = below. nearest (rawTarget, min) ;
}
} else {
if (above ! = null) {
newResult = above. nearest (rawTarget, min) ;
}
}
// Use smaller result, if found.
if (newResult ! = null) { return newResult; }
}
return result;
}
More on KD-Trees at Wikipedia
I tried the others suggested here, and I also found OCMapView which has worked the best.
Its free and allows for easy grouping of annotations, which is what I needed. Its a bit newer & more updated than Revolver and to me is easier to implement.
A proof of concept is the Offline Maps app "OffMaps" ;)
http://itunes.apple.com/us/app/offmaps/id313854422?mt=8
I recently had to implement annotation clustering with MapKit. The solutions mentioned above are good, depending on your use case. I ended up going with FBAnnotationClustering (Objective-C) because it was free, and had lots of stars and few issues on github:
https://github.com/infinum/FBAnnotationClustering
The app I was working on was very map-centric, so it made sense to translate FBAnnotationClustering into Swift. Here's a blog post on the approach, which includes a link to the sample project on github.
http://ribl.co/blog/2015/05/28/map-clustering-with-swift-how-we-implemented-it-into-the-ribl-ios-app/
Inspired by WWDC 2011 video, this code works very well for me. Maybe not the fastest of all proposed here but it's for free and it's definitely the simplest.
It basically use 2 maps. One is hidden and hold every single annotation (allAnnotationMapView in my code). One is visible and show only the clusters or the annotations if single (mapView in my code).
- (void)didZoom:(UIGestureRecognizer*)gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateEnded){
[self updateVisibleAnnotations];
}
}
- (void)updateVisibleAnnotations {
static float marginFactor = 2.0f;
static float bucketSize = 50.0f;
MKMapRect visibleMapRect = [self.mapView visibleMapRect];
MKMapRect adjustedVisibleMapRect = MKMapRectInset(visibleMapRect, -marginFactor * visibleMapRect.size.width, -marginFactor * visibleMapRect.size.height);
CLLocationCoordinate2D leftCoordinate = [self.mapView convertPoint:CGPointZero toCoordinateFromView:self.view];
CLLocationCoordinate2D rightCoordinate = [self.mapView convertPoint:CGPointMake(bucketSize, 0) toCoordinateFromView:self.view];
double gridSize = MKMapPointForCoordinate(rightCoordinate).x - MKMapPointForCoordinate(leftCoordinate).x;
MKMapRect gridMapRect = MKMapRectMake(0, 0, gridSize, gridSize);
double startX = floor(MKMapRectGetMinX(adjustedVisibleMapRect) / gridSize) * gridSize;
double startY = floor(MKMapRectGetMinY(adjustedVisibleMapRect) / gridSize) * gridSize;
double endX = floor(MKMapRectGetMaxX(adjustedVisibleMapRect) / gridSize) * gridSize;
double endY = floor(MKMapRectGetMaxY(adjustedVisibleMapRect) / gridSize) * gridSize;
gridMapRect.origin.y = startY;
while(MKMapRectGetMinY(gridMapRect) <= endY) {
gridMapRect.origin.x = startX;
while (MKMapRectGetMinX(gridMapRect) <= endX) {
NSSet *allAnnotationsInBucket = [self.allAnnotationMapView annotationsInMapRect:gridMapRect];
NSSet *visibleAnnotationsInBucket = [self.mapView annotationsInMapRect:gridMapRect];
NSMutableSet *filteredAnnotationsInBucket = [[allAnnotationsInBucket objectsPassingTest:^BOOL(id obj, BOOL *stop) {
BOOL isPointMapItem = [obj isKindOfClass:[PointMapItem class]];
BOOL shouldBeMerged = NO;
if (isPointMapItem) {
PointMapItem *pointItem = (PointMapItem *)obj;
shouldBeMerged = pointItem.shouldBeMerged;
}
return shouldBeMerged;
}] mutableCopy];
NSSet *notMergedAnnotationsInBucket = [allAnnotationsInBucket objectsPassingTest:^BOOL(id obj, BOOL *stop) {
BOOL isPointMapItem = [obj isKindOfClass:[PointMapItem class]];
BOOL shouldBeMerged = NO;
if (isPointMapItem) {
PointMapItem *pointItem = (PointMapItem *)obj;
shouldBeMerged = pointItem.shouldBeMerged;
}
return isPointMapItem && !shouldBeMerged;
}];
for (PointMapItem *item in notMergedAnnotationsInBucket) {
[self.mapView addAnnotation:item];
}
if(filteredAnnotationsInBucket.count > 0) {
PointMapItem *annotationForGrid = (PointMapItem *)[self annotationInGrid:gridMapRect usingAnnotations:filteredAnnotationsInBucket];
[filteredAnnotationsInBucket removeObject:annotationForGrid];
annotationForGrid.containedAnnotations = [filteredAnnotationsInBucket allObjects];
[self.mapView addAnnotation:annotationForGrid];
//force reload of the image because it's not done if annotationForGrid is already present in the bucket!!
MKAnnotationView* annotationView = [self.mapView viewForAnnotation:annotationForGrid];
NSString *imageName = [AnnotationsViewUtils imageNameForItem:annotationForGrid selected:NO];
UILabel *countLabel = [[UILabel alloc] initWithFrame:CGRectMake(15, 2, 8, 8)];
[countLabel setFont:[UIFont fontWithName:POINT_FONT_NAME size:10]];
[countLabel setTextColor:[UIColor whiteColor]];
[annotationView addSubview:countLabel];
imageName = [AnnotationsViewUtils imageNameForItem:annotationForGrid selected:NO];
annotationView.image = [UIImage imageNamed:imageName];
if (filteredAnnotationsInBucket.count > 0){
[self.mapView deselectAnnotation:annotationForGrid animated:NO];
}
for (PointMapItem *annotation in filteredAnnotationsInBucket) {
[self.mapView deselectAnnotation:annotation animated:NO];
annotation.clusterAnnotation = annotationForGrid;
annotation.containedAnnotations = nil;
if ([visibleAnnotationsInBucket containsObject:annotation]) {
CLLocationCoordinate2D actualCoordinate = annotation.coordinate;
[UIView animateWithDuration:0.3 animations:^{
annotation.coordinate = annotation.clusterAnnotation.coordinate;
} completion:^(BOOL finished) {
annotation.coordinate = actualCoordinate;
[self.mapView removeAnnotation:annotation];
}];
}
}
}
gridMapRect.origin.x += gridSize;
}
gridMapRect.origin.y += gridSize;
}
}
- (id<MKAnnotation>)annotationInGrid:(MKMapRect)gridMapRect usingAnnotations:(NSSet *)annotations {
NSSet *visibleAnnotationsInBucket = [self.mapView annotationsInMapRect:gridMapRect];
NSSet *annotationsForGridSet = [annotations objectsPassingTest:^BOOL(id obj, BOOL *stop) {
BOOL returnValue = ([visibleAnnotationsInBucket containsObject:obj]);
if (returnValue) {
*stop = YES;
}
return returnValue;
}];
if (annotationsForGridSet.count != 0) {
return [annotationsForGridSet anyObject];
}
MKMapPoint centerMapPoint = MKMapPointMake(MKMapRectGetMinX(gridMapRect), MKMapRectGetMidY(gridMapRect));
NSArray *sortedAnnotations = [[annotations allObjects] sortedArrayUsingComparator:^(id obj1, id obj2) {
MKMapPoint mapPoint1 = MKMapPointForCoordinate(((id<MKAnnotation>)obj1).coordinate);
MKMapPoint mapPoint2 = MKMapPointForCoordinate(((id<MKAnnotation>)obj2).coordinate);
CLLocationDistance distance1 = MKMetersBetweenMapPoints(mapPoint1, centerMapPoint);
CLLocationDistance distance2 = MKMetersBetweenMapPoints(mapPoint2, centerMapPoint);
if (distance1 < distance2) {
return NSOrderedAscending;
}
else if (distance1 > distance2) {
return NSOrderedDescending;
}
return NSOrderedSame;
}];
return [sortedAnnotations objectAtIndex:0];
}
I think Foto Brisko (iTunes link) does this.
I do not think there is a Cocoa Touch framework for it.