I'm facing a bit complicated (at least it looks like it to me) problem with a custom UIView that I made (called EventBadge).
Here's the code of my custom class:
EventBadge.h
#interface EventBadge : UIView
- (void)setBadgeFillColor:(UIColor *) color;
- (void)setBadgeBorderColor:(UIColor *) color;
- (void)setBadgeIcon:(MyCustomIcons) icon;
#end
EventBadge.m
#implementation EventBadge
UIColor *badgeFillColor;
UIColor *badgeBorderColor;
MyCustomIcons badgeIcon;
- (void)drawRect:(CGRect)rect {
// Gets graphic context
CGContextRef context = UIGraphicsGetCurrentContext();
// Sets fill and border colors for cirlce
CGContextSetFillColor(context, CGColorGetComponents([badgeFillColor CGColor]));
CGContextSetStrokeColor(context, CGColorGetComponents([badgeBorderColor CGColor]));
// Set border line width
CGContextSetLineWidth(context, 2.0);
// Set rect containing circle as inset of rect
CGRect circle = CGRectInset(rect, 1, 1);
// Draw fill and stroke into rect
CGContextFillEllipseInRect(context, circle);
CGContextStrokeEllipseInRect(context, circle);
// Draws icon
[self drawBadgeIconInside:circle];
// Fill graphic context with path
CGContextFillPath(context);
}
/**
* Sets the background color for the badge and forces refresh
*/
- (void)setBadgeFillColor:(UIColor *) color{
badgeFillColor = color;
[self setNeedsDisplay];
}
/**
* Sets the background color for the badge and forces refresh
*/
- (void)setBadgeBorderColor:(UIColor *) color{
badgeBorderColor = color;
[self setNeedsDisplay];
}
/**
* Sets the icon for the badge and forces refresh
*/
- (void)setBadgeIcon:(MyCustomIcons) icon{
badgeIcon = icon;
[self setNeedsDisplay];
}
/**
* Draws the badge icon inside a rectangle
*/
- (void)drawBadgeIconInside:(CGRect) rect {
// Creates the inner rectangle from the original one (20x20)
CGRect iconContainer = CGRectInset(rect, 5, 5);
// Switch on badgeIcon: many different supported types
switch (badgeIcon) {
case EventLocation:
[StyleKit drawIconLocationWithFrame:iconContainer colorBase:[StyleKit blackMP]];
break;
case EventCar:
[StyleKit drawIconCarWithFrame:iconContainer colorBase:[StyleKit blackMP]];
break;
default:
MyLog(MyLogLevelError, #"INVALID MyCustomIcon");
break;
}
}
#end
I have a UITableView that can be filled with three different types of UITableViewCell, let's say TypeA, TypeB and TypeC.
TypeA and TypeB have different elements inside (UILabels, UIViews and so on) and they both have my EventBadge. TypeC is made of standard elements only.
Here's the code for all cell types:
TypeA.h
#interface TypeACell : UITableViewCell
#property (strong, nonatomic) IBOutlet UIView *prevRouteView;
#property (strong, nonatomic) IBOutlet UIView *nextRouteView;
#property (strong, nonatomic) IBOutlet UILabel *addressLabel;
#property (strong, nonatomic) IBOutlet EventBadge *eventBadgeView;
#end
TypeB.h
#interface TypeBCell : UITableViewCell
#property (strong, nonatomic) IBOutlet EventBadge *eventBadgeView;
#property (strong, nonatomic) IBOutlet UIView *prevRouteView;
#property (strong, nonatomic) IBOutlet UIView *nextRouteView;
#property (strong, nonatomic) IBOutlet UILabel *titleLabel;
#property (strong, nonatomic) IBOutlet UILabel *addressLabel;
#property (strong, nonatomic) IBOutlet UILabel *startTime;
#property (strong, nonatomic) IBOutlet UILabel *endTime;
#property (strong, nonatomic) IBOutlet CalendarColorView *calendarColor;
#end
TypeC.h
#interface TypeCCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UIView *routeView;
#property (strong, nonatomic) IBOutlet UILabel *duration;
#property (strong, nonatomic) IBOutlet UILabel *startTime;
#property (strong, nonatomic) IBOutlet UILabel *endTime;
#property (strong, nonatomic) IBOutlet CalendarColorView *calendarColor;
#property (strong, nonatomic) IBOutlet TransportTypeIconView *transportTypeView;
#end
I choose the type of cell inside cellForRowAtIndexPath method of my ViewController looking at the type of object stored in _tableviewData (the array used to fill the tableView). The code looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if([_tableviewData[indexPath.row] isKindOfClass:[EventTypeA class]]){
EventTypeA *event = (EventTypeA *)_tableviewData[indexPath.row];
return [self tableView:tableView createTypeACell:event atIndexPath:indexPath];
}
else if([_tableviewData[indexPath.row] isKindOfClass:[EventTypeB class]]) {
EventTypeB *event = (EventTypeB *)_tableviewData[indexPath.row];
return [self tableView:tableView createTypeBCell:event atIndexPath:indexPath];
}
else {
EventTypeC *event = (EventTypeC *)_tableviewData[indexPath.row];
return [self tableView:tableView createTypeCCell:event atIndexPath:indexPath];
}
}
Inside each method createTypeXCell I work directly on elements and set their properties. Everything is working as expected except properties set on my custom view. So TypeC works perfectly and everything in TypeA and TypeB works as expected except the settings for colors and icons on my eventBadgeView.
The behaviour that I get is that each eventBadgeView, no matter which UITableViewCell belongs to, gets painted with the properties of the last eventBadgeView being worked (the last item of the array).
If I scroll a little bit up or down the UITableView, enough to render one item, that item gets updated well, with the properties I set previously.
But if I scroll too much everything gets messed up once again.
I've noticed that drawRect gets always called a lot later with regards to setNeedsDisplay and I've learned that this is meant to be like this.
I've read on lots of SO posts (I'm not linking here all of them) and based on those what I've tried to do (with no luck) is:
call [cell.eventBadgeView setNeedsDisplay] inside the method that
creates the cell after setting properties
put all the part of setting cell properties and [cell.eventBadgeView setNeedsDisplay] inside dispatch_async
use a CALayer to "force" drawRect to be executed synchronously
Maybe as I'm new to ObjectiveC I'm missing some basic things, and I have big doubts on my custom EventBadge : UIView class since everything else works fine.
Thanks in advance for the help! :)
You should declare those variables out the implementation body otherwise, they'll be threated like gloabal variables in the .m file (more info about this here)
UIColor *badgeFillColor;
UIColor *badgeBorderColor;
MyCustomIcons badgeIcon;
put them in an interface (inside the .m file or directly in the .h) and declare them as #property
#interface MPEventBadge ()
#property (strong, nonatomic) UIColor *badgeFillColor;
#property (strong, nonatomic) UIColor *badgeBorderColor;
#property (nonatomic) MPInsertEventIcons badgeIcon;
#end
you can then access the variable like
_badgeFillColor = color;
Related
I currently have a header that displays a name, time, and a couple of buttons. This header should only appear if an appointment is selected in a dashboard, which is irrelevant here. However, once i logout and log back in, with no patient selected, the header view is displayed. I think this is because I did not deallocate the appointment object, and i'm not sure how to do that (i'm new to iOS programming).
Here's my code:
So I have the interface
#interface DashboardVC : CommonVC <UIActionSheetDelegate, HeaderViewDelegate, PracticeServiceDelegate> {
IBOutlet HeaderView *_headerView;
}
And inside the HeaderView object i have these properties:
#property (strong, nonatomic) CCAppointment *appointment;
#property (strong, nonatomic) IBOutlet UIButton *backButton;
#property (strong, nonatomic) IBOutlet UIView *currentPatientView;
#property (strong, nonatomic) IBOutlet UIImageView *avatarImageView;
#property (strong, nonatomic) IBOutlet UILabel *patientNameLabel;
I then, in dashboard VC, want to deallocate, but i'm not sure how... this is what i have:
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
How do I deallocate the properties so that the headerVIew does not show up?
if you want to destroy _headerView try:
[_headerView removeFromSuperview];
_headerView = nil;
I found a lot of how to use methods of chlidViewController. But I couldn't find how to change and set value of uitextfield and uiswitch from childViewController.
ChildViewController.h:
#protocol VVInformationTableViewControllerDelegate;
#interface VVInformationTableViewController : UITableViewController
#property (weak, nonatomic) id<VVInformationTableViewControllerDelegate> delegate;
#property (weak, nonatomic) IBOutlet UITextField *nameTextField;
#property (weak, nonatomic) IBOutlet UITextField *surnameTextField;
#property (weak, nonatomic) IBOutlet UITextField *emailTextField;
#property (weak, nonatomic) IBOutlet UITextField *locationTextField;
#property (weak, nonatomic) IBOutlet UITextField *headlineTextField;
#property (weak, nonatomic) IBOutlet UITextField *positionTextField;
#property (weak, nonatomic) IBOutlet UITextField *companyTextField;
#property (weak, nonatomic) IBOutlet UISwitch *messagesEnable;
#end
ParentViewControler.m:
- (void)viewDidLoad
{
self.currentAttendee = [VVAPIClient sharedClient].currentUser;
NSParameterAssert(self.currentAttendee);
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES];
self.infoTableController = [[VVInformationTableViewController alloc] initWithNibName:#"InformationTableViewController" bundle:nil];
[self addChildViewController:self.infoTableController];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.infoTableController.nameTextField.text = self.currentAttendee.firstName?:#"";
self.infoTableController.surnameTextField.text = self.currentAttendee.lastName?:#"";
self.infoTableController.emailTextField.text = self.currentAttendee.email?:#"";
self.infoTableController.locationTextField.text = self.currentAttendee.location?:#"";
self.infoTableController.headlineTextField.text = self.currentAttendee.headline?:#"";
self.infoTableController.positionTextField.text = self.currentAttendee.position?:#"";
self.infoTableController.companyTextField.text = self.currentAttendee.company?:#"";
}
-(void)viewDidLayoutSubviews{
self.infoTableController.messagesEnable.on = NO;
self.infoTableController.nameTextField.tag = 0;
self.infoTableController.surnameTextField.tag = 1;
self.infoTableController.emailTextField.tag = 2;
self.infoTableController.locationTextField.tag = 3;
self.infoTableController.headlineTextField.tag = 5;
self.infoTableController.positionTextField.tag = 6;
self.infoTableController.companyTextField.tag = 7;
}
Thanks for help.
As david says in his comment, don't.
It violates the encapsulation of the other view controller, and leads to spaghetti code.
You should treat another VCs (View Controller's) views as private.
What you should do is add properties to the child view controller to hold strings and other state data that you need to display. Then in your child view controller's viewWillAppear method, you can take the settings and apply them to your view hierarchy.
In your case, since what you're doing is displaying a whole bunch of information about "currentAttendee", (which I guess is a model object) you might want to think about passing a pointer to the whole attendee object to the child, and letting it display the information itself.
Or, of the child can edit the object, you might want to pass a copy, and use a delegate method when you want to commit the changes made in the child, or simply return if you want to discard changes.
Okay, I know there is a ton of these questions out there, because I've looked and tried some of the solutions. However, many of the ones I tried didn't work or the answer was too over my head for me to really grasp well - I'm a new developer and this is my first app. I learn by learning what not to do at this point.
I have the 'unrecognized selector sent to instance error' on a UIStepper stepperValueChanged setup. Here is the contents of the error message as it is given to me:
[DetailViewController stepperValueChanged]: unrecognized selector sent to instance 0x8637630
I will probably be ripped apart for this, but I can't really understand what's going on here - my only guess so far is to assume it has something to do with the only point in my code where stepperValueChanged exists - under the DetailViewController.h, as placed below:
#interface DetailViewController : UIViewController <UISplitViewControllerDelegate>
{
// Create GUI parameters for text fields, text labels, and the stepper:
IBOutlet UITextField *value1;
IBOutlet UITextField *value2;
IBOutlet UITextField *value3;
IBOutlet UISwitch *double_precision;
IBOutlet UILabel *value1_type;
IBOutlet UILabel *value2_type;
IBOutlet UILabel *value3_type;
IBOutlet UILabel *deriv_units;
IBOutlet UILabel *units;
IBOutlet UILabel *result;
IBOutlet UIStepper *stepper;
}
// Define properties of the above GUI parameters:
#property (nonatomic, retain) UITextField *value1;
#property (nonatomic, retain) UITextField *value2;
#property (nonatomic, retain) UITextField *value3;
#property (nonatomic, retain) UILabel *value1_type;
#property (nonatomic, retain) UILabel *value2_type;
#property (nonatomic, retain) UILabel *value3_type;
#property (nonatomic, retain) UILabel *deriv_units;
#property (nonatomic, retain) UILabel *units;
#property (nonatomic, retain) UILabel *result;
// Setup property as instance of UIStepper:
#property (nonatomic, strong) IBOutlet UIStepper *stepper;
// Setup NSString instance for segue linking:
#property (nonatomic, strong) NSString *equationName;
#property (strong, nonatomic) id detailItem;
#property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
// IBActions for the Calculate button and UIStepper instance:
- (IBAction)Calculate:(id)sender;
- (IBAction)stepperValueChanged:(id)sender;
- (IBAction)double_precision:(id)sender;
#end
Any ideas what is going on here? I don't have much of a clue, and if anyone can help explain to me what exactly is in play here while addressing it, I would be more than grateful.
If you need the contents of the implementation file, let me know; I'll edit it in.
Relevant areas of the .m file:
#interface DetailViewController ()
#property (strong, nonatomic) UIPopoverController *masterPopoverController;
- (void)configureView;
#end
#implementation DetailViewController
// Synthesize an instance of NSString for segue linking:
#synthesize equationName = _equationName;;
// Synthesize all other variables:
#synthesize value1 = _value1;
#synthesize value2 = _value2;
#synthesize value3 = _value3;
#synthesize value1_type = _value1_type;
#synthesize value2_type = _value2_type;
#synthesize value3_type = _value3_type;
#synthesize deriv_units = _deriv_units;
#synthesize result = _result;
#synthesize units = _units;
#synthesize stepper = _stepper;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
self.title = _equationName;
self.stepper.stepValue = 1;
self.stepper.autorepeat = NO;
self.stepper.continuous = YES;
self.stepper.wraps = YES;
int eqNum;
if ((_equationName = #"Energy-Frequency Relation"))
{
eqNum = 1;
self.stepper.minimumValue = 1;
self.stepper.maximumValue = 3;
}
else if ((_equationName = #"Energy-Frequency-Wavelength Relation"))
{
eqNum = 2;
self.stepper.minimumValue = 1;
self.stepper.maximumValue = 4;
}
// Take _equationName quantization and use it in a switch case to determine the formula that IBAction will use:
if (dflt)
{
switch (eqNum)
{
case 1:
if ((stepper.value = 1))
{
// Change deriv_units appropriately:
self.deriv_units.text = #"Energy (Joules)";
// This is a Planck's constant calculation, we hide the second variable as the constant
// is stored:
self.value2.hidden = YES;
self.value2_type.hidden = YES;
self.value3.hidden = YES;
self.value3_type.hidden = YES;
// Now we set up the parameters of the first entry variable:
self.value1_type.text = #"Frequency (in Hz)";
double frequency = [value1.text doubleValue];
double Planck = 6.626069e-34;
double energy = Planck * frequency;
// Now we set up the return field to return results:
NSString* resultIntermediate = [NSString stringWithFormat:#"%f", energy];
self.units.text = #"J";
}
// Identical function statements under ViewDidLoad truncated
}
bool dflt;
-(IBAction)KeyboardGoAway:(id)sender
{
[self.value1 resignFirstResponder];
[self.value1 resignFirstResponder];
[self.value1 resignFirstResponder];
}
-(IBAction)double_precision:(id)sender
{
// Sets double-float 'truth' value depending on state of UISwitch:
if (double_precision.on)
{
dflt = TRUE;
}
else
{
dflt = FALSE;
}
}
#pragma mark - Calculation runtime
-(IBAction)Calculate:(id)sender
{
// Assigns numerical information to _equationName data -
// switch case can only handle integer literals
// Also handles stepper incrementation and UILabel/UITextView hiding
NSString* resultIntermediate;
self.result.text = resultIntermediate;
}
The trailing colon makes the difference. Your action method is stepperValueChanged:,
but from the error message it seems that you connected the stepper to stepperValueChanged.
There are two reason for these kind of issues.
Probable case 1:
You first declared the function like - (IBAction)stepperValueChanged;
Connected the IBAction to stepper
Changed the method to - (IBAction)stepperValueChanged:(id)sender;
Solution:
Delete old connection in the interface builder and connect it again.
Probable case 2:
In your code you are calling the method using a selector where you written like: #selector(stepperValueChanged)
Solution:
Change the selector like: #selector(stepperValueChanged:)
Usually this means you are missing the method in your .m or you might of misspelled stepperValueChanged.
Edit: Actually, I believe it needs to be stepperValueChanged: with a semicolon.
so I'm writing Obj-C for iOS, and something "strange" is happening..
I have an MVC, with a UITableView (private):
#interface MVC ()
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#property (strong, nonatomic) CellVC *cell1;
#property (strong, nonatomic) CellVC *cell2;
#end
I load the table view up with a few custom cells. My custom cell class is actually a UIViewController... so I instantiate a few, and set cell.contentView to the corresponding CellVC.view inside the tableView:cellForRowAtIndexPath: method. My custom cell class:
#interface CellVC : UIViewController
#property (strong, nonatomic) IBOutlet UIKnob *knob1;
#property (strong, nonatomic) IBOutlet UIKnob *knob2;
#property (strong, nonatomic) IBOutlet UIKnob *knob3;
#property (strong, nonatomic) IBOutlet UIKnob *knob4;
#end
In case you're wondering, I've written a subclass of UIControl named UIKnob...
In CellVC's viewDidAppear: method, I've set a breakpoint to check the values of every knob. Each knob is non-nil, so I am happy... they have all been created.
My goal is to set MVC as the delegate of each knob. (4 knobs for each cell)
If I set a breakpoint anywhere in MVC, the value of each knob is nil??...
cell1.knob1.delegate = self;
will not work because the knobs only exist inside CellVC.m ...
Any ideas??
I'm newbie in the iOS development and I'm working in a projecte that it uses iOS5 and Storyboarding. I would like to create a reusable component, like a button, with a custom view (inside the button there will be some images and labels, it will be a big button), to create some of them in the same view of a Storyboard.
So I've created a XIB file (ItemClothes.xib) with a UIButton and inside of it some UIImagesViews and a UILabel. Then I've created a subclass of UIButton (UIItemClothes.h and UIItemClothes.m), with properties for UIImageViews and UILabel components.
UIItemClothes.h
#import <UIKit/UIKit.h>
#import "SCClothes.h"
#interface UIItemClothes : UIButton
#property (nonatomic, strong) IBOutlet UIImageView *imageClothes;
#property (nonatomic, strong) IBOutlet UIActivityIndicatorView *loadingImage;
#property (nonatomic, strong) IBOutlet UIImageView *seasonIconClothes;
#property (nonatomic, strong) IBOutlet UIImageView *categoryIconClothes;
#property (nonatomic, strong) NSString *idClothes;
#property (strong, nonatomic) IBOutlet UILabel *lblProva;
#end
UIItemClothes.m
#import "UIItemClothes.h"
#implementation UIItemClothes
#synthesize imageClothes = _imageClothes;
#synthesize loadingImage = _loadingImage;
#synthesize seasonIconClothes = _seasonIconClothes;
#synthesize categoryIconClothes = _categoryIconClothes;
#synthesize idClothes = _idClothes;
#synthesize lblProva = _lblProva;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self addSubview:[[[NSBundle mainBundle] loadNibNamed:#"ItemClothes" owner:self options:nil] objectAtIndex:0]];
}
return self;
}
#end
Then in the .XIB file I've set the class of UIButton as UIItemClothes, and make the relationships between XIB's UI components and my class properties.
So, after that, in the Storyboard, in the ViewController of one view I've written this code:
UIItemClothes *item = [[UIItemClothes alloc] initWithFrame:CGRectMake(0.0, 0.0, 200.0, 200.0)];
item.lblProva.text = #"test!";
[item.categoryIconClothes setImage:iconCategory];
item.seasonIconClothes.image = iconSeason;
[cell addSubview:item];
As you see, this component will be inside a TableViewCell, and the idea is to put more components (UIItemClothes) inside of it.
The problem is that the component is drawed but any outlet is set as I do in the code above.
Can anyone help me?
Thanks!
well, the problem has been resolved... Instead of having a custom subclass of UIButton, there will be needed a ViewController with all Outlets. Then in the other ViewController (StoryBoard) is initialized this new ViewController