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;
}
Related
Thank you for looking at the question.I am using the open source project called ICView controller https://github.com/iltercengiz/ICViewPager I would like to ask how can i set the background color of the tabs to transparent so that the lower part of the background image in content view controller can be shown.I set all the factors to clear color in the delegate as shown below. However, the tabs' background turns into black. I have been looking for answers from web and stack but no results have been found. Can anyone give me some suggestions? Thank a lot
- (UIColor *)viewPager:(ViewPagerController *)viewPager colorForComponent:(ViewPagerComponent)component withDefault:(UIColor *)color {
switch (component) {
case ViewPagerIndicator:
return [UIColor clearColor];
break;
case ViewPagerContent:
return [UIColor clearColor];
break;
case ViewPagerTabsView:
return [UIColor clearColor];
break;
}
return color;
}
Use this code , it may help you
- (UIColor *)viewPager:(ViewPagerController *)viewPager colorForComponent:(ViewPagerComponent)component withDefault:(UIColor *)color {
switch (component) {
case ViewPagerIndicator:
return [UIColor whiteColor];
case ViewPagerTabsView:
return [UIColor colorWithRed:244 green:67 blue:54 alpha:0.4];
case ViewPagerContent:
return [UIColor whiteColor];
default:
return color;
}
}
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!
I want to change the tintColor property according to tabbar's selected index. The code I'm using now is not working, all the tabbar views have this code:
- (void)viewDidAppear:(BOOL)animated{
switch (self.tabBarController.selectedIndex) {
case 0:
self.tabBarController.tintColor = [UIColor colorWithRed:147/255 green:22/255 blue:0/255 alpha:1.0];
break;
case 1:
self.tabBarController.tintColor = [UIColor whiteColor];
break;
case 2:
self.tabBarController.tintColor = [UIColor greenColor];
break;
default:
break;
}
}
You don't need to do that; instead, put this in the viewWillAppear: method of your contained controllers:
Controller 1:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.tabBarController.tabBar.tintColor = [UIColor blueColor];
}
Controller 2:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.tabBarController.tabBar.tintColor = [UIColor yellowColor];
}
This assumes iOS5+. Hope this helps.
I am trying to create a UISegmentedControl programatically. I have a UIViewController in the storyboard with nothing in it.
.h file
UISegmentedControl *segmentedControl;
NSString *feedBackButtonTitle;
NSString *contactsButtonTitle;
and here are the property declarations.
#property (nonatomic,retain) IBOutlet UISegmentedControl *segmentedControl;
-(void) segmentedControlIndexChanged;
In viewDidLoad: I have initalized and added the UISegmentedControl.
NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];
if ([language isEqualToString:#"en"]){
contactsButtonTitle = [[[configFileDictionary objectForKey:#"Contacts"] objectForKey:#"Label"] objectForKey:#"en"];
feedBackButtonTitle = [[[[[configFileDictionary objectForKey:#"Contacts"] objectForKey:#"Contact"]objectForKey:#"Feedback"]objectForKey:#"Label"]objectForKey:#"en"];
}
else if([language isEqualToString:#"fr"]){
contactsButtonTitle = [[[configFileDictionary objectForKey:#"Contacts"] objectForKey:#"Label"] objectForKey:#"fr"];
feedBackButtonTitle = [[[[[configFileDictionary objectForKey:#"Contacts"] objectForKey:#"Contact"]objectForKey:#"Feedback"]objectForKey:#"Label"]objectForKey:#"fr"];
}
NSArray *itemsArray = [[NSArray alloc] initWithObjects:contactsButtonTitle, feedBackButtonTitle, nil];
segmentedControl = [[UISegmentedControl alloc] initWithItems:itemsArray];
segmentedControl.segmentedControlStyle = UISegmentedControlStylePlain;
//segmentedControl.selectedSegmentIndex = 0;
segmentedControl.frame = CGRectMake(0.0f, 0.0f, 320.0f,40.0f);
[segmentedControl addTarget:self action:#selector(segmentedControlIndexChanged) forControlEvents:UIControlEventValueChanged];
// [self.view addSubview:segmentedControl];
// Create view for contact display.
[self createViews];
and this the (void)segmentedControlIndexChanged
-(void)segmentedControlIndexChanged
{
switch (self.segmentedControl.selectedSegmentIndex)
{
case 0:
[self createViews];
break;
case 1:
[self showFeedbackForm];
break;
default:
break;
}
}
This is showing the segmented control on the screen just fine, but when I click on the options in the segmentedcontrol, it always goes into the option case 0. segmented control and opens [self createViews];
On inserting breakpoints at the line case 0, I noticed that the option _selectedSegment in segmentedControl is 1. This doesn't make any sense.
Ok so I created in my UIViewController a property segmentedControl and then wrote only that code:
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *itemsArray = [[NSArray alloc] initWithObjects:#"a", #"b", nil];
self.segmentedControl = [[UISegmentedControl alloc] initWithItems:itemsArray];
self.segmentedControl.segmentedControlStyle = UISegmentedControlStylePlain;
self.segmentedControl.selectedSegmentIndex = 0;
self.segmentedControl.frame = CGRectMake(0.0f, 0.0f, 320.0f,40.0f);
[self.segmentedControl addTarget:self action:#selector(segmentedControlIndexChanged) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:self.segmentedControl];
}
-(void)segmentedControlIndexChanged
{
switch (self.segmentedControl.selectedSegmentIndex)
{
case 0:
NSLog(#"createviews");
break;
case 1:
NSLog(#"showfeedbackform");
break;
default:
break;
}
}
It works for me perfectly - logging the proper choices.
As you say the _segmentedControl is all right - notice that I use dot notation to get segmentedControl. This might be the case since when you're not using dot notation - you're not calling the getter.
Edit
To sum up a little - segmentedControl from your .h file is redundant - it's just another UISegmentedControl. Your property can be referenced by dot notation - self.segmentedControl. Or by synthesized name (made by default) _segmentedControl.
So what you're doing is referencing to this .h object when initializing and adding your UISegmentedController but when segmentedControlIndexChanged is called - you change it in your property which is not even visible.
Ok a few things here:
Since you got a property, use self.segmentedControl instead of segmentedControl
With a simple change in your selector signature life is just easier:
[self.segmentedControl addTarget:self
action:#selector(segmentedControlIndexChanged:)
forControlEvents:UIControlEventValueChanged]; // Notice the colon
-(void)segmentedControlIndexChanged:(id)sender
{
switch ([sender selectedSegmentIndex])
{
case 0:
[self createViews];
break;
case 1:
[self showFeedbackForm];
break;
default:
break;
}
}
Hi im trying to use segmented control to swap between three map views however its not working.
My IBAction method is as follows.
- (IBAction)segmentSwitch:(id)sender {
NSLog(#"inside segmented switch");
NSLog(#"selected segment %#",selectedSegment);
if (selectedSegment == 0) {
mapView.mapType = MKMapTypeStandard;
}
else{
mapView.mapType = MKMapTypeHybrid;
}
}
I have declared UISegementedControl as an outlet and connected it to the xib view. I have also connected this method with touch down/touch up inside/outside. It still doesn't print the NSLog commands given above. Which means this method is not accessed at all?
Quick summary of how to set up a UISegmentedControl in IB for those dealing with more than two segments:
IBOutlet UISegmentedControl *segmentControl; in #interface (or set it as #property)
- (IBAction)segmentedControlIndexChanged:(id)sender; in .h before #end
drag "Segmented Control" into view and change "Style" to Plain, Bordered, or Bar
increment # of "Segments"
Choose "Segment" and edit the "Title" making sure "Enabled" is checked
Connect your segmentedControl to Files Owner
Connect your segmentedControlIndexChanged: action and select "Value Changed" NOT "Touch up Inside"!!
add some code, maybe a switch statement if you have say 4 segments:
-(IBAction)segmentedControlIndexChanged:(id)sender {
NSLog(#"segmentedControlIndexChanged");
switch (segmentControl.selectedSegmentIndex)
{
case 0:
{
NSLog(#"dateSegmentActive");
dateSegmentActive = YES;
noteSegmentActive = NO;
typeSegmentActive = NO;
userIDSegmentActive = NO;
[yourTable reloadData];
}
break;
case 1:
{
NSLog(#"noteSegmentActive");
dateSegmentActive = NO;
noteSegmentActive = YES;
typeSegmentActive = NO;
userIDSegmentActive = NO;
[yourTable reloadData];
}
break;
case 2:
{
NSLog(#"typeSegmentActive");
dateSegmentActive = NO;
noteSegmentActive = NO;
typeSegmentActive = YES;
userIDSegmentActive = NO;
[yourTable reloadData];
}
break;
case 3:
{
NSLog(#"userIDSegmentActive");
dateSegmentActive = NO;
noteSegmentActive = NO;
typeSegmentActive = NO;
userIDSegmentActive = YES;
[yourTable reloadData];
}
break;
default:
break;
}
}
In recent iOS versions, you need the braces for each case: or you will get errors. This also shows some bool flagging to keep track of what segment is active, maybe for your willDisplayCell method.
Hope you have selected the right method ValueChanged and also you have connected the outlet of your method properly.
The only thing you need to do now is to replace your code with your code.
- (IBAction)segmentSwitch:(UISegmentedControl *)sender
{
NSLog(#"inside segmented switch");
NSLog(#"selected segment %d",sender.selectedSegmentIndex);
if (sender.selectedSegmentIndex == 0)
{
mapView.mapType = MKMapTypeStandard;
}
else
{
mapView.mapType = MKMapTypeHybrid;
}
}
Try replacing this code with your code.
Hope this helps you.
You should use the ValueChanged action for detecting the the switch of segments.
Is selectedSegment your UISegmentedControl?
Then you code should be like:
- (IBAction) segmentSwitch:(id)sender {
if (self.selectedSegment.selectedSegmentIndex == 0) {
mapView.mapType = MKMapTypeStandard;
} else{
mapView.mapType = MKMapTypeHybrid;
}
}