Mobile Development 10 min read

Master iOS Pagination: Build Custom QiPageMenuView & QiPageContentView

This article explains how to create a flexible paginated interface in iOS using the custom QiPageMenuView and QiPageContentView components, covering implementation analysis, key properties, code examples, and two usage patterns that enable decoupled menu and content views for seamless scrolling and navigation.

360 Zhihui Cloud Developer
360 Zhihui Cloud Developer
360 Zhihui Cloud Developer
Master iOS Pagination: Build Custom QiPageMenuView & QiPageContentView

Implementation Overview

As an iOS developer, pagination controllers are frequently used for news‑style homepages. The article summarizes the key points for building a paginated UI in iOS.

Analysis of the Effect

The effect consists of two parts: QiPageMenuView (a UIScrollView‑based menu) and QiPageContentView (a UIPageViewController‑based content area). QiPageMenuView offers customizable properties such as item width, margins, fonts, colors, underline, and automatic resizing. QiPageContentView encapsulates UIPageViewController to avoid duplicated code and allows independent reuse.

QiPageMenuView Implementation

The header declares the interface and a series of @property definitions for appearance and layout. The core scrolling logic is implemented in scrollToPageItem:, which calculates the target offset based on the selected item's frame and adjusts the scroll view.

- (void)scrollToPageItem:(QiPageItem *)pageItem {
    [self refreshUnderLineViewPosition:pageItem];
    if (self.contentSize.width <= self.width) { return; }
    CGRect originalRect = pageItem.frame;
    CGRect convertRect = [self convertRect:originalRect toView:self.superview];
    CGFloat targetX;
    CGFloat realMidX = CGRectGetMinX(originalRect) + CGRectGetWidth(originalRect) / 2;
    if (CGRectGetMidX(convertRect) < CGRectGetMidX(self.frame)) {
        if (realMidX > CGRectGetMidX(self.frame)) {
            targetX = realMidX - CGRectGetMidX(self.frame);
        } else {
            targetX = 0;
        }
    } else {
        if (realMidX + CGRectGetMidX(self.frame) < self.contentSize.width) {
            targetX = realMidX - CGRectGetMidX(self.frame);
        } else {
            targetX = self.contentSize.width - CGRectGetMaxX(self.frame);
        }
    }
    [self setContentOffset:CGPointMake(targetX, 0) animated:YES];
}

Two usage patterns are shown: (1) initializing with a dataSource dictionary to customize colors, fonts, margins, etc.; (2) creating the view and then setting properties directly.

// Example of custom dataSource
NSDictionary *dataSource = @{
    QiPageMenuViewNormalTitleColor : [UIColor blackColor],
    QiPageMenuViewSelectedTitleColor : [UIColor redColor],
    QiPageMenuViewTitleFont : [UIFont systemFontOfSize:14],
    // ... other properties
};
QiPageMenuView *menuView = [[QiPageMenuView alloc] initWithFrame:CGRectMake(0,0,self.view.width,50)
                                                          titles:@[@"Message",@"Event",@"Broadcast"]
                                                       dataSource:dataSource];
menuView.backgroundColor = [UIColor orangeColor];
[self.view addSubview:menuView];

QiPageContentView Implementation

The header defines the interface, a UIPageViewController property, an array of child view controllers, and block/delegate callbacks for scroll events.

@interface QiPageContentView : UIView <UIPageViewControllerDelegate, UIPageViewControllerDataSource, UIScrollViewDelegate>
@property (nonatomic, strong) UIPageViewController *pageViewController;
@property (nonatomic, strong) NSArray *controllerArray; // child controllers
@property (nonatomic, copy) void (^pageContentViewDidScroll)(NSInteger currentIndex, NSInteger beforeIndex, QiPageContentView *pageView);
@property (nonatomic, weak) id<QiPageContentViewDelegate> contentViewDelegate;
- (instancetype)initWithFrame:(CGRect)frame childViewController:(NSArray *)childViewControllers;
- (void)setPageContentShouldScrollToIndex:(NSInteger)index beforeIndex:(NSInteger)beforeIndex;
@end

Scrolling to a specific page is performed by setting the UIPageViewController’s view controllers with animation.

Interaction Between Menu and Content

Both components define delegate protocols. QiPageMenuView notifies when an item is clicked via the pageItemClicked block or the pageMenuViewDidClickedIndex:beforeIndex: delegate method. QiPageContentView notifies scroll completion via the pageContentViewDidScroll block or the pageContentViewDidScrollToIndex:beforeIndex: delegate method. By assigning the callbacks, the two views stay synchronized while remaining loosely coupled.

Combined Usage Example

A typical setup creates a menu view, adds it to the controller’s view, creates a content view positioned below the menu, and links the callbacks so that selecting a menu item scrolls the content view and vice‑versa.

QiPageMenuView *menuView = [[QiPageMenuView alloc] initWithFrame:CGRectMake(0,0,self.view.width,50)
                                                          titles:@[@"System",@"Event",@"Broadcast",@"Latest",@"Hot"]
                                                       dataSource:dataSource];
[self.view addSubview:menuView];

QiPageContentView *contentView = [[QiPageContentView alloc] initWithFrame:CGRectMake(0, menuView.bottom+10, self.view.width, self.view.height - menuView.bottom - 98)
                                                        childViewController:@[vc0, vc1, vc2, vc3, vc4]];
[self.view addSubview:contentView];

menuView.pageItemClicked = ^(NSInteger clickedIndex, NSInteger beforeIndex, QiPageMenuView *menu) {
    NSLog(@"Clicked: before %ld now %ld", beforeIndex, clickedIndex);
    [contentView setPageContentShouldScrollToIndex:clickedIndex beforIndex:beforeIndex];
};

contentView.pageContentViewDidScroll = ^(NSInteger currentIndex, NSInteger beforeIndex, QiPageContentView *view) {
    menuView.pageScrolledIndex = currentIndex;
    NSLog(@"Scrolled: before %ld now %ld", beforeIndex, currentIndex);
};

The decoupled design allows QiPageMenuView and QiPageContentView to be reused independently in different projects.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

iOSpaginationObjective‑CUIScrollViewQiPageContentViewQiPageMenuViewUIPageViewController
360 Zhihui Cloud Developer
Written by

360 Zhihui Cloud Developer

360 Zhihui Cloud is an enterprise open service platform that aims to "aggregate data value and empower an intelligent future," leveraging 360's extensive product and technology resources to deliver platform services to customers.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.