Am changing the color of the selected segment. It works fine but uisegment control tint color is set to default until it is touched for the first time.
This is the method that changes the color for the selected segment. It works fine but when the segment shows up first time. It has pale gray color. Then when touched it starts working fine as I needed.
(This segment control is added as subview to uialertview)
-(void)segmentValueChanged:(UISegmentedControl*)sender
{
for (int i=0; i<[sender.subviews count]; i++)
{
if ([[sender.subviews objectAtIndex:i]isSelected] )
{
UIColor *tintcolor=[UIColor colorWithRed: 98/255.0 green:156/255.0 blue:247/255.0 alpha:1.0];
[[sender.subviews objectAtIndex:i] setTintColor:tintcolor];
trackType = sender.selectedSegmentIndex;
}
else{
UIColor *tintcolor=[UIColor colorWithRed: 225/255.0 green:220/255.0 blue:210/255.0 alpha:1.0];
[[sender.subviews objectAtIndex:i] setTintColor:tintcolor];
}
}
}
you can call segmentControlValueChanged method forcefully in viewDidLoad method. Like this:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.05 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self segmentedControlValueChanged:segmentedControlOne];
});
Can you please change it from viewdidload or viewwillappear method of your view? because as per your code, it will change, when user first time touch it.
truy this code
i solved my app in this code
- (void)viewDidAppear:(BOOL)animated
{
for(UIView *v in [self.view subviews] )
{
if([v isKindOfClass:[UISegmentedControl class]])
{
// ((UISegmentedControl*)v).enabled=NO;
dispatch_async(dispatch_get_main_queue(),^{
for (int i=0; i<[ ((UISegmentedControl*)v).subviews count]; i++)
{
if ([[((UISegmentedControl*)v).subviews objectAtIndex:i]isSelected] )
{
[[((UISegmentedControl*)v).subviews objectAtIndex:i] setTintColor:[UIColor colorWithRed: 0/255.0 green:176/255.0 blue:223/255.0 alpha:1.0]];
//[[((UISegmentedControl*)v).subviews objectAtIndex:0]setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
// break;
}
else
{
[[((UISegmentedControl*)v).subviews objectAtIndex:i] setTintColor:[UIColor whiteColor]];
//[[((UISegmentedControl*)v).subviews objectAtIndex:0]setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
}
}
});
}
}
}
I figured it out myself. Since alertview creates all the views only after [alertview show]. color changes to segmentcontrol is not afftected since segmentcontrol is not really created yet. So what I did was I delayed the process of segmentcontrol tintcolor changes until it's been created by alertview
[alertview show];
double delayInSeconds = 0.01;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self performSelectorOnMainThread:#selector(segmentValueChanged:) withObject:segControl waitUntilDone:YES];
});
Related
I am new to XCode. I used with NSUserDefaults even though it is not coming what i required means If i click one time on that button it should change the colour to green and if i press it again it should change the colour to black.
Here my Code is -
- (IBAction)subscribeButtonAction:(id)sender {
if (count == 0) {
[_subscribeButtonObj setBackgroundColor:[UIColor greenColor]];
greenStr=[NSString stringWithFormat:#"green"];
NSUserDefaults *greendefults=[NSUserDefaults standardUserDefaults];
[greendefults setValue:greenStr forKey:#"greencolor"];
[greendefults synchronize];
///
count++;
} else if(count == 1){
[_subscribeButtonObj setBackgroundColor:[UIColor blueColor]];
blackStr=[NSString stringWithFormat:#"black"];
NSUserDefaults *blackDefaults=[NSUserDefaults standardUserDefaults];
[blackDefaults setValue:blackStr forKey:#"blackcolor"];
[blackDefaults synchronize];
//count = 0;
}
}
In ViewWillAppear I wrote the code like this -
-(void)viewWillAppear:(BOOL)animated
{
//count = 0;
if ([[NSUserDefaults standardUserDefaults] stringForKey:#"greencolor"]) {
NSLog(#"change the button to green color %#",[[NSUserDefaults standardUserDefaults] stringForKey:#"greencolor"]);
} else {
NSLog(#"change the button to blackcolor ");
}
}
Can anyone please help me. Thanks in Advance
There's no need of NSUserDefaults to implement this. Its simple to handle with UIButton's control states,
UIControlStateNormal
UIControlStateSelected
For example,
- (IBAction)changeColor:(id)sender {
UIButton *button = (UIButton *)sender;
if (button.selected) { // If selected will change the color into Red
button.backgroundColor = [UIColor redColor];
[button setSelected:NO];
} else {
button.backgroundColor = [UIColor greenColor];
[button setSelected:YES];
}
}
And, keeep in mind you can change your button's state initially like setting this,
[myButton setSelected:YES];
Assign, this code in your viewDidLoad
Cheers!!
If you wanna do it the NSUserDefault way. Setting control states is a nice way though. but It will set a unwanted overlay background to the button if UIControlStateSelected is YES. :
- (IBAction)btnAction:(id)sender {
NSUserDefaults *color=[NSUserDefaults standardUserDefaults];
if (count == 0) {
[self.btnOutlet setBackgroundColor:[UIColor greenColor]];
[color setValue:#"green" forKey:#"color"];
}else if(count == 1){
[self.btnOutlet setBackgroundColor:[UIColor blueColor]];
[color setValue:#"blue" forKey:#"color"];
}
count = !count;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
count = 0;
if([[[NSUserDefaults standardUserDefaults] valueForKey:#"color"] isEqualToString:#"green"]){ // been used
[self.btnOutlet setBackgroundColor:[UIColor greenColor]];
}else if([[[NSUserDefaults standardUserDefaults] valueForKey:#"color"] isEqualToString:#"blue"]){
[self.btnOutlet setBackgroundColor:[UIColor blueColor]];
}else{ // first time
[self.btnOutlet setBackgroundColor:[UIColor yellowColor]];
}
}
I am an iOS developer currently developing an iphone application. I have a simple question regarding updating the contents of a ViewController and I would greatly appreciate it if I can get someone’s feedback who is aware of this issue or have a suggested solution.
I’m writing a method that constantly updates the text of a label (and other components such as the background colour of a UIImage “box1” and “box2” ).
The issue : update to the text of the label (along with other changes) only takes effect at the end when the code was done execution. So I have written a simple infinite loop that does this as follows:
-(void) stateTest{
int i=0;
for(;;){
if (i==5) {
self.stateLabel.text=#"Opened"; //stateLabel previously declared
[self.box2 setBackgroundColor:[UIColor whiteColor]]; // box2 declared as UIImage
[self.box1 setBackgroundColor:[UIColor purpleColor]];
}
if (i==10){
self.stateLabel.text=#"Closed";
[self.box2 setBackgroundColor:[UIColor redColor]];
[self.box1 setBackgroundColor:[UIColor whiteColor]];
break;
}
i++;
}
}
and in the viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
self.stateLabel.text=#“View did Load";
[self.box1 setBackgroundColor:[UIColorwhiteColor]];
[self.box2 setBackgroundColor:[UIColorwhiteColor]];
[self stateTest];
}
I’m stepping through the code (breakpoints) and this is the issue I’m facing:
when i==5 the label text does NOT get updated (same as the color of the boxes)
when i==10, the label text does NOT get updated
The update (both the label text and the box color) show up after the code is done executing with
stateLabel : "Closed",
Box 2: red background color
I have tried calling upon several functions at the end of the stateTest method (after the i++) hoping that it will “REFRESH” the contents of the view, label and/or the UIImage:
[self.stateLabel setNeedsLayout];
[self.stateLabel setNeedsDisplay];
[self.box1 setNeedsDisplay];
[self.box2 setNeedsDisplay];
[self.view setNeedsDisplay];
Unfortunately non of these trials worked. I have also put an NSLog that outputs the text of the label and that works just fine, as I want. But the problem is with the dynamic update of the contents of the view controller during execution of code/method.
I would greatly appreciate any help and I am open to any suggestion
Ideally, this code is used in parallel with a face detection algorithm that detects the state of the mouth. There is a processImage method that processes the image every frame. I call [self stateTest] every time the image is processed; if the mouth is opened → stateLabel.text=#”Open”…etc
Thank you in advance for your contribution
Cheers!
The UI update will happen only when the run loop is completed. normally i run the infinite loop in background thread and post the UI update in the main thread. This will take care of the run loop.
Below code is for reference.
-(void) viewDidLoad
{
[super viewDidLoad];
self.subView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 30, 30)];
self.subView.backgroundColor = [UIColor blueColor];
[self.view addSubview:self.subView];
dispatch_queue_t newQueue = dispatch_queue_create("newQueue", nil);
dispatch_async(newQueue, ^{
[self stateTest];
});
}
-(void) stateTest{
int i=0;
for(;;){
if (i==5) {
[self performSelectorOnMainThread:#selector(purpleColor) withObject:self waitUntilDone:NO];
}
if (i==10){
[self performSelectorOnMainThread:#selector(blueColor) withObject:self waitUntilDone:NO];
// break;
}
if (i==15){
[self performSelectorOnMainThread:#selector(redColor) withObject:self waitUntilDone:NO];
//break;
}
if (i==20){
[self performSelectorOnMainThread:#selector(greenColor) withObject:self waitUntilDone:NO];
break;
}
sleep(1);
i++;
}
}
-(void) purpleColor
{
[self.subView setBackgroundColor:[UIColor purpleColor]];
}
-(void) blueColor
{
[self.subView setBackgroundColor:[UIColor blueColor]];
}
-(void) redColor
{
[self.subView setBackgroundColor:[UIColor redColor]];
}
-(void) greenColor
{
[self.subView setBackgroundColor:[UIColor greenColor]];
}
it's not a very good idea to run a infinite loop on the main thread (uithread). Instead can I suggest you to use a timer or a dispatch event ? below is some code you can use for a timer. and I would also point you out that NSTimer cannot be re used. hence if you wish to do this operation after you invalidated it you need to re create the timer & add it into a runloop.
// properties in your controller
#property (nonatomic) BOOL state;
#property (nonatomic, strong) NSTimer *timer;
// where to create it . timer interval is in seconds & use decimals if you want split seconds.
- (void)viewDidLoad
{
[super viewDidLoad];
self.timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:#selector(onTimer:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
}
// timer callback method
int count = 0;
- (void)onTimer:(NSNotification *)sender
{
self.state = !self.state;
if (self.state)
{
self.box1.backgroundColor = [UIColor redColor];
self.box2.backgroundColor = [UIColor blueColor];
}
else
{
self.box1.backgroundColor = [UIColor yellowColor];
self.box2.backgroundColor = [UIColor greenColor];
}
count++;
if (count == 100)
{
[self.timer invalidate];
[[[UIAlertView alloc] initWithTitle:#"timer done" message:#"timer finished" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil] show];
}
}
Im attempting add image views to a UIView using this code:
for (int i = 0; i <numberOfImages; i++) {
UIImageView *image = [UIImageView alloc]initWithFrame:CGRectMake(40, 40, 40, 40)];
image.image = [images objectAtIndex:i];
[self.view addSubview:image];
}
This works but the problem is I would like to have a 5 second delay before it adds each image, instead it adds them all at the same time. Can anybody help me out? Thanks.
Example:
5 seconds = one image on screen
10 seconds = two images on screen
15 seconds = three images on screen
It will be more efficient to use an NSTimer.
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:numberOfSeconds
target:self
selector:#selector(methodToAddImages:)
userInfo:nil
repeats:YES];
This will essentially call methodToAddImages repeatedly with the specified time interval. To stop this method from being called, call [NSTimer invalidate] (bear in mind that an invalidated timer cannot be reused, and you will need to create a new timer object in case you want to repeat this process).
Inside methodToAddImages you should have code to go over the array and add the images.
You can use a counter variable to track the index.
Another option (my recommendation) is to have a mutable copy of this array and add lastObject as a subview and then remove it from the mutable copy of your array.
You can do this by first making a mutableCopy in reversed order as shown:
NSMutableArray* reversedImages = [[[images reverseObjectEnumerator] allObjects] mutableCopy];
Your methodToAddImages looks like:
- (void)methodToAddImages
{
if([reversedImages lastObject] == nil)
{
[timer invalidate];
return;
}
UIImageView *imageView = [[UIImageView alloc] initWithFrame:(CGRectMake(40, 40, 40, 40))];
imageView.image = [reversedImages lastObject];
[self.view addSubview:imageView];
[reversedImages removeObject:[reversedImages lastObject]];
}
I don't know if you're using ARC or Manual Retain Release, but this answer is written assuming ARC (based on the code in your question).
You can use dispatch_after to dispatch a block, executed asynchronously that adds the image. Example:
for(int i = 0; numberOfImages; i++)
{
double delayInSeconds = 5.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
{
UIImageView *image = [UIImageView alloc]initWithFrame:CGRectMake(40, 40, 40, 40)];
image.image = [images objectAtIndex:i];
// Update the view on the main thread:
[self.view performSelectorOnMainThread: #selector(addSubview:) withObject: image waitUntilDone: NO];
});
}
Separate your code into a function, and call via NSTimer.
for (int i = 0; numberOfImages; i++) {
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:#selector(showImage)
userInfo:[NSNumber numberWithInt:i]
repeats:NO];
And then your function:
-(void) showImage:(NSTimer*)timer {
//do your action, using
NSNumber *i = timer.userInfo;
//Insert relevant code here
if (!done)
NSTimer *newTimer = [NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:#selector(showImage)
userInfo:[NSNumber numberWithInt: i.intValue+1]
repeats:NO];
}
}
userInfo is a convenient way of passing parameters to functions that you need to call (but they do have to be Objects). Also, by using repeats:NO, you don't have to worry about invalidating the timer, and there's no risk of leaving timer running in memory.
also this is best option. Try this
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
I think you'd be better off with an animation
for (int i = 0; i < numberOfImages; i++)
{
// Retrieve the image
UIImageView *image = [[UIImageView alloc] initWithFrame:CGRectMake(40, 40, 40, 40)];
image.image = [images objectAtIndex:i];
// Add with alpha 0
image.alpha = 0.0;
[self.view addSubview:image];
[UIView animateWithDuration:0.5 delay:5.0*i options:UIViewAnimationOptionAllowUserInteraction animations:^{
// Fade in with delay
image.alpha = 1.0;
} completion:nil];
}
Not exactly what you asked for, since all the views will be added immediately, and then faded-in, but I feel that you're actually trying to achieve that, like some sort of stacking of images, right?
In fact, if you plan on removing the previous image, you can do it in the completion block, like this:
UIImageView *imagePrevious = nil;
for (int i = 0; i < numberOfImages; i++)
{
// Retrieve the image
UIImageView *image = [[UIImageView alloc] initWithFrame:CGRectMake(40, 40, 40, 40)];
image.image = [images objectAtIndex:i];
// Add with alpha 0
image.alpha = 0.0;
[UIView animateWithDuration:0.5 delay:5.0*i options:UIViewAnimationOptionAllowUserInteraction animations:^{
// Add and fade in with delay
[self.view addSubview:image];
image.alpha = 1.0;
} completion:^(BOOL finished)
{
if (finished && imagePrevious)
{
[imagePrevious removeFromSuperview];
}
}];
imagePrevious = image;
}
I am trying to execute ball blasting effect to play sequentially. One after another.
What I have done yet:
For ball blasting effect i had used
UIButton *ballButton = (UIButton *)[cell viewWithTag:10];
ballButton.imageView.animationImages = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:#"1.png"],
[UIImage imageNamed:#"2.png"],
[UIImage imageNamed:#"3.png"],
[UIImage imageNamed:#"4.png"],
nil];
ballButton.imageView.animationDuration = 1;
ballButton.imageView.animationRepeatCount = 1;
and this line on code is attached to multiple buttons in a cell of a collection view.
I call these ballbutton.imageview start the animation like this
[UIView animateWithDuration:1 delay:5 options:UIViewAnimationOptionCurveEaseOut animations:^{
NSIndexPath *path2 = [NSIndexPath indexPathForRow:x inSection:0];
UICollectionViewCell *cell = [ballContainer cellForItemAtIndexPath:path2];
UIButton *ballObject = (UIButton *) [cell viewWithTag:10];
[ballObject.imageView startAnimating];
} completion:^(BOOL b){
NSLog(#" here i call next animation of ball blast to execute ");
}];
I nested 3 animations buttons like this.
First of all, why don't you create one big animation for all other three? The thing with the UIView animateWithDuration: is that it performs the animation block in the period of time you gave to it, i.e. setting the frame from (200,200) to (0,0) will move it proportionally in the time of a second, in your case. But UIImageView's properties regarding animations are made in such way that the animation is already done for you.
Personally, I would suggest using a timer, like this:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:ballObject.imageView.animationDuration
target:self
selector:#selector(performNextAnimation:)
userInfo:nil repeats:NO];
[ballObject.imageView startAnimating];
And in the performNextAnimation method:
- (void) performNextAnimation{
[timer invalidate]; // you have to access the timer you've scheduled with the animation
timer = nil;
/* code for starting the next animation */
}
this way i solved my issue.
initially i started animation by calling this
[self startAnim:index];
than implemented this StartAnim like this and problem solved.
-(void)StartAnim :(int)x{
NSIndexPath *path2 = [NSIndexPath indexPathForRow:x inSection:0];
UICollectionViewCell *cell = [ballContainer cellForItemAtIndexPath:path2];
UIButton *ballObject = (UIButton *) [cell viewWithTag:10];
[ballObject setBackgroundImage:nil forState:UIControlStateNormal];
ballObject.imageView.image = nil;
[ballObject.imageView startAnimating];
double delayInSeconds = 0.15;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
if(x-6>=0){
[self StartAnim :(x-6)];
}
});
}
I am working on with a simple animation that I have 10 button and "on click" of one button ( for example 5) all button should start animate one by on but they are animating the same time, please let me know what can be done or ..... Thanks
NSMutableArray* imagesArray = [[NSMutableArray alloc] init];
for (int images = 0; images < 15; images++) {
UIImage* buttonImage = [UIImage imageNamed:[NSString stringWithFormat:#"aaqqq00%02d.png", images]];
[imagesArray addObject:buttonImage];
}
NSArray* reversedAnim = [[imagesArray reverseObjectEnumerator] allObjects];
int buttonTag = button.tag;
for (int images = 1; images <= 10; images++) {
UIButton *animButton = (UIButton *)[self.view viewWithTag:images];
if (images <= buttonTag) {
animButton.imageView.animationImages = imagesArray;
[animButton setImage:
[UIImage imageNamed:#"aaqqq0014.png"] forState:UIControlStateNormal];
animButton.adjustsImageWhenHighlighted = NO;
animButton.imageView.animationDuration = 1; //whatever you want (in seconds)
animButton.imageView.animationRepeatCount = 1;
[animButton.imageView startAnimating];
} else {
if (currentButtonTag_ >= images) {
animButton.imageView.animationImages = reversedAnim;
[animButton setImage:
[UIImage imageNamed:#"aaqqq0000.png"] forState:UIControlStateNormal];
animButton.adjustsImageWhenHighlighted = NO;
animButton.imageView.animationDuration = 0.2; //whatever you want (in seconds)
animButton.imageView.animationRepeatCount = 1;
[animButton.imageView startAnimating];
}
}
}
As you iterate through your loop, have a variable that holds the desired delay, and add to it at the end of each loop. We'll call this delay.
Now, instead of calling:
[animButton.imageView startAnimating];
Do this:
[animButton.imageView performSelector:#selector(startAnimating) withObject:nil afterDelay:delay];
And each button will start animating after the accumulated delay.
You need to give some delay time and duration time.
[UIView animateWithDuration:0.6
delay:2.0
options: UIViewAnimationCurveEaseOut
animations:^{S1Button.frame = CGRectMake(20, 10, 50, 10);S1buttonA.alpha = 0;}
completion:nil];
Set this for every animation.