I have an application with navigation controller and some table view controller. In table view controller I have a two section header my definitions:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (section == 0) {
UIView* customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 74)];
UIImageView *myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"toolbarTopBack.png"]];
UILabel *headline = [[UILabel alloc] initWithFrame:CGRectMake(11, 14, 305, 21)];
headline.backgroundColor = [UIColor clearColor];
headline.textColor = [UIColor whiteColor];
headline.font = [UIFont fontWithName:#"Helvetica Neue" size:21];
headline.text = searchPosition;
UILabel *subHeadline = [[UILabel alloc] initWithFrame:CGRectMake(11, 36, 305, 21)];
subHeadline.backgroundColor = [UIColor clearColor];
subHeadline.textColor = [UIColor grayColor];
subHeadline.font = [UIFont fontWithName:#"Helvetica Neue" size:16];
subHeadline.text = searchRegion;
[customView addSubview:myImageView];
[customView addSubview:headline];
[customView addSubview:subHeadline];
return customView;
} else {
// create the parent view that will hold header Label
UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 44)];
customView.userInteractionEnabled = YES;
UIImageView *myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"mainToolBar.png"]];
UIToolbar *topToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 44)];
topToolbar.barStyle = UIBarStyleDefault;
[topToolbar setBackgroundColor:[UIColor clearColor]];
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{
NSMutableDictionary *appSettingsData = [[NSMutableDictionary alloc] initWithDictionary:[appDelegate getAppStrings]];
NSArray *segmentItems = [NSArray arrayWithObjects:[NSString stringWithFormat:#"%# (%d)", [appSettingsData valueForKey:#"segmentButton4"], listCountOffers], [NSString stringWithFormat:#"%# (%d)", [appSettingsData valueForKey:#"segmentButton5"], [[appDelegate comunication] getSimilarCount:[appDelegate getCurrentCI] idPosition:idPosition idRegion:idRegion]], nil];
segmentControl = [[UISegmentedControl alloc] initWithItems:segmentItems];
segmentControl.frame = CGRectMake(6, 8, 308, 29);
segmentControl.autoresizingMask = UIViewAutoresizingFlexibleWidth;
segmentControl.segmentedControlStyle = UISegmentedControlStyleBar;
[segmentControl setTintColor:[UIColor grayColor]];
[segmentControl addTarget:self action:#selector(segmentedControlIndexChanged:) forControlEvents:UIControlEventValueChanged];
segmentControl.momentary = NO;
segmentControl.selectedSegmentIndex = 0;
});
UIBarButtonItem *toolbarItem = [[UIBarButtonItem alloc] initWithCustomView:segmentControl];
[topToolbar addSubview:toolbarItem.customView];
[customView addSubview:myImageView];
[customView addSubview:topToolbar];
return customView;
}
}
I use "static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{", because I need create this header only first time (because when I scroll table, method is call and call ... and this is wrong) ...
Everything works fine, when I create table view controller it show a headers, when I scroll it, nothing is recreating (it is fine), but when I push back button a then reopen tableview controller headers are empty. Where is problem ? Is there any solution, how to fix it ? Thanks a lot
Well, to me it looks like it's a problem with your static dispatch.
When you push the Back button, chances are that your view holding the table view is released (I don't know your code, but I suppose it is like that), meaning all internal variables are gone - except your static dispatch, which won't be called the next time you instantiate the view. So, during the next instantiation your segmentItems will not be created, but because the view was released, they are empty. You should solve your 'only create once' problem differently, e.g. by remembering the created segmentItems in a dictionary and getting them from there if they do not exist yet.
You're using dispatch_once without really needing to. The block will only be executed once, even if you subsequently remove the view controller from memory and deallocate segmentControl.
Use lazy loading instead - create a property for your segmentControl view within your view controller, and in the accessor for that, if the backing ivar is nil, create it then:
Your synthesize statement:
#synthesize segmentControl = _segmentControl
Your accessor method:
-(UISegmentedControl*)segmentControl
{
if (_segmentControl)
return _segmentControl;
UISegmentedControl *segmentControl = //... create your control here
self.segmentControl = segmentControl
return segmentControl;
}
Then when you want to use the view, use self.segmentControl. The first time you call it, it will be created, the subsequent times, it will be re-used.
check it with breakpoint and see the process. it maybe the memory allocation problem. See this it may help you. http://www.icodeblog.com/2010/12/10/implementing-uitableview-sections-from-an-nsarray-of-nsdictionary-objects/
Related
I have this code and it's working :
[_fieldEmail setFont:[UIFont fontWithName:#"ABeeZee-Regular" size:14]];
[_fieldPassword setFont:[UIFont fontWithName:#"ABeeZee-Regular" size:14]];
[_fieldRegisterName setFont:[UIFont fontWithName:#"ABeeZee-Regular" size:14]];
[_fieldRegisterEmail setFont:[UIFont fontWithName:#"ABeeZee-Regular" size:14]];
[_fieldRegisterPassword setFont:[UIFont fontWithName:#"ABeeZee-Regular" size:14]];
[_titleLogin setFont:[UIFont fontWithName:#"Raleway-ExtraLight" size:28]];
[_titleRegister setFont:[UIFont fontWithName:#"Raleway-ExtraLight" size:28]];
[_titleVote setFont:[UIFont fontWithName:#"Raleway-ExtraLight" size:28]];
also I have this code to apply padding left and padding right for each text field that I have :
UIView *fieldEmail = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
_fieldEmail.leftViewMode = UITextFieldViewModeAlways;
_fieldEmail.leftView = fieldEmail;
UIView *fieldPassword = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
_fieldPassword.leftViewMode = UITextFieldViewModeAlways;
_fieldPassword.leftView = fieldPassword;
UIView *fieldRegisterName = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
_fieldRegisterName.leftViewMode = UITextFieldViewModeAlways;
_fieldRegisterName.leftView = fieldRegisterName;
UIView *fieldRegisterEmail = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
_fieldRegisterEmail.leftViewMode = UITextFieldViewModeAlways;
_fieldRegisterEmail.leftView = fieldRegisterEmail;
UIView *fieldRegisterPassword = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
_fieldRegisterPassword.leftViewMode = UITextFieldViewModeAlways;
_fieldRegisterPassword.leftView = fieldRegisterPassword;
but I think it's an ugly code. because I have to set every text field and label one by one. Is it any better way to simplify this?
thank you very much..
I wouldn't do this way. If you check your code, you have a lot of similar pattern for your TextField.
Why don't create customTextField which is inherited from UITextField? And then, what you need is set font, leftViewMode and leftView in your customTextField class. When use it, just alloc with frame. Done!
In iOS 5 and later you can use the UIAppearance API to give a consistent style to your controls. Which iOS framework are you targeting?
OR
As suggested by Brain you can create a custom TextField and use that instead of UITextField. Your custom TextField would of course inherit from the UITextField but it will change different properties which you desire.
Make two arrays:
NSArray* fields= #[ _fieldEmail, _fieldPassword, _fieldRegisterName, _fieldRegisterEmail, _fieldRegisterPassword ];
NSArray* titles = #[ _titleLogin, _titleRegister, _titleVote ];
Then use makeObjectsPerformSelector:withObject: to execute a method call on all the array objects:
UIFont* font1= [UIFont fontWithName: #"ABeeZee-Regular" size: 14];
UIFont* font2= [UIFont fontWithName:#"Raleway-ExtraLight" size:28];
[fields makeObjectsPerformSelector: #selector(setFont:) withObject: font1];
[titles makeObjectsPerformSelector: #selector(setFont:) withObject: font2];
As for the second task you can simply use iteration and put the created UIView objects in a mutable array, if you need to use them later. If you want call them by name, then also a dictionary is a good idea:
NSArray* keys= #[ #"fieldEmail", #"fieldPassword", #"fieldRegisterName", #"fieldRegisterEmail", "fieldRegisterPassword" ];
NSMutableDictionary* fieldsDict= [[NSMutableDictionary alloc] init];
for(NSString* key in keys) {
UIView* field= [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
field.leftViewMode= UITextFieldViewModeAlways;
field.leftView= field; // I hope that this property is weak
[fieldsDict setObject: field forKey: key];
}
You could try to loop through all the subviews and check if they are an instance of UITextField or any subclass of UITextField. If they are, you can set the font property.
I quickly wrote some sample code to show you how you could do this:
for (UIView *subview in [[self view] subviews]) {
if ([subview isKindOfClass:[UITextField class]]) {
UITextField *textField = (UITextField *)subview;
[textField setFont:[UIFont fontWithName:#"ABeeZee-Regular" size:14.f]];
}
}
Be aware of the fact that this code only loops through the 'closest' children of [self view] and thus won't modify views deeper in the hierarchy.
I am trying to customize my tableView in my IOS app. When my tableView(or rather array) is empty, I want to display a customized label instead of the items in the tableView. The label I am referring to is "label0". But something is terribly wrong, my [label0 setHidden:YES]; or [label0 setHidden:NO]; only works in the first block of the if "method"? In the second block (if else) nothing happens no matter what I try to set the label as (hidden or shown).
What have I missed? I cannot see my own fault?
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 30)] autorelease];
UILabel *label0 = [[[UILabel alloc] initWithFrame:CGRectMake(0, 25, tableView.bounds.size.width - 0, 100)] autorelease];
if ([self.searchResults count] == 0){
headerView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"lista2.png"]];
UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(5, 3, tableView.bounds.size.width - 5, 18)] autorelease];
label.text = #"Information";
label.textColor = [UIColor whiteColor];
label.backgroundColor = [UIColor clearColor];
[headerView addSubview:label];
label0.text = #"Test test test";
label0.textColor = [UIColor blackColor];
label0.backgroundColor = [UIColor whiteColor];
[tableView addSubview:label0];
[label0 setHidden:NO];
}
else {
headerView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"lista2.png"]];
UILabel *label2 = [[[UILabel alloc] initWithFrame:CGRectMake(5, 3, tableView.bounds.size.width - 5, 18)] autorelease];
label2.text = #"Search results";
label2.textColor = [UIColor whiteColor];
label2.backgroundColor = [UIColor clearColor];
[headerView addSubview:label2];
[label0 setHidden:YES];
}
return headerView;
}
EDIT
I have moved the code to viewDidLoad and set the property for the UILabel. This have unfortunately not solved my problem....
UILabel *label0 = [[[UILabel alloc] initWithFrame:CGRectMake(0, 25, tableView.bounds.size.width - 0, 100)] autorelease];
[tableView addSubview:label0];
if ([self.searchResults count] == 0){
label0.text = #"Test test test";
label0.textColor = [UIColor blackColor];
label0.backgroundColor = [UIColor whiteColor];
[label0 setHidden:NO];
}
else {
[label0 setHidden:YES];
}
This is because your label0 is created every time this method is called so in "else" you are referring to totally different object (not the one that you added to tableView when array was empty).
You shouldn't be adding subviews to tableView from this method. Consider using viewDidLoad. That way you will be adding label0 only once. To achieve that add label0 as property of your viewController.
You forgot to add label0 as subview please put this line in the else statement
[tableView addSubview:label0];
also I cannot see any benefit from doing so. I believe you can just hide the table view and show another view that has the label. but nesting views that way is not good when you come back to debug this code after 1 month you will struggle to understand it.
You say in your edit that you set the property for the UILabel (I assume you mean that you have a property called label0?). If this is so, then when you alloc init your label, it should be self.label0 = ..... not UILabel *label0 = .....
I am implementing the searchdisplay controller on the iPhone App, but will hit the following error when I try to click on the search bar (after a few tries)
Thread 1: EXC_BAD_ACCESS (code=1, address=0x30000008)
Snippet of my code as follows:
- (void)viewDidLoad
{
//Setting up the search bar for search display controller
UISearchBar *tempBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 34, 320, 44)];
self.sBar = tempBar;
[tempBar release];
self.sBar.delegate = self;
self.sBar.tintColor = [UIColor colorWithHexString:#"#b6c0c7"];
self.sBar.placeholder = #"Search DM friends";
self.searchDisplayController = [[[UISearchDisplayController alloc] initWithSearchBar:sBar contentsController:self]autorelease];
[self setSearchDisplayController:searchDisplayController];
[searchDisplayController setDelegate:self];
[searchDisplayController setSearchResultsDataSource:self];
self.searchDisplayController.searchResultsTableView.delegate = self;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 78)]autorelease];
headerView.backgroundColor = [UIColor colorWithHexString:#"#ebe7e6"];
if (tableView != self.searchDisplayController.searchResultsTableView){
//Search
UILabel *tagFriendsTitle = [[UILabel alloc]initWithFrame:CGRectMake(10, 10, 320, 16)];
tagFriendsTitle.font = [UIFont boldSystemFontOfSize:14];
tagFriendsTitle.backgroundColor = [UIColor clearColor];
tagFriendsTitle.text = #"Who should see this? Tag them!";
[headerView addSubview:tagFriendsTitle];
//THIS IS WHERE I GET MY EXC_BAD_ACCESS error
[headerView addSubview:self.sBar];
[tagFriendsTitle release];
}
return headerView;
}
I am not sure which part of my code is causing the error, but it seems that the sBar deallocated from memory when I try to add it to header subview? But I am not sure why I needed to click on the search bar multiple times before that happens.
This is how it looks on the iPhone, the searchbar forms part of the headerview
go to product>edit schems> enable nszombie objects and see what's the prblem there
If this is an assign property, you should probably change it to a retain property. And don't forget to set the property to nil in dealloc and viewDidUnload.
I want to set an image and a label at the center of my UINavigationBar, along all my navigation stack.
What I'm currently doing is adding it to my navigation item titleView.
The "problem" with this approach is that I have to call this method in the viewDidLoad for each view controller I push to my navigation stack.
The other way around is to add the UILable and UIImageView directly to the UINavigationBar, however that why I have to calculate the center myself, and in addition I read that's not the recommended approach.
Any Idea how to get what I want ?
My Code:
CGRect navTitle = controller.navigationController.navigationBar.bounds;
CGFloat aHeight = navTitle.size.height;
UIView* container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 163, aHeight)];
UIImage* statusImg = [UIUtils getStatusImage];
UIImageView *statusImage = [[UIImageView alloc] initWithFrame:CGRectMake(0,aHeight/2-statusImg.size.height/2, 33., 32.)];
statusImage.autoresizingMask = UIViewAutoresizingNone;
statusImage.image = statusImg;
statusImage.backgroundColor = [UIColor clearColor];
[statusImage setTag:1];
[statusImage setHidden:NO];
initWithFrame:CGRectMake(statusImage.frame.origin.x + 33. + 3, 0, 130., navTitle.size.height)];
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(statusImage.frame.origin.x + 33. + 3, 0, 130., navTitle.size.height)];
titleLabel.textAlignment = UITextAlignmentLeft;
titleLabel.lineBreakMode = UILineBreakModeTailTruncation;
titleLabel.textColor = [UIColor whiteColor];
titleLabel.font = [UIFont boldSystemFontOfSize:20.];
titleLabel.shadowOffset = CGSizeMake(1, -1);
titleLabel.opaque = NO;
titleLabel.backgroundColor = [UIColor clearColor];
[titleLabel setTag:2];
[container addSubview:statusImage];
[container addSubview:titleLabel];
controller.navigationItem.titleView = container;
[statusImage release];
[titleLabel release];
[container release];
Found the a nice way to do it :
Registering yourself as the delegate of UINavigationController will let you receive a callback each time a new controller is about to be pushed.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
Inside that function, getting the viewController and operating on his navigationitem will do the trick.
I am wanting to show a simple loading dialog when certain things are happening in my app. I figured I would just create a new view, add a label to that, and then set that view to a subView of my current view.
When doing this, I don't see anything!
Here is how I am writing my method:
- (void)showLoading {
UIView *loading = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
loading.backgroundColor = [UIColor blackColor];
UILabel *txt = [[UILabel alloc] initWithFrame:CGRectMake(198, 9, 94, 27)];
txt.text = #"Loading...";
txt.textColor = [UIColor whiteColor];
[loading addSubview:txt];
[super.view addSubview:loading];
[super.view bringSubviewToFront:loading];
[loading release];
[txt release];
}
Am I doing this completely wrong?
EDIT:
I added it to the viewDidLoad method, and it works how I want:
loading = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
loading.backgroundColor = [UIColor blackColor];
UILabel *txt = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 94, 27)];
txt.text = #"Loading...";
txt.textColor = [UIColor whiteColor];
[loading addSubview:txt];
[txt release];
[self.view addSubview:loading];
[self.view bringSubviewToFront:loading];
But when loading it from a method, it seems to lag, and not show up for a bit.
Although this doesn't directly answer your question, I'd recommend grabbing MBProgressHUD from GitHub and using that in place of a static label. Looks better, less code for you to directly maintain, etc. You can find it at http://github.com/matej/MBProgressHUD
The way I use it is by creating a subclass of UITableViewController and defining a handful of methods to show and hide the HUD view. From there, I call each relevant method when I'm loading or done loading.
Specifically, I have four methods: -hudView, -showLoadingUI, -showLoadingUIWithText:, and -hideLoadingUI.
-hudView creates a new MBProgressHUD object if one doesn't already exist, and adds it to the current view ([self.view addSubview:hudView]).
-showLoadingUI calls -showLoadingUIWithText: with a default title, -showLoadingUIWithText: just unhides the MBProgressHUD and sets a label value for it (self.hudView.labelText = #"foo";).
-hideLoadingUI hides the hudView ([self.hudView hide:YES]).
First, I don't think UIView has method called init. You may just call the super of it. The appropriate method you should call is - (id)initWithFrame:(CGRect)aRect . The frame is the position, the size of the View you want to display. More here
Another thing is why you call [super.view addSubView:], I think it should be self.view, isn't it?