UISegmentControl behaves unusual when placed in tableView's header
I have some problem implementing a segment control. Because i want it to be a fixed header so when i scroll i can always see it, i've implemented it in the
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
All is well till here, the segment control appears. The problem is when the segments are clicked. Although the function implemented with a selector is called and the segment control has the correct selectedSegmentIndex, the segments are not highlighted except the one that is initially set with the
sortControl.selectedSegmentIndex = 0;
in the viewForHeaderInSection
. This Segment interacts being highlighted and non-highlighted (when pressed again). Another weird thing is that when i press the other segments, the segment at 0 becomes highlighted.
Here is the complete code for the viewForHeaderInSection
:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIColor *tintColor = [UIColor colorWithRed:241.0/255 green:78.0/255 blue:35.0/255 alpha:1];
sortControl = [[UISegmentedControl alloc] initWithItems:
[NSArray arrayWithObjects:@"Distance", @"Rating", @"Name", nil]];
sortControl.segmentedControlStyle = UISegmentedControlStyleBar;
sortControl.tintColor = tintColor;
sortControl.frame = CGRectMake(20, 20, 280, 35);
sortControl.selectedSegmentIndex = 0;
[sortControl addTarget:self action:@selector(sortChanged) forControlEvents:UIControlEventValueChanged];
UIView *view=[UIView new];
view.frame = CGRectMake(0, 0, 320, 70);
view.backgroundColor =[UIColor blueColor];
[sortControl setEnabled:YES forSegmentAtI开发者_开发问答ndex:0];
[sortControl setEnabled:YES forSegmentAtIndex:1];
[sortControl setEnabled:YES forSegmentAtIndex:2];
view.userInteractionEnabled = YES;
[view addSubview:sortControl];
return view;
}
You have here two kind of problems: the first one has been arisen by AliSoftware in his previous response: you must set the momentary property to NO to avoid the flickering issue.
But the main problem is in the way you use the
tableView:viewForHeaderInSection:
delegate method. In this method you are recreating each time the same view, with two bad effects:
- the first is visible in your app: the segmented control is re-initialized and the selected button is set to the first one (index 0)
- the second is adding a memory leak each time the method is called by the table view. Consider that this method is called multiple times by the table view and out of your control: essentially each time the header is scrolled outside the screen and then it re-enters, the table needs to regenerate the view and calls the method again. On your code the segment is created but never released thus leaking.
The solution to this problem is to define a single instance for the header, set it initially to nil and then check if it is nil or not. If nil create it, if not use the previously generated instance. Another possible way to do this is in the code below. So create a static instance and use GCD's dispatch_once to create the segmented control only the first time. In this case you will never lose the current control status as it will be reused at each header call. You can improve the performance by also moving the whole header UIView creation inside the dispatch_once block, so avoiding extra allocs each time.
static UISegmentedControl *sortControl;
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIColor *tintColor = [UIColor colorWithRed:241.0/255 green:78.0/255 blue:35.0/255 alpha:1];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sortControl = [[UISegmentedControl alloc] initWithItems:
[NSArray arrayWithObjects:@"Distance", @"Rating", @"Name", nil]];
sortControl.segmentedControlStyle = UISegmentedControlStyleBar;
sortControl.tintColor = tintColor;
sortControl.frame = CGRectMake(20, 20, 280, 35);
sortControl.selectedSegmentIndex = 0;
});
[sortControl addTarget:self action:@selector(sortChanged) forControlEvents:UIControlEventValueChanged];
UIView *view=[UIView new];
view.frame = CGRectMake(0, 0, 320, 70);
view.backgroundColor =[UIColor blueColor];
sortControl.momentary = NO;
[sortControl setEnabled:YES forSegmentAtIndex:0];
[sortControl setEnabled:YES forSegmentAtIndex:1];
[sortControl setEnabled:YES forSegmentAtIndex:2];
view.userInteractionEnabled = YES;
[view addSubview:sortControl];
return view;
}
This is because you set sortControl.momentary = YES;
.
This property makes each segment of your SegmentedControl behaves like a "momentary button", meaning that when touching a segment, the segment is highlighted, then it triggers the event, and when you stop touching it comes back to its original state.
Removing this line (or setting this property to NO) should solve your issue.
精彩评论