Set Uibutton Random Position on UIView - iphone

I want to set 5 buttons on uiview at random position. Buttons need maintain some spacing to each other. I mean buttons should not overlap to each other.
All buttons set on UIView come from corners with rotation animation.
btn1.transform = CGAffineTransformMakeRotation(40);
btn2.transform = CGAffineTransformMakeRotation(60);
btn3.transform = CGAffineTransformMakeRotation(90);
btn4.transform = CGAffineTransformMakeRotation(30);
btn5.transform = CGAffineTransformMakeRotation(20);
I Can rotate buttons using above code but can you pls. help me for set buttons on random position with out overlapping by each other.
If points are fix than I can set buttons with animation by this code but I want random position of buttons.
[AnimationView moveBubble:CGPointMake(18, 142) duration:1 : btn1];
[AnimationView moveBubble:CGPointMake(118, 142) duration:1 : btn2];
[AnimationView moveBubble:CGPointMake(193, 142) duration:1 : btn3];
[AnimationView moveBubble:CGPointMake(18, 216) duration:1 : btn4];
Thanks in advance.

1st, add buttons to an NSArray, only to make things easier:
NSArray *buttonArray = #[btn1,btn2,btn3,btn4,btn5];
Now, this code tries to Arrange them at random positions.
int xTemp, yTemp;
for (int i = 0; i < 5; i++) {
while (YES) {
xTemp = arc4random_uniform(view.frame.size.width - [buttonArray[i] frame].size.width);
yTemp = arc4random_uniform(view.frame.size.height - [buttonArray[i] frame].size.height);
if (![self positionx:xTemp y:yTemp intersectsAnyButtonTillIndex:i inButtonArray:buttonArray]) {
[AnimationView moveBubble:CGPointMake(xTemp, yTemp) duration:1 : buttonArray[i]];
break;
}
}
}
Implement this function somewhere too:
- (BOOL) positionx:(int)xTemp y:(int)yTemp intersectsAnyButtonTillIndex:(int)index inButtonArray:(NSArray *)buttonArray {
//Again please change the < to <= , I'm sorry, doing too many things at once.
for (int i = 0; i <= index; i++) {
CGRect frame = [buttonArray[i] frame];
//EDIT : In the logic earlier, I had wrongly done a minus where I should have done a plus.
if ((xTemp > frame.origin.x && xTemp < (frame.size.width + frame.origin.x)) && (yTemp > frame.origin.y && yTemp < (frame.size.height + frame.origin.y))) return YES;
}
return NO;
OK this is a workign soln., I hope, just added something to WolfLink's answer. Check This.
for (UIButton *button in buttonArray) {
button.frame = CGRectMake(arc4random_uniform(view.frame.size.width - button.frame.size.width), arc4random_uniform(view.frame.size.height - button.frame.size.height), button.frame.size.width, button.frame.size.height);
while ([self button:button intersectsButtonInArray:buttonArray]) {
button.frame = CGRectMake(arc4random_uniform(view.frame.size.width - button.frame.size.width), arc4random_uniform(view.frame.size.height - button.frame.size.height), button.frame.size.width, button.frame.size.height);
}
//another function
-(BOOL)button:(UIButton *)button intersectsButtonInArray:(NSArray *)array {
for (UIButton *testButton in array) {
if (CGRectIntersectsRect(button.frame, testButton.frame) && ![button isEqual:testButton]) {
return YES;
}
}
return NO;
}

Based on spiritofmysoul.wordpress's code:
//in the function where you randomize the buttons
NSArray *buttonArray = #[btn1,btn2,btn3,btn4,btn5];
for (UIButton *button in buttonArray) {
float widthOffset = self.frame.size.width-button.frame.size.width;
float heightOffset = self.frame.size.height-button.frame.size.height;
button.frame = CGRectMake(arc4random()%widthOffset, arc4random()%heightOffset, button.frame.size.width, button.frame.size.height);
while ([self button:button intersectsButtonInArray:buttonArray]) {
button.frame = CGRectMake(arc4random(), arc4random(), button.frame.size.width, button.frame.size.height);
}
//another function
-(BOOL)button:(UIButton *)button intersectsButtonInArray:(NSArray *)array {
for (UIButton *testButton in array) {
if (CGRectIntersectsRect(button.frame, testButton.frame) && ![button isEqual:testButton]) {
return YES;
}
}
return NO;
}
Beware: This will work well for small amounts of buttons on a large space but as you add buttons and you run out of space, this method will take much longer to run. If there is not enough space for all the buttons, it will become an infinite loop.

Related

Custom UIPickerView with three Components each showing label on Selection Indicator

In my app I am trying to make an custom UIPickerView which contains three components(days, hours and minutes). I have already made the custom picker with three components. And Now I am stuck at how I can add the labels to the selection indicator which shows which component is for days, hours or minutes.
I have already gone through each and every link or question posted on this site but none them helped me.
I am trying to implement something like this image
Can any one suggest me how can I achieve this?
Thats how I achieve this....I have made my Custom PickerView with the help of some code I found...
In .h file:
// LabeledPickerView.h
// LabeledPickerView
#import <UIKit/UIKit.h>
#interface LabeledPickerView : UIPickerView
{
NSMutableDictionary *labels;
}
/** Adds the label for the given component. */
-(void)addLabel:(NSString *)labeltext forComponent:(NSUInteger)component forLongestString:(NSString *)longestString;
#end
and In the .m file...
// LabeledPickerView.m
// LabeledPickerView
#import "LabeledPickerView.h"
#implementation LabeledPickerView
/** loading programmatically */
- (id)initWithFrame:(CGRect)aRect {
if (self = [super initWithFrame:aRect]) {
labels = [[NSMutableDictionary alloc] initWithCapacity:3];
}
return self;
}
/** loading from nib */
- (id)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
labels = [[NSMutableDictionary alloc] initWithCapacity:3];
}
return self;
}
- (void) dealloc
{
[labels release];
[super dealloc];
}
#pragma mark Labels
// Add labelText to our array but also add what will be the longest label we will use in updateLabel
// If you do not plan to update label then the longestString should be the same as the labelText
// This way we can initially size our label to the longest width and we get the same effect Apple uses
-(void)addLabel:(NSString *)labeltext forComponent:(NSUInteger)component forLongestString:(NSString *)longestString {
[labels setObject:labeltext forKey:[NSNumber numberWithInt:component]];
NSString *keyName = [NSString stringWithFormat:#"%#_%#", #"longestString", [NSNumber numberWithInt:component]];
if(!longestString) {
longestString = labeltext;
}
[labels setObject:longestString forKey:keyName];
}
//
- (void) updateLabel:(NSString *)labeltext forComponent:(NSUInteger)component {
UILabel *theLabel = (UILabel*)[self viewWithTag:component + 1];
// Update label if it doesn’t match current label
if (![theLabel.text isEqualToString:labeltext]) {
NSString *keyName = [NSString stringWithFormat:#"%#_%#", #"longestString", [NSNumber numberWithInt:component]];
NSString *longestString = [labels objectForKey:keyName];
// Update label array with our new string value
[self addLabel:labeltext forComponent:component forLongestString:longestString];
// change label during fade out/in
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.75];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
theLabel.alpha = 0.00;
theLabel.text = labeltext;
theLabel.alpha = 1.00;
[UIView commitAnimations];
}
}
/**
Adds the labels to the view, below the selection indicator glass-thingy.
The labels are aligned to the right side of the wheel.
The delegate is responsible for providing enough width for both the value and the label.
*/
- (void)didMoveToWindow {
// exit if view is removed from the window or there are no labels.
if (!self.window || [labels count] == 0)
return;
UIFont *labelfont = [UIFont boldSystemFontOfSize:15];
// find the width of all the wheels combined
CGFloat widthofwheels = 0;
for (int i=0; i<self.numberOfComponents; i++) {
widthofwheels += [self rowSizeForComponent:i].width;
}
// find the left side of the first wheel.
// seems like a misnomer, but that will soon be corrected.
CGFloat rightsideofwheel = (self.frame.size.width - widthofwheels) / 2;
// cycle through all wheels
for (int component=0; component<self.numberOfComponents; component++) {
// find the right side of the wheel
rightsideofwheel += [self rowSizeForComponent:component].width;
// get the text for the label.
// move on to the next if there is no label for this wheel.
NSString *text = [labels objectForKey:[NSNumber numberWithInt:component]];
if (text) {
// set up the frame for the label using our longestString length
NSString *keyName = [NSString stringWithFormat:#"%#_%#", [NSString stringWithString:#"longestString"], [NSNumber numberWithInt:component]];
NSString *longestString = [labels objectForKey:keyName];
CGRect frame;
frame.size = [longestString sizeWithFont:labelfont];
// center it vertically
frame.origin.y = (self.frame.size.height / 2) - (frame.size.height / 2) - 0.5;
// align it to the right side of the wheel, with a margin.
// use a smaller margin for the rightmost wheel.
frame.origin.x = rightsideofwheel - frame.size.width -
(component == self.numberOfComponents - 1 ? 5 : 7);
// set up the label. If label already exists, just get a reference to it
BOOL addlabelView = NO;
UILabel *label = (UILabel*)[self viewWithTag:component + 1];
if(!label) {
label = [[[UILabel alloc] initWithFrame:frame] autorelease];
addlabelView = YES;
}
label.text = text;
label.font = labelfont;
label.backgroundColor = [UIColor clearColor];
label.shadowColor = [UIColor whiteColor];
label.shadowOffset = CGSizeMake(0,1);
// Tag cannot be 0 so just increment component number to esnure we get a positive
// NB update/remove Label methods are aware of this incrementation!
label.tag = component + 1;
if(addlabelView) {
/*
and now for the tricky bit: adding the label to the view.
kind of a hack to be honest, might stop working if Apple decides to
change the inner workings of the UIPickerView.
*/
if (self.showsSelectionIndicator) {
// if this is the last wheel, add label as the third view from the top
if (component==self.numberOfComponents-1)
[self insertSubview:label atIndex:[self.subviews count]-3];
// otherwise add label as the 5th, 10th, 15th etc view from the top
else
[self insertSubview:label aboveSubview:[self.subviews objectAtIndex:5*(component+1)]];
} else
// there is no selection indicator, so just add it to the top
[self addSubview:label];
}
if ([self.delegate respondsToSelector:#selector(pickerView:didSelectRow:inComponent:)])
[self.delegate pickerView:self didSelectRow:[self selectedRowInComponent:component] inComponent:component];
}
}
}
And call this addLabel: method with the label text and component tag and thats it..!!
Download the Source code Of custom UIPickerView Control .
Custom UiPickerView.
Hope it Helps to You :)

iOS: Find all controls with the same tag

I have created a storyboard with 12 buttons, 12 smaller buttons and 12 labels.
It is like that:
btnBig1.tag = 1
btnSmall1.tag = 1
lbl1.tag = 1
btnBig2.tag = 2
btnSmall2.tag = 2
lbl2.tag = 2
etc...
Now when a procedure is called
- (IBAction)processButtonUpInside:(id)sender
{
UIButton *nButton = (UIButton*)sender;
int nInt = nButton.tag;
}
... I would like to do something with all 3 controls (big button, small button and label).
It should look like this (pseudo-code):
- (IBAction)processButtonUpInside:(id)sender
{
UIButton *nButton = (UIButton*)sender;
int nInt = nButton.tag;
UIButton *nButtonBig (UIButton*)CastFromTagID(nInt)
//do something with the big button
UIButton *nButtonSmall (UIButton*)CastFromTagID(nInt)
//do something with the small button
UILabel *nLabel (UILabel*)CastFromTagID(nInt)
//do something with the label
}
As you can see, the CastFromTagID is my "own invention". I don't know how I should actually do this.
Can somebody help?
Thank you very much.
You can use 3 a different starting point for each button family:
enum {
kTagFirstBigButton = 1000,
kTagFirstSmallButton = 2000,
kTagFirstLabel = 3000,
}
Assign the tags using them:
btnBig1.tag = kTagFirstBigButton + 1;
btnSmall1.tag = kTagFirstSmallButton + 1;
lbl1.tag = kTagFirstLabel + 1;
btnBig2.tag = kTagFirstBigButton + 2;
btnSmall2.tag = kTagFirstSmallButton + 2;
lbl2.tag = kTagFirstLabel + 2;
...
Now it's easy to find anything:
- (IBAction)processButtonUpInside:(id)sender
{
UIButton *nButton = (UIButton*)sender;
/* I'm not sure what button is `sender` here
If it's a big or small one you can guess
comparing its tag with the first tag
*/
int offset = nButton.tag;
UIButton *nButtonBig = (UIButton*)[view viewWithTag:kTagFirstBigButton + offset];
//do something with the big button
UIButton *nButtonSmall = (UIButton*)[view viewWithTag:kTagFirstSmallButton + offset];
//do something with the small button
UILabel *nLabel = (UILabel*)[view viewWithTag:kTagFirstLabel + offset];
//do something with the label
}
You shouldn't assign the same tag id to different views.
Indeed, do something like this:
btnBig1.tag = 11 btnSmall1.tag = 12 lbl1.tag = 13;
btnBig2.tag = 21 btnSmall2.tag = 22 lbl2.tag = 23;
Then consider the last digit of the tag id:
UIView *nView = (UIView *)sender;
if (lastDigit(sender.tag) == 3)
// this is a label
{
UIButton *nButtonBig = [nView.superview viewWithTag:nInt-2];
UIButton *nButtonSmall = [nView.superview viewWithTag:nInt-1];
UILabel *nLabel = (UILabel *)sender;
}
else if (lastDigit(sender.tag) == 2)
.....
where lastDigit(sender.tag) is a function that returns the last digit of a given integer.
In my case where I don't have a reference to the subviews that I want to edit under the same tag I just grab all of the subviews for a given view then loop through all of them and check the tag, if the tag match I execute some code. For example..
#define kSameViewTag 9500001
for (int i = 0; i < 10; i++) // add a bunch of same tag views //
{
UIView *someview = [UIView new];
someview.tag = kSameViewTag;
[YourParent addSubview:someview];
}
Then later on or whenever you need to loop through your views you can do.
NSArray *subviews = [[YourParent subviews] copy];
for (UIView *v in subviews)
{
if (v.tag == kSameViewTag)
{
// Do some code //
}
}
Now this may become an performance issue if you have a lot of subviews so you can always run it on the background thread then jump into the main thread to do UI updates. For Example:
NSArray *subviews = [[YourParent subviews] copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
for (UIView *v in subviews)
{
if (v.tag == kSameViewTag)
{
dispatch_async(dispatch_get_main_queue(), ^{
// Do Some UI Stuff Here //
});
}
}
});

Animating sequence of images in cocos2d

i have this code to show animation of a image
-(void) blink:(ccTime) delta {
animateblink ++; //adds 1 every frame
if (animateblink <= 6 ) { //if we included frames to show for breaking and the current frame is less than the max number of frames to play
if (animateblink < 6) {
[sprite setTexture:[[CCSprite spriteWithFile:[NSString stringWithFormat:#"%#_blinkk00%i.png", baseImageName,animateblink]] texture]];
[self unschedule:_cmd];
[self schedule:#selector(openEyes:) interval:0.1f];
[self schedule:#selector(moveSprite:) interval:0.1f];
}
}
}
i have 6 images of animating like
dragonimage_blinkk001,dragonimage_blinkk002,dragonimage_blinkk003,dragonimage_blinkk004,dragonimage_blinkk005,dragonimage_blinkk006 like that
i put two methods,
1: for animation time
2: for movement of the image
the code is
-(void) openEyes:(ccTime) delta {
[sprite setTexture:[[CCSprite spriteWithFile:[NSString stringWithFormat:#"%#.png", baseImageName]] texture]];
[self unschedule:_cmd];
int blinkInterval = (arc4random() % 6) + 1; // range 3 to 8
[self schedule:#selector(blink:) interval:blinkInterval];
}
-(void)moveSprite:(ccTime)delta
{
movementCounter ++;
if (movementCounter == 1000) {
[self unschedule:_cmd];
}
else
{
spriteimagename.position = ccp(spriteimagename.position.x+10,spriteimagename.position.y);
}
}
but on the first method the animation time is not correct,there is a lot of delay of animation,i just want to show animation of the images randomly and fast,its a dragon flying animation.
my sec on method is not at all working,i didn't get any movement of that image.
i hope you understand my issue.how to solve the above two method issues.
Thanks in advance.
Quick solution is to add frameIndex member in cocos2d CCSpriteFrame class. i don't know is that allowed to change. But it works fine.
#interface CCSpriteFrame : NSObject <NSCopying>
{
int frameIndex;
....
}
//Here in code initialize frames with unique index
CCAnimation* animation;
NSMutableArray *animFrames2 = [NSMutableArray array];
for( int i=1;i<=15;i++)
{
CCSpriteFrame *frame = [cache spriteFrameByName:[NSString stringWithFormat:#"ActerSmash_%d.png",i]];
frame.frameIndex = (int)i;
[animFrames2 addObject:frame];
}
animation = [CCAnimation animationWithFrames:animFrames2];
CCAnimate *action = [CCAnimate actionWithDuration:ACTER_SMASH_SPEED animation:animation restoreOriginalFrame:YES];
action.tag = kTagAnimationSmashAnim ;
mActer.AnimSmash = action;
//Checking frame Index
CCAnimate *anim = mActer.AnimSmash ;
for(CCSpriteFrame *frame in anim.animation.frames)
{
if([mActer isFrameDisplayed:frame] ) )
{
if(frame.frameIndex == 5 )
{
//Do something..
}
}
}

How to update an object's image in NSMutableArray?

I am trying to set the image of the face down card to the image that the value of the card is. The method in KCCard, image:, returns the image of the card.
- (UIImage *)image:(BOOL)yesOrNo
{
if (!yesOrNo) {
return [UIImage imageNamed:#"back-blue-150-3.png"];
} else {
return [UIImage imageNamed:[NSString stringWithFormat:#"%#-%#-150", [self suitAsString], [self valueAsString]]];
}
}
The code I am using in the deal method is as follows.
int lastDealerX = 437;
//int lastDealerY = 49;
int lastDealerTag = 0;
for (KCCard *aCard in dealerHand) {
if (lastDealerTag == 0) {
KCCardView *cardView = [[KCCardView alloc] initWithFrame:CGRectMake(lastDealerX, 49, 150, 215)];
cardView.backgroundColor = [UIColor blackColor];
cardView.image = [aCard image:NO];
cardView.tag = lastDealerTag;
[self.view addSubview:cardView];
lastDealerTag = lastDealerTag + 1;
lastDealerX = lastDealerX + 42;
} else {
KCCardView *cardView = [[KCCardView alloc] initWithFrame:CGRectMake(lastDealerX, 49, 150, 215)];
cardView.backgroundColor = [UIColor blackColor];
cardView.image = [aCard image:YES];
cardView.tag = lastDealerTag;
[self.view addSubview:cardView];
lastDealerTag = lastDealerTag + 1;
lastDealerX = lastDealerX + 42;
}
}
The KCCardView with tag 0 shows the card face down and the other card is face up. The problem is that when I want the face down card to show, it won't. Here is the show code.
- (IBAction)showCard:(id)sender {
for (UIView *view in self.view.subviews) {
for (KCCard *aCard in dealerHand) {
KCCardView *cardView = (KCCardView *)view;
if (cardView.tag == 0) {
cardView.image = [[dealerHand objectAtIndex:0] image:YES];
}
}
}
}
KCCard is an NSObject, KCCardView is a UIImageView, and dealerHand is an NSMutableArray.
Here is a video showing the build and run: http://aleckazarian.com/misc/Blackjack.mov
Here is the XCode project: http://aleckazarian.com/misc/Blackjack.zip
If you look at the connection in the nib you'll notice that it is connected to
showCard
this is a completely different method to
showCard:
In your class you implement - (IBAction)showCard:(id)sender; therefore you need to break the connection in Interface builder and reconnect it.
Update
The second time I ran your program I got
-[UIRoundedRectButton setImage:]: unrecognized selector sent to instance 0x68612e0
This looks like it's because you are iterating over the view's subviews and checking if 0 == tag. 0 is the default value for tag so essentially mostly every view will respond true unless you have explicitly set the tags to something else. The problem code it
for (UIView *view in self.view.subviews) {
for (KCCard *aCard in dealerHand) {
KCCardView *cardView = (KCCardView *)view;
if (cardView.tag == 0) { // <------- This is the bad check
cardView.image = [((KCCard *)[dealerHand objectAtIndex:0]) image:YES];
}
}
}
To fix this either do one of these (they are in order of my preference - I wouldn't go near 3 or 4 in this case):
Keep a reference to the cardView's in an array
Give the cardView's a non zero tag when they are created
Use respondsToSelector:
Test for the class `[cardView isKindOf:[UIButton class]];
The compiler does not know, what kind of object [dealerHand objectAtIndex:0] is, thus it cannot respond to image:. Try this:
cardView.image = [((KCCard *)[dealerHand objectAtIndex:0]) image:YES];

Trouble in making hidden button Visible

Following code i am writing to hide some buttons in viewDidLoad. Here Buttons Are hiding
- (void)viewDidLoad
{
for (int i = 100; i<117; i++)
{
UIButton *smileyButton = (UIButton *)[scroll viewWithTag:i];
UITextField *smileyFields = (UITextField *)[scroll viewWithTag:i];
UIImageView *smileyImage = (UIImageView *)[scroll viewWithTag:i];
smileyFields.hidden = YES;
smileyButton.hidden = YES;
}
}
Now in Following Action am making Buttons Visible. But buttons are not Visible
-(IBAction)editButton:(id)sender
{
for (int i = 100; i<117; i++)
{
UIButton *smileyButton = (UIButton *)[scroll viewWithTag:i];
UITextField *smileyFields = (UITextField *)[scroll viewWithTag:i];
UIImageView *smileyImage = (UIImageView *)[scroll viewWithTag:i];
[smileyFields setHidden:NO]; //TextFields Not Visible
[smileyButton setHidden:NO]; //Buttons Not Visbile
}
}
If you have several views with the same tag, function viewWithTag will return only one view, so if you call this 3 times, you get always the same view.
To do what you want, you could iterate all subviews and check tags:
for (UIView *aView in scrollView.subviews) {
if (aView.tag >= 100 && aView.tag < 117) {
aView.hidden = NO;
}
}
Are you building the view controller in Interface Builder? If so, set the Tag of each thing you want to hide to a different number: try something simple like 1, 2, 3, etc. If you're building in code set the tag property instead. Remember your maximum tag number (let's assume it's 4).
Then add the following to your .h:
- (void)setTaggedViewsHidden:(BOOL)hidden;
and the following to your .m:
- (void)setTaggedViewsHidden:(BOOL)hidden {
for (NSInteger tag = 1; tag <= 4; tag++) {
[scroll viewWithTag:tag].hidden = hidden;
}
}
In your viewDidLoad call it like so:
[self setTaggedViewsHidden:YES];
and in your editButton: selector call it as:
[self setTaggedViewsHidden:NO];
Remember to adjust the code in setTaggedViewsHidden to match the tags you're using. The best way to do this is to #define a constant for the min and max tags and use those in the for loop.