iOS can't select segment in UISegmentedControl - ios

I have a UISegmentedControl in a headerview in a UITableView. For some reason, I cannot select any segments, whenever I do, it automatically selects the last segment in the array and I cannot select anything else. When I remove the action, I can select which ever. No idea what's going on.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if (section == 1) {
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0,0, 320, 40)]; // x,y,width,height
NSArray *itemArray = [NSArray arrayWithObjects:#"E01", #"E02", #"E03", #"E05", #"E06", #"T05", #"E17", #"E19", nil];
control = [[UISegmentedControl alloc] initWithItems:itemArray];
[control setFrame:CGRectMake(30.0, 0, (tableView.bounds.size.width) - 60, 40)];
[control setSelected:YES];
[control setSegmentedControlStyle:UISegmentedControlStylePlain];
[control addTarget:self action:#selector(unitSegmentControl:) forControlEvents:UIControlEventValueChanged];
[headerView addSubview:control];
return headerView;
}
return nil;
}

I'm not aware what calling setSelected does on a UISegmentedControl, but I would suggest you use:
control.selectedSegmentIndex = anNSInteger;
to set the initial selected segment. I doubt that's your issue though.
Something else to consider if you have a scrolling table view,
viewForHeaderInSection
will get called for that section every time that header scrolls onto the screen, meaning that your segmented control will get reinitialized every time the header gets scrolled onto the screen, and you will lose your selected index.
Other than that maybe you could post the code for your unitSegmentControl selector. Possibly it's causing the table view to reload and your viewForHeaderInSection to be called again, thus reinitializing your segmented controller.

Related

How to do large tableView header?

I want to do a large tableView header like in Health app in iOS 11. I added a screenshot to show this element in red text. How to do large a tableView header?
If I understand your question correctly (and unfortunately the screenshot is gone), you can do that using the prefersLargeTitles property. This works on iOS 11 and higher only.
For instance:
if (#available(iOS 11.0, *)) {
self.navigationController.navigationBar.prefersLargeTitles = YES;
self.navigationItem.largeTitleDisplayMode = UINavigationItemLargeTitleDisplayModeAlways;
} else {
// Fallback on earlier versions
}
You can call this code in viewDidLoad or viewWillAppear of your UITableViewController.
Just set the frame property of the tableHeaderView.
No recorded Data is table view header. you can customize the tableview header with viewForHeaderInSection method of tableview. Your question is already answered in this link. Changing Font Size For UITableView Section Headers
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UILabel *TESTLabel = [[UILabel alloc] init];
TESTLabel .frame = CGRectMake(20, 8, 320, 40);
TESTLabel .font = [UIFont boldSystemFontOfSize:18];
TESTLabel .text = [self tableView:tableView titleForHeaderInSection:section];
UIView *headerView = [[UIView alloc] init];
[headerView addSubview: TESTLabel];
return headerView;
}
TRY THIS

UITableView header doesn't listen to scroll

I have a simple UITable and i want a little image before the table starts, so i use a tableheader so far so good, this works quite nicely
self.table.tableHeaderView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:img]];
only the weird thing is when i try to scroll on a table view row the table scrolls but when i try to scroll on the header nothing happens, its like the scroll listener isnt listening to to the scroll event on the header.
Just to be clear the header does scroll when you scroll the table as one piece ( and that is the desired behaviour )
Im googleling like crazy but kant seem to find the answer, thanks!!
some extra code
- (void)viewDidLoad
{
[super viewDidLoad];
// set the table header
self.table.tableHeaderView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"header"]];
// add empty footer view to hide empty cells
self.table.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
// set title
self.navigationItem.title = [self.catData objectForKey:#"titlePage"] ? [self.catData objectForKey:#"titlePage"] : [self.catData objectForKey:#"title"];
}
Use Grouped Tableview. then you can scroll your table view.
Have you tried setting your header view with :
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
return [[UIImageView alloc] initWithImage:[UIImage imageNamed:img]];
}
You need to implement this below method:--
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGRect rect = self.tableView.tableHeaderView.frame;
rect.origin.y = MIN(0, self.tableView.contentOffset.y);
self.tableView.tableHeaderView.frame = rect;
}

Adding UIButton to UITableView section header

