preface
Recently, according to the requirements of the project, we need to achieve an interface effect similar to clicking on the top menu of Taobao to locate the corresponding section, as follows:
The navigation menu at the top is responsible for navigation and locating the block position of the corresponding section. Click the corresponding menu and scroll to locate the corresponding module position.
Analysis of the
Roughly speaking, this effect can be divided into three key points:
- The menu is suspended
- Click the menu to locate the jump
- Scroll linkage menu items
After these three problems are solved, the effect is as follows:
According to the analysis, the actual main solution to the above three problems to achieve this scrolling effect. First lay out the Demo interface, a grouped UITableView with sections, and a tableViewHeader to complete the simple layout.
Menu suspension processing scheme
First of all, the implementation of menu suspension is not the suspension of the section of the system, because if the scrolling suspension is enabled, other sections will be suspended together, which will cause the loss of the menu bar. The ultimate goal is to ensure that the menu suspension and other sections follow the tableView to scroll. So it’s up to us to levitate the menu. In order to achieve the effect of suspension, you can switch the menu hierarchy according to the offset in the tableView proxy’s scrolling method, that is, if the scroll exceeds the menu display area, load the menu at the top of the suspension position, no scroll beyond the time, and then put the menu in the previous position. The implementation code is as follows:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{ CGFloat offsetY = scrollView.contentOffset.y; // [self hangOnMenu:offsetY]; // Menu linkage [self updateMenuTitle:offsetY]; } - (void)hangOnMenu:(CGFloat)offsetY{if(offsetY > (176-44)) {// Prevent multiple changes to the page hierarchyif ([self.selectMenu.superview isEqual:self.view]) {
return; Selectmenu. frame = CGRectMake(0, 64, SCREEN_WIDTH, 44); [self.view addSubview:self.selectMenu]; }else{// Prevent multiple changes to the page hierarchyif ([self.selectMenu.superview isEqual:self.tableView]) {
return; } selectMenu.frame = CGRectMake(0, 196, SCREEN_WIDTH, 44); [self.tableView addSubview:self.selectMenu]; }}Copy the code
Click the menu to locate the implementation of the jump
Click the menu to jump to the corresponding section position. If the tableView scrollToIndex method is simply used, it will be difficult to adjust the jump position, because this method can only be adjusted to the position of the corresponding cell, which will block part of the sectionHeader and lead to the inaccurate scrolling position. To keep scrolling positions accurate and under manual control, the setContentOffset method is used for scrolling content, using the rectForSection method to find the position of the corresponding section as follows:
- (LCSelectMenuView *)selectMenu{
if(! _selectMenu) { _selectMenu = [LCSelectMenuView new]; _selectMenu.frame = CGRectMake(0, 196, SCREEN_WIDTH, 44); _selectMenu.titleArray = @[@"Product Introduction"The @"Product Model"The @"Commodity parameters"The @"Relevant comments"The @"Related Recommendations"];
__weak typeof(self) _ws = self;
[_selectMenu setPageSelectBlock:^(NSInteger index) {
CGRect rect = [_ws.tableView rectForSection:index];
CGFloat offsetY = rect.origin.y - 20 - 44 - 44;
[_ws.tableView setContentOffset:CGPointMake(0, offsetY) animated:YES]; _ws.scrollFlag = YES; // Open the menu and click the flag to prevent the scroll agent didScrollView from firing}]; }return _selectMenu;
}
Copy the code
Scroll linkage menu items
Here is the most difficult to solve the scrolling menu title linkage problem. To ensure real-time synchronization of the current menu position during scrolling, we need to determine whether to scroll to the corresponding menu in real time during scrolling.
Because it is necessary to determine whether the current scrolling position reaches a menu, after loading the data in tableView, it is necessary to calculate and save the position of sectionHeader in tableView, so as to know whether the scrolling has reached the corresponding position of sectionHeader. In order to change the position of the menu when scrolling, the following calculation was made after the layout was completed:
- (void)markSectionHeaderLocation{ dispatch_async(dispatch_get_global_queue(0, 0), ^{ self.sectionLocationArray = nil; // Calculate the position of each packet headerfor (int i = 0; i < self.selectMenu.titleArray.count; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:i]; CGRect frame = [self.tableView rectForSection:indexPath.section]; // The offset of the first group is 10 less than the other groups CGFloat offsetY = (frame.origine.y-64-44); NSLog(@"offsetY is %f",offsetY); [self.sectionLocationArray addObject:[NSNumber numberWithFloat:offsetY]]; }}); }Copy the code
After the calculation, we only need to judge whether the scrolling position OffsetY position can complete the change of the menu position within the interval of each section. As follows:
/** contentOffsetY{title */ - (void)updateMenuTitle:(CGFloat)contentOffsetY{if(! Self. ScrollFlag) {/ / traversefor(int i = 0; i<self.sectionLocationArray.count; I++) {// last buttonif (i == self.sectionLocationArray.count - 1) {
if (contentOffsetY >= [self.sectionLocationArray[i] floatValue]) {
[self.selectMenu setCurrentPage:i]; }}else{
if (contentOffsetY >= [self.sectionLocationArray[i] floatValue] && contentOffsetY < [self.sectionLocationArray[i+1] floatValue]) {
[self.selectMenu setCurrentPage:i];
}
}
}
}
}
Copy the code
Need to pay attention to
One thing I want to emphasize here is that if I manually click on the menu it will trigger the tableView’s scrollDidScroll method, and because I’m going to set the position of the menu based on the offset of the scroll it’s going to mess up the position of the menu during scrolling, Therefore, a flag bit scrollFlag is added here to avoid the conflict of menu switching caused by scrolling.
In addition, if a web page webView is added to the cell, the location of the section will not be displayed because the cell does not scroll to the location of the cell, which will cause the deviation of the calculation of the position of the section, leading to the inaccurate problem of clicking the menu to jump to the corresponding section location. Therefore, if you add webView to the cell, please note that the solution is to display the cell with webView first, and then display other cells to complete the calculation of the section accurately.