I have a button that seems superfluous. I want to remove the button and place its functionality (animating a simple bar chart with associated labels) into a method that gets called upon return from a user input view controller.
It seemed simple enough to rename the existing IBAction method and put the call to the replacement method into the delegate method that handles the transition back to the original View controller. However, this produced an unexpected result.
Here's a screenshot. The button in question is the red one (Show Graph):
The problem is that before the change, the two labels (firstLabel and secondLabel) over the bars would appear after the bars animate into position. After the method change (the creation code is unchanged), the labels appear instantly upon return to the VC, before the bars animate.
Here's the original IBAction method attached to the button:
- (IBAction)goButtonAction:(id)sender
{
switch (goButtonKey)
{
case 0:
{
}
break;
case 1:
{
[self handleAvsAAction];
[self doTheMathAvsA];
[self makeBarChart];
}
break;
case 2:
{
[self handleCvsCAction];
[self doTheMathCvsC];
[self makeBarChart];
}
default:
break;
}
[self.goButton setUserInteractionEnabled:NO];
}
And here's the new method:
- (void) showGraph
{
switch (goButtonKey)
{
case 0:
{
}
break;
case 1:
{
[self handleAvsAAction];
[self doTheMathAvsA];
[self makeBarChart];
}
break;
case 2:
{
[self handleCvsCAction];
[self doTheMathCvsC];
[self makeBarChart];
}
default:
break;
}
[self.goButton setUserInteractionEnabled:NO];
}
Here's the code (from makeBarChart) that produces the bar animation and the labels. For brevity, I'm just showing one bar--the other is essential identical, except being driven by different data:
switch (thisRiser.tag)
{
case 1:
{
[self.chartView addSubview:firstLabel];
[firstLabel setHidden:YES];
[UIView animateWithDuration:.6
delay:.2
options: UIViewAnimationCurveEaseOut
animations:^
{
// Starting state
thisRiser.frame = CGRectMake(35, self.chartView.frame.size.height, barWidth, 0);
thisRiser.backgroundColor = startColor1;
// End state
thisRiser.frame = CGRectMake(35, self.chartView.frame.size.height, barWidth, -focusBarEndHeight);
thisRiser.backgroundColor = endColor1;
thisRiser.layer.shadowColor = [[UIColor blackColor] CGColor];
thisRiser.layer.shadowOpacity = 0.7;
thisRiser.layer.shadowRadius = 4.0;
thisRiser.layer.shadowOffset = CGSizeMake(5.0f, 5.0f);
thisRiser.layer.shadowPath = [UIBezierPath bezierPathWithRect:thisRiser.bounds].CGPath;
}
completion:^(BOOL finished)
{
firstLabel.frame = CGRectMake(thisRiser.frame.origin.x, thisRiser.frame.origin.y - 65, barWidth, 60);
[firstLabel.titleLabel setFont:[UIFont boldSystemFontOfSize:12]];
firstLabel.titleLabel.numberOfLines = 0;
firstLabel.titleLabel.textAlignment = NSTextAlignmentCenter;
[firstLabel setTitle:[NSString stringWithFormat:#"%#\n%.2f%%\nTime--%#",focusItemName,focusItemPercent,actualDurationFocusItem] forState:UIControlStateNormal];
firstLabel.backgroundColor = [UIColor clearColor];
[firstLabel setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[firstLabel setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
[firstLabel setHidden:NO];
[firstLabel addTarget:self action:#selector(firstLabelAction:) forControlEvents:UIControlEventTouchUpInside];
[firstLabel setUserInteractionEnabled:YES];
[thisRiser setUserInteractionEnabled:YES];
// NSLog(#"Done!");
}];
}
break;
It doesn't seem reasonable that such a straightforward change would cause this effect. I've tried it several times to be sure I'm not breaking anything, and it seems that I am not.
Any ideas?
Try to put all the code from "completion:^(BOOL finished)" block, inside an if statement:
completion:^(BOOL finished) {
if (finished) {
// Do all that stuff, including make the label visible...
}
}
The problem was resolved by moving the call to the code from the former button action method (refactored into showGraph) from viewDidLoad into `viewDidAppear, as suggested by #rdelmar in a comment. Many thanks!
Related
I'm having a problem with reading taps on navigation bar (I need to open dropdown menu by tapping on title field, just like in telegram and etc. but not in swift)
I know that basically its unreadable, and already've tried with taprecognizer, but it didn't work for me any good.
Now my menu opens with rightbarbutton - that's ugly.
How can I deal with it?
Now string that drops menu (placed in viewDidLoad) looks like:
navbar = [[UIBarButtonItem alloc]initWithTitle:#"navbar" style:UIBarButtonItemStylePlain target:self action:#selector(navigationTitleTapGestureAction:)];
and a part that declares button:
NSArray *buttons = #[navbar <<...a few more buttons...>>];
self.navigationItem.rightBarButtonItems = buttons;
EDIT: additional code from the comments:
- (IBAction)navigationTitleTapGestureAction:(id)sender {
automaticDisappearanceCanceled_ = YES;
if (menuToolbarVisible_) {
[self hideMenuAnimated:YES];
}
else {
[self showMenuAnimated:YES];
}
}
- (void)showMenuAnimated:(BOOL)animated {
[self.view layoutIfNeeded];
self.toolbarTopLayoutConstraint.constant = 0.f;
self.menuToolbar.hidden = NO;
[UIView animateWithDuration:animated ? ToolbarMenuAnimationDuration : 0.f animations:^{
[self.view layoutIfNeeded];
} completion: ^(BOOL finished) {
}];
menuToolbarVisible_ = YES;
}
- (void)hideMenuAnimated:(BOOL)animated {
[self.view layoutIfNeeded];
self.toolbarTopLayoutConstraint.constant = -ToolbarMenuHeight;
[UIView animateWithDuration:animated ? ToolbarMenuAnimationDuration : 0.f animations: ^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self.menuToolbar.hidden = YES;
}];
menuToolbarVisible_ = NO;
}
As far is I know you just want to get taps on the text on the center of navigation bar you can do this by adding a UIButton in the titleView like this :-
UIButton *centerButton=[[UIButton alloc]initWithFrame:CGRectMake(0, 0, 44.0, 44.0)];
[centerButton setTitle:#"Center" forState:UIControlStateNormal];
[centerButton addTarget:self action:#selector(action) forControlEvents:UIControlEventTouchDown];
self.navigationItem.titleView=centerButton;
I have a scrollview(timesScrollView) which is added as a subview on a view(dropDownView).The view is hidden until a particular button is pressed, when that button is pressed view will appear.
(IBAction)how_many_times_btn_click:(id)sender{
if(howMany==false){
for(UIView *view in dropDownView.subviews)
{
[view removeFromSuperview];
}
howMany=true;
duration=false;
how_many_times_btn.backgroundColor=[UIColor colorWithRed:130/255.0f green:189/255.0f blue:31/255.0f alpha:1.0f];
durationBtn.backgroundColor=[UIColor colorWithRed:62/255.0f green:67/255.0f blue:79/255.0f alpha:1.0f];
startBtn.backgroundColor=[UIColor colorWithRed:62/255.0f green:67/255.0f blue:79/255.0f alpha:1.0f];
dropDownView.hidden=NO;
dropDownView.frame=CGRectMake(0, 0, self.view.frame.size.width,70);
dropDownView.backgroundColor=[UIColor colorWithRed:37/255.0f green:42/255.0f blue:54/255.0f alpha:1.0f];
//dropDownView.backgroundColor=[UIColor whiteColor];
targetLbl=[[UILabel alloc]init];
targetLbl.frame=CGRectMake(0, 30, dropDownView.frame.size.width,30);
targetLbl.text=#"TARGET";
targetLbl.textColor=[UIColor whiteColor];
targetLbl.font=[UIFont boldSystemFontOfSize:22];
targetLbl.textAlignment=NSTextAlignmentCenter;
how_many_Lbl=[[UILabel alloc]init];
how_many_Lbl.frame=CGRectMake(0, targetLbl.frame.origin.y+targetLbl.frame.size.height, dropDownView.frame.size.width, 20);
how_many_Lbl.textAlignment=NSTextAlignmentCenter;
how_many_Lbl.text=#"HOW MANY TIMES WILL YOU DO IT?";
how_many_Lbl.textColor=[UIColor colorWithRed:65/255.0f green:71/255.0f blue:80/255.0f alpha:1.0f];
how_many_Lbl.font=[UIFont systemFontOfSize:10.0f];
hideViewBtn=[UIButton buttonWithType:UIButtonTypeCustom];
hideViewBtn.frame=CGRectMake(dropDownView.frame.size.width-30,20,20,20);
[hideViewBtn setImage:[UIImage imageNamed:#"Close Icon [ x ]"] forState:UIControlStateNormal];
[hideViewBtn addTarget:self action:#selector(hideView) forControlEvents:UIControlEventTouchUpInside];
//hideViewBtn.backgroundColor=[UIColor whiteColor];
self.timesScroll=[[LTInfiniteScrollView alloc] initWithFrame:CGRectMake(0, how_many_Lbl.frame.origin.y+how_many_Lbl.frame.size.height+16, dropDownView.frame.size.width, 102)];
//self.timesScroll.backgroundColor=[UIColor whiteColor];
self.timesScroll.verticalScroll=NO;
self.timesScroll.dataSource=self;
self.timesScroll.maxScrollDistance=5;
self.timesScroll.contentInset=UIEdgeInsetsMake(0, self.timesScroll.frame.size.width/2-31, 0,self.timesScroll.frame.size.width/2-31 );
self.timesScroll.userInteractionEnabled=YES;
self.timesScroll.exclusiveTouch=YES;
dropDownView.frame=CGRectMake(0, 0, self.view.frame.size.width,_timesScroll.frame.origin.y+_timesScroll.frame.size.height+20);
[self viewWillAppear:YES];
[dropDownView addSubview:targetLbl];
[dropDownView addSubview:how_many_Lbl];
[dropDownView addSubview:hideViewBtn];
[dropDownView addSubview:_timesScroll];
}
else
{
[self hideView];
}
}
The method above is what I am using to create view.
Now my problem is that when that particular button(how_many_times_btn) is pressed again all views are first removed then added as you can see and scrollview starts from initial position but I want it show from where I left it last time how_many_times_btn was clicked.
Hope you can understand What I am trying to say....if not I am happy to elaborate furthur.
you can get the last position by delegate methods
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
nslog(#"%f %f",scrollView.contentOffset.x,scrollView.contentOffset.y);
}
and store the x and y value and set
scrollView.contentOffset = CGPointMake(x,y);
You can save contentOffsetto one variable of CGPoint. And use this variable 's value later to scroll the UIScrollview.
Something like below line of code :
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
contentOffset = scrollView.contentOffset;
}
When button pressed write below line of code:
self.timesScroll .contentOffset = contentOffset;
I'm using LTInfiniteScrollview in which there is a method 'reloadDataWithInitialIndex'
-(void)reloadDataWithInitialIndex:(NSInteger)initialIndex
{
for (UIView *view in self.scrollView.subviews) {
[view removeFromSuperview];
}
self.views = [NSMutableDictionary dictionary];
self.visibleViewCount = [self.dataSource numberOfVisibleViews];
self.totalViewCount = [self.dataSource numberOfViews];
[self updateSize];
_currentIndex = initialIndex;
self.scrollView.contentOffset = [self contentOffsetForIndex:_currentIndex];
[self reArrangeViews];
[self updateProgress];}
This method is called in 'viewWillAppear'
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.viewSize = CGRectGetWidth(self.view.frame) / Number_of_visibleViews;
self.timesScroll.delegate=self;
[self.timesScroll reloadDataWithInitialIndex:howIndex];}
I just passed previous index value here.
This question already has answers here:
Animating only the image in UIBarButtonItem
(4 answers)
Closed 8 years ago.
I have an UIButton created by the following code
button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:[UIImage imageNamed:#"refresh_icon.png"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:#"reload_selected.png"] forState:UIControlStateSelected];
[button addTarget:self action:#selector(buttonAction:)forControlEvents:UIControlEventTouchUpInside];
[button setFrame:CGRectMake(0, 0, 20 , 20)];
Here when it's clicked the selector buttonAction is called and I am animating the button by a 360 degree rotation like this
- (void) buttonAction : (id) sender {
NSLog(#"Reload Button Clicked");
[self runSpinAnimationOnView:self.button duration:1.0 rotations:1.0 repeat:0];
}
- (void) runSpinAnimationOnView:(UIView*)view duration:(CGFloat)duration rotations:(CGFloat)rotations repeat:(float)repeat;
{
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 /* full rotation*/ * rotations * duration ];
rotationAnimation.duration = duration;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = repeat;
[view.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
}
It's working good but it's not that I actually want. I want that , when my button is clicked then button will take the image "reload_selected.png" (which I set for UIControlStateSelected) as background and then run the animation. When the animation is finished then button will have to return to it's actual background ("refresh_icon.png") again.
Can anyone suggest some change in code that will help me achieve the action I described above ? Thanks in advance for your help.
Can you try like this,
[UIView animateWithDuration:YOURDURATION
delay:0
options:(UIViewAnimationOptionCurveLinear)
animations:^ {
[button setImage:[UIImage imageNamed:#"reload_selected.png"] forState:UIControlStateSelected];
button.transform = CGAffineTransformRotate(CGAffineTransformIdentity,M_PI * 2);
}
completion:^(BOOL finished) {
[button setImage:[UIImage imageNamed:#"refresh_icon.png"] forState:UIControlStateNormal];
}
];
Instead of using Core Animation, you can use animateWithDuration:animations:completion: method of UIView. This method allows you to specify a completion block whick you can use to reset the image once the animation is completed.
EDIT:
Do something like
[view animateWithDuration:duration animations:^{
//Do your animations here
} completion: ^(BOOL finished){
if(finished) {
//reset the image
}
}];
To specify the animations you might want to animate the view's transform property using CGAffineTransformRotate.
my goal is to create a simple popover view over a bar button in my tool bar. So apparently Apple doesn't want me to create this on my iPhone. But i already saw something familiar on other apps.
So instead of using the UIPopOver thing from Apple, i like to create an UIView which appears when the bar button is clicked. And disappears when it is clicked again. It would be over the top if i also could create the little arrow which points to the button (you know which arrow i mean :D). But this is not relevant at this time. I just want to create this "popover appears and disappears with the same button". My "solution" right know is not a solution:
- (IBAction)buttonPressed:(id)sender
{
UIView *myPopOverView = [[UIView alloc] initWithFrame:CGRectMake(25, 25, 500, 250)];
myPopOverView.alpha = 0.0;
myPopOverView.layer.cornerRadius = 5;
myPopOverView.layer.borderWidth = 1.5f;
myPopOverView.layer.masksToBounds = YES;
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(testNSLog)
forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"Show myPopOverView" forState:UIControlStateNormal];
button.frame = CGRectMake(10, 10, 100, 30);
[myPopOverView addSubview:button];
[self.view addSubview:myPopOverView];
[UIView animateWithDuration:0.4 animations:^{
[myPopOverView setAlpha:1.0];
} completion:^(BOOL finished) {}];
}
So i don't have a clue on how to do that with this code fragment. It appears right away as i want. But i don't know how to create this toggle. I tried with a simple Bool-If-Toggle, but it didn't work. And i don't really know how to remove it from my view either.
Can you guys help me with this?
Thanks in advance!
Ok i solved it.
i defined a UIView in the .h-File and instantiate it in ViewDidLoad, then i did:
- (IBAction)buttonPressed:(id)sender
{
if (showedOptions == NO) {
[self.view addSubview:self.popoverView];
[UIView animateWithDuration:0.4 animations:^{
[self.popoverView setAlpha:1.0];
} completion:^(BOOL finished) {}];
showedOptions = YES;
return;
} else {
showedOptions = NO;
[self.popoverView removeFromSuperview];
}
}
I want to use a control I found on CocoaControls called SDNestedTable:https://github.com/serverdensity/ios-SDNestedTable
I have subclassed the SDNestedTableViewController class but I want to change the background color of the table cells and there is no provided way to do that.
The other classes in the library are SDGroupCell and SDSubCell which inherit from SDSelectableCell. SDSelectableCell contains the 3 methods to change the background depending on the state of the cell.
Here are the relevant methods in SDSelectableCell.m:
- (void) styleEnabled
{
for (UIView *view in checkBox.subviews) [view removeFromSuperview];
[checkBox addSubview:onCheckBox];
checkBox.alpha = 1.0;
itemText.alpha = 1.0;
self.backgroundView.backgroundColor = UIColorFromRGBWithAlpha(0x0d2e4d, 1.0);
}
- (void) styleDisabled
{
for (UIView *view in checkBox.subviews) [view removeFromSuperview];
[checkBox addSubview:offCheckBox];
checkBox.alpha = 1.0;
itemText.alpha = 0.4;
self.backgroundView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:1.0];
}
- (void) styleHalfEnabled
{
for (UIView *view in checkBox.subviews) [view removeFromSuperview];
[checkBox addSubview:onCheckBox];
checkBox.alpha = 0.45;
itemText.alpha = 0.7;
self.backgroundView.backgroundColor = UIColorFromRGBWithAlpha( , 1.0);
}
I can see two ways of doing this, but I'm a newb and want to verify the best way to handle this:
1) Just change the code in SDSelectableCell.m. I'd have to change 3 lines to set the 3 colors and then I'm done. However, I'm thinking it's bad practice to import libraries like this and just change the code. I can foresee issues in the future if someone working on the project has to reimport the library and doesn't know it was changed.
1a) I guess I could also just rename/refactor everything so that it isn't SD-whatever anymore, which at least would prevent someone else from thinking it's the original SDNestedTable library.
2) I could subclass SDSelectableCell and override those 3 methods. Although, this would require me to subclass every other class in the library, since they instantiate SDSelectable cell and I'd have to change all that.
3) Some other way? Categories and Extensions don't seem like they'd work, but maybe I'm missing something.
After giving the github code a quick look, it looks like they provide a simple way for you to setup the cells any way you'ld like. In your SDNestedTableDelegate implement the -mainTable:itemDidChange: method.
- (void)mainTable:(UITableView *)mainTable itemDidChange:(SDGroupCell *)item
{
SelectableCellState state = item.selectableCellState;
switch (state) {
case Checked:
item.backgroundView.backgroundColor = [UIColor ...];
break;
case Unchecked:
item.backgroundView.backgroundColor = [UIColor ...];
break;
case Halfchecked:
item.backgroundView.backgroundColor = [UIColor ...];
break;
default:
break;
}
}
UPDATE
It looks like the library gives you the a place to format items and subitems when you subclass SDNestedTableViewController by overriding -mainTable:setItem:forRowAtIndexPath: and -item:setSubItem:forRowAtIndexPath:. Combining that with the above item did change code and extracting common functionality gives you:
- (void)PRIVATE_finalizeSelectableCell:(SDSelectableCell *)item
{
SelectableCellState state = item.selectableCellState;
switch (state) {
case Checked:
item.backgroundView.backgroundColor = [UIColor ...];
break;
case Unchecked:
item.backgroundView.backgroundColor = [UIColor ...];
break;
case Halfchecked:
item.backgroundView.backgroundColor = [UIColor ...];
break;
default:
break;
}
}
- (void)mainTable:(UITableView *)mainTable itemDidChange:(SDGroupCell *)item
{
[self PRIVATE_finalizeSelectableCell:item];
}
- (SDGroupCell *)mainTable:(UITableView *)mainTable setItem:(SDGroupCell *)item forRowAtIndexPath:(NSIndexPath *)indexPath
{
[self PRIVATE_finalizeSelectableCell:item];
return item;
}
- (SDSubCell *)item:(SDGroupCell *)item setSubItem:(SDSubCell *)subItem forRowAtIndexPath:(NSIndexPath *)indexPath
{
[self PRIVATE_finalizeSelectableCell:subItem];
return subItem;
}