I have a UITableView with 1 section and for the section header, I would like to keep everything about the header the same but simply add a button on the right side. I cannot put the button in the navigation controller because the two available spots to put such a button are already occupied by other buttons.
Here you can see the result of what I tried to do. Now all I want to do is put an add button on the right side of the header, but what I have tried didn't work. I also tried some other solutions on StackOverflow, but they did not accomplish quite what I wanted to do. Additionally, if there is a better way of creating an add button, please let me know. I tried using a UIBarButtonItem but I couldn't figure out how to add its view to an actual view. Thanks!
This is what I have so far in my delegate:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIButton *addButton = [[UIButton alloc] init]; //I also tried setting a frame for the
button, but that did not seem to work, so I figured I would just leave it blank for posting
the question.
addButton.titleLabel.text = #"+";
addButton.backgroundColor = [UIColor redColor];
[self.tableView.tableHeaderView insertSubview:addButton atIndex:0];
//I feel like this is a bad idea
return self.tableView.tableHeaderView;
}
- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 50;
}
The problem is that your self.tableView.tableHeaderView is nil at this point in time, therefore you can't use it. So what you need to do is, create a UIView, add title, and button to it, style them, and return it.
This should add a title and button to your section header, you still need to style the title with correct font and size but will give you an idea.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
CGRect frame = tableView.frame;
UIButton *addButton = [[UIButton alloc] initWithFrame:CGRectMake(frame.size.width-60, 10, 50, 30)];
[addButton setTitle:#"+" forState:UIControlStateNormal];
addButton.backgroundColor = [UIColor redColor];
UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 100, 30)];
title.text = #"Reminders";
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
[headerView addSubview:title];
[headerView addSubview:addButton];
return headerView;
}
From iOS 6, you can also implement
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
in your UITableViewDelegate. For example:
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
if (section == 0) {
if ([view.subviews.lastObject isKindOfClass:[UIButton class]]) {
return;
}
UIButton *button = [UIButtonbuttonWithType:UIButtonTypeSystem];
button.frame = CGRectMake(view.frame.size.width - 160.0, 0, 160.0, view.frame.size.height); // x,y,width,height
[button setTitle:#"My Button" forState:UIControlStateNormal];
[button addTarget:self action:#selector(sectionHeaderButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[view addSubview:button];
}
}
If you are interested in Swift solution:
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let frame = tableView.frame
let button = UIButton(frame: CGRectMake(5, 10, 15, 15)) // create button
button.tag = section
// the button is image - set image
button.setImage(UIImage(named: "remove_button"), forState: UIControlState.Normal) // assumes there is an image named "remove_button"
button.addTarget(self, action: #selector(TestController.remove(_:)), forControlEvents: .TouchUpInside) // add selector called by clicking on the button
let headerView = UIView(frame: CGRectMake(0, 0, frame.size.width, frame.size.height)) // create custom view
headerView.addSubview(button) // add the button to the view
return headerView
}
You might want to specify the height of the header in the section. This must be in sync with the height of the custom view:
override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return CGFloat(30)
}
You have 2 choices, both via your tableView.delegate. The first involves implementing the delegate method
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
which enables you to basically return anything you want in a custom view, which will be used as the header for your desired section. This could be as simple as
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIButton *addButton = [UIButton buttonWithType:UIButtonTypeContactAdd];
[addButton addTarget:self action:#selector(SomeMethod:) forControlEvents:UIControlEventTouchUpInside];
return addButton;
}
which will put a round info button (centered) as your header. But more likely you'll want to create an actual UIView object and populate it with your button (and a section title label?) and lay everything out as you like [see others' answers for how to do this].
However, the second approach is probably better for the general case of simply adding a button to (one of) your section headers [I know you stated 1 section, but a lot of folks will probably land on this question wanting to do similar in a multi-section table]. This involves implementing the delegate method
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
and basically adding your button to the header after-the-fact; specifically
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
// Remove old button from re-used header
if ([view.subviews.lastObject isKindOfClass:UIButton.class])
[view.subviews.lastObject removeFromSuperview];
if (section == MySectionNumberWithButton) {
UIButton *addButton = [UIButton buttonWithType:UIButtonTypeContactAdd];
[addButton addTarget:self action:#selector(SomeMethod:) forControlEvents:UIControlEventTouchUpInside];
[view addSubview:addButton];
// Place button on far right margin of header
addButton.translatesAutoresizingMaskIntoConstraints = NO; // use autolayout constraints instead
[addButton.trailingAnchor constraintEqualToAnchor:view.layoutMarginsGuide.trailingAnchor].active = YES;
[addButton.bottomAnchor constraintEqualToAnchor:view.layoutMarginsGuide.bottomAnchor].active = YES;
}
}
Note, because the tableView re-uses headers, in a multi-section table you must make sure to remove any button you might have previously added, otherwise you'll eventually end up with buttons in unwanted sections. Then, if this is the right section, add the button to the existing header. Note, I'm using NSLayoutAnchor (iOS 9+) to layout the button for brevity; you can do the same with NSLayoutConstraint (iOS 6+)
This approach has the distinct advantage that - for just adding a button - you dont have to recreate the regular layout to match all your other (non-button) headers, or worry about margins changing when you rotate your device, etc. In particular, the header title is untouched and will retain any global appearance settings you may have defined for table headers (eg font, color, ...), all of which you'd have the messy job of re-creating if you took the tableView:viewForHeaderInSection: approach.
You can do that by using the below code, you can put any type of view in header view but you have to specify the frame for it.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *view=[[UIView alloc]init];
UIButton *addButton=[UIButton buttonWithType:UIButtonTypeContactAdd];
addButton.frame=CGRectMake(250, 0, 100, 50);
[view addSubview:addButton];
[tblView.tableHeaderView insertSubview:view atIndex:0];
//I feel like this is a bad idea
return view;
}
Swift 4 :
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let frame = tableView.frame
let button = UIButton(frame: CGRect(x: 5, y: 10, width: 15, height: 15))
button.tag = section
button.setImage(UIImage(named: "remove_button"), for: UIControl.State.normal)
button.addTarget(self,action:#selector(buttonClicked),for:.touchUpInside)
let headerView = UIView(frame: CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height))
headerView.addSubview(button)
return headerView
}
This functions handles the button click:
#objc func buttonClicked(sender:UIButton)
{
if(sender.tag == 1){
//Do something for tag 1
}
print("buttonClicked")
}
If you want to use Interface Builder to build your section header, you can use a UITableViewCell as the header. Create a prototype cell for your header in your UITableView, customize as you would any other cell, including adding labels, buttons, and constraints.
You can instantiate in your UITableViewController lazily:
lazy var headerCell: MyHeaderTableViewCell = {
let cell = tableView.dequeueReusableCell(withIdentifier: "Header") as! MyHeaderTableViewCell
return cell
}()
To make it the header:
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return headerCell
}

