Before, the company made a page similar to zhihu small round table, but it felt that some parts were not good enough after writing, so I wrote it again with Swift, and welcome you to point out any shortcomings

All you need to do is pass in a title array

Override func viewDidLoad() {super.viewdidLoad () let zeVC = ZEPageViewController() zevc.titlesarr = [" dynamic "," problem "," discussion "] self.addChildViewController(zeVC) self.view.addSubview(zeVC.view) // Do any additional setup after loading the view, typically from a nib. }Copy the code

The principle of

The hierarchical view of the project looks like this




I’m going to create a scrollView at the bottom that’s the same size as viewController.View and then I’m going to add the tableviewController to it Finally will tableviewController. TableView. ContentInset top set to you want the height of the (headerView + menuView) It then proxies the tableviewController’s offset to the main controller, which is used to calculate the movement of the top headerView and menuView Then main controller scrollview proxy method is invoked to calculate tableviewcontroller. ContentOffset

The main difficulty is calculating the contentInset and contentOffset of the three TableViewControllers

code

Take a look at global properties first

/** Screen width height */ let kZEScreenWidth = uiscreen.mainScreen ().bounds.size.width let kZEScreenHight = Uiscreen.mainscreen ().bounds.size.height /** Height of header and menu */ let kZEHeaderHight:CGFloat = 135 let kZEMenuHight:CGFloat = 50 Let KSCrollHorizon Y = kZEMenuHight+kZEHeaderHight let kNavigationHight:CGFloat = 64 /** Offset method operatio enum */ enum HeaderMenuShowType :UInt {case up = 1 // fixed on navigation case butTom = 2 // fixed on navigation} /** button Let COLOR_BUTTON_DEFAULT = uicolor. init(red: 124/255.0, green: 129/255.0, blue: 138/255.0, alpha: 1) let COLOR_BUTTON_SELECT = uicolor. init(red: 0/255.0, green: 127/255.0, blue: 255/255.0, alpha: 1)Copy the code

ZEPageViewController

Create a scrollView

/ * * at the bottom of the create scrollView and tableViewController added to the above * / func layoutBackgroundScrollView () {self. BackgroundScrollView = UIScrollView(frame: self.view.frame) self.backgroundScrollView?.pagingEnabled = true self.backgroundScrollView?.bounces = false self.backgroundScrollView?.delegate = self let floatArrCount = CGFloat(titlesArr.count) self.backgroundScrollView?.contentSize = CGSizeMake(floatArrCount*kZEScreenWidth,self.view.frame.size.height-64) // ScrollY = -kscrollHorizony // The tableView's offset is the opposite of the offset symbol assigned to it for I in 0.. < titlesArr.count { let floatI = CGFloat(i) let tableViewVC = ZETableViewController(style: UITableViewStyle. Plain) / / top tableView outflow HeaderView and position of MenuView tableViewVC tableView. ContentInset = UIEdgeInsetsMake(kScrollHorizY, 0, 0, 0 ) tableViewVC.delegate = self tableViewVC.view.frame = CGRectMake(floatI * kZEScreenWidth,0, self.view.frame.size.width, Self. View. Frame. The size. Height - 64) tableViewVC. Tags = titlesArr [I] / / add tableViewVC into an array of convenient management TableViewArr. Append (tableViewVC) self. AddChildViewController (tableViewVC)} / / when needed to add to the view, avoid started takes too much resources backgroundScrollView?.addSubview(tableViewArr[0].view) self.view.addSubview(backgroundScrollView!) }Copy the code

Create HeaderView MenuView

/** Create HeaderView and MenuView */ func layoutHeaderMenuView() NSBundle.mainBundle().loadNibNamed("ZEHeaderView", owner: self, options: nil).first as! ZEHeaderView headerView.frame = CGRectMake(0, 64, kZEScreenWidth, kZEHeaderHight) self.view .addSubview(headerView) // MenuView menuView = ZEMenuView(frame:CGRectMake(0,CGRectGetMaxY(headerView.frame),kZEScreenWidth,kZEMenuHight)) menuView.delegate = self menuView.setUIWithArr(titlesArr) self.view .addSubview(self.menuView) }Copy the code

And then call those two methods in ViewDidLoad

    override func viewDidLoad() {
        super.viewDidLoad()
        self.automaticallyAdjustsScrollViewInsets = false
        layoutBackgroundScrollView()
        layoutHeaderMenuView()
    }Copy the code



The control is now created

First, in ZETableViewController, set the offset at which the proxy method calls the tableView scroll

    override func scrollViewDidScroll(scrollView: UIScrollView) {
        self.delegate?.tableViewDidScrollPassY(scrollView.contentOffset.y)

    }Copy the code

And then you do it in ZEPageControl

func tableViewDidScrollPassY(tableviewScrollY: CGFloat) {// Calculate each change of value let seleoffSetY = tableviewScrollY - scrollY // synchronize the value of scrollY scrollY = tableviewScrollY // Offset beyond Navigation if scrollY >= -kzemenuhight {headerMenuViewShowType(.up)}else if scrollY <= -kscrollHorizony {// The offset exceeds Navigation. HeaderMenuViewShowType (.butTom)}else{// The only thing left to follow is to change the y value of headerView to the offset headerView.frame.origin.y -= seleoffSetY menuView.frame.origin.y = CGRectGetMaxY(headerView.frame) } } /** Because frequent use the header and the menu is fixed, so declare a method used to lazy * / func headerMenuViewShowType (showType: headerMenuShowType) {switch showType {case .up: menuView.frame.origin.y = kNavigationHight headerView.frame.origin.y = kNavigationHight-kZEHeaderHight break case .buttom: headerView.frame.origin.y = kNavigationHight menuView.frame.origin.y = CGRectGetMaxY(headerView.frame) break } }Copy the code

// Do not look at the lack of code, the previous version of the calculation is super messy… There’s a lot less code after sorting it out…




And then how you slide left to right

func scrollViewDidScroll(scrollView: UIScrollView) {/ / determine whether there are changes in X, here only deals with horizontal sliding if scrollX = = scrollView. ContentOffset. {X return; } if scrollY >= -kzemenuhight {scrollY = -kzemenuhight} for if scrollY = -kzemenuhight} for tableViewVC in tableViewArr { tableViewVC.tableView.contentOffset = CGPointMake(0, ScrollY)} / / used to change the status of menuView let rate = (scrollView. ContentOffset. X/kZEScreenWidth). Self menuView. ScrollToRate (rate) / / Plus 0.7 means that when I slide to 30% I load the next tableView backgroundScrollView, right? AddSubview (tableViewArr [Int (rate + 0.7)]. View) / / record scrollX x = scrollView contentOffset. X}Copy the code

Swiping left and right also involves clicking on the MenuView, so select the agent back in the MenuView

Func menuViewSelectIndex (index: Int) {/ / 0.3 seconds animation in order to appear not too abrupt UIView. AnimateWithDuration (0.3) {self. BackgroundScrollView? .contentOffset = CGPointMake(kZEScreenWidth*CGFloat(index),-kNavigationHight) } }Copy the code

The detailed code of HeaderView and MenuView can be seen in DEM, because they are customized according to different needs. If you want to modify the project for your own use, just change it in the specific View. If you change the height, please change it in the global properties

rendering




github:Github.com/Lafree317/Z…

Please click a few stars if you like