Subview won't hide correctly in custom UITableViewCell on toggling of UITableView edit

So my app has an editable and sortable UITableView in its left hamburger basement:
To make sure the table cells were skinny enough to show both the delete button and the sorting drag handle on edit, I created a custom UITableViewCell to handle the editing of the table cells:
Everything works fine on edit, but when I tap done, instead of hiding the delete button hangs around:
The code for this, inside of BookmarkTableViewCell.m, is:
- (void)setEditing:(BOOL)editing animated:(BOOL)animate
{
[super setEditing:editing animated:animate];
if (editing) {
for (UIView * view in self.subviews) {
if([[[view class] description] isEqualToString:#"UITableViewCellReorderControl"])
{
UIView *movedReorderControl = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetMaxX(view.frame), CGRectGetMaxY(view.frame))];
[movedReorderControl addSubview:view];
[self addSubview:movedReorderControl];
CGRect newFrame = movedReorderControl.frame;
newFrame.origin.x = -35;
movedReorderControl.frame = newFrame;
}
}
UIImageView *deleteBtn = [[UIImageView alloc]initWithFrame:CGRectMake(10, 10, 24, 24)];
[deleteBtn setImage:[UIImage imageNamed:#"icon_delete.png"]];
[self addSubview:deleteBtn];
}
}
Let me know if you need anymore details. Any insight into fixing this would be great. Thanks!
It looks like you're adding the deleteBtn, but you aren't removing it. if editing is false you should locate the deleteBtn cell and remove it from it's superview so it goes away.

Calling a UITableViewDelegate method from ViewController

I'd like to call the following method from my view controller class:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
However for the life of me I can't figure out how to do it. I tried:
UIView *view = [tableView viewForHeaderInSection:section];
UIView *view = [self viewForHeaderInSection:section];
UIView *view = [self tableView:viewForHeaderInSection:section];
All give me errors. It's that extra tableView: bit on the beginning. Can anyone give some advice or at least explain what that tableView:(UITableView *)tableView means?
Thanks!
Steve
I don't know why you would want to call it, but if it is implemented in the same object that you're calling it from then you can use self:
UIView* view = [self tableView:tableView viewForHeaderInSection:section];
otherwise, you can get the delegate from the tableView and call the delegate:
id<UITableViewDelegate> theDelegate = tableView.delegate;
UIView* view = [theDelegate tableView:tableView viewForHeaderInSection:section];
Why would you want to call it? This is one of the UITableViewDelegate methods that are normally called automatically when the table is being constructed by the tableView. The tableView class object fills in the parameters that it needs when it makes the call to this method. The view controller only needs to provide the right delegate methods, customized by you, so it can set it up properly.
Did you customize the code, as in this example, in your delegate class?
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// create the parent view that will hold header Label
UIView* customView = [[UIView alloc] initWithFrame:CGRectMake(10.0, 0.0, 300.0, 44.0)];
// create the button object
UILabel * headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.opaque = NO;
headerLabel.textColor = [UIColor blackColor];
headerLabel.highlightedTextColor = [UIColor whiteColor];
headerLabel.font = [UIFont boldSystemFontOfSize:20];
headerLabel.frame = CGRectMake(10.0, 0.0, 300.0, 44.0);
// If you want to align the header text as centered
// headerLabel.frame = CGRectMake(150.0, 0.0, 300.0, 44.0);
headerLabel.text = <Put here whatever you want to display> // i.e. array element
[customView addSubview:headerLabel];
return customView;
}
I'm not near my Mac, or I would give you one of my own examples. But this is the general way this method is used.
By the way, you can see that the parameter tableView is not referenced in the sample code above. If you really want to call this method, use nil. UITableViewDelegate protocol allows the controller to be delegate for more than one tableView. If this happens, the method should test to see which tableView is reference, so that specialized behavior can be accommodated for each tableView.
Additional info:
If you just want to see what the height of your tableView's header is, you can evaluate its sectionHeaderHeight property. There are other properties like this, such as sectionFooterHeight and rowHeight.
You should know that delegate methods are there to help the tableView, using your customization. So the delegate method tableView:heightForHeaderInSection: is actually for you to customize the header height. Your delegate methods tells the tableView what the height is. It isn't a way to examine a property of the tableView.
Apples documentation says that if you customize by using tableView:heightForHeaderInSection: then the tableView sectionHeaderHeight is not valid. You would expect this, because that property refers to the height of all of the section headers.
Using the sectionHeaderHeight property, which you can write to in this case, you can set all of the headers to the same height.
Here is some sample code from something I'm working on now. I've added an NSLog statement for you.
resultsTableVC = [[[ResultsTableVC alloc] initWithController:self] retain];
self.tableView = [[[UITableView alloc] initWithFrame:CGRectMake(0, 110, self.view.frame.size.width, self.view.frame.size.height-120) style:UITableViewStyleGrouped] retain];
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
self.tableView.autoresizesSubviews = YES;
self.tableView.layer.cornerRadius = 10.0f;
self.tableView.delegate = resultsTableVC;
self.tableView.dataSource = resultsTableVC;
self.tableView.backgroundView = nil;
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.separatorColor = [UIColor defaultResultTableBackgroundColor];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
[self.view addSubview:self.tableView];
NSLog(#"header: %f, row: %f", tableView.sectionHeaderHeight, tableView.rowHeight);
(Someone will probably point out that I don't need some of those retains. I'm still working on that.)
This tells me that the standard section height is 100 and the standard row height is 44.0. I have a pointer to my tableView, a property that I can use through this class.
Now if you are setting the header height using tableView:heightForHeaderInSection: then you should have the height already calculated in your program. I don't think you can query for the height of a particular section (or row) once you set it.
Does this help?

Resources