DNSPageView-ObjC 2.1.0

DNSPageView-ObjC 2.1.0

Daniels 维护。



  • Daniels

DNSPageView-ObjC

Version License Platform

DNSPageView 的 Objective-C 版本,是一个灵活且易于使用的 pageView 框架,titleView 和 contentView 可以布局在任何地方,可以纯代码初始化,也可以使用 xib 或者 storyboard 初始化,并且提供了常见的样式属性进行设置。

如果你使用的开发语言是 Swift,请使用 DNSPageView

特点

  • 使用简单
  • 多种初始化方式
  • 灵活布局
  • 常见样式
  • 双击 titleView 的回调
  • contentView 滑动监听
  • 适配 iOS 13 暗黑模式
  • 动态改变样式

需求

  • iOS 8.0+

  • Xcode 9.0+

安装

CocoaPods

CocoaPods 是 Cocoa 项目的依赖管理器。您可以使用以下命令安装它:

$ gem install cocoapods

要构建 DNSPageView,需要 CocoaPods 1.1+。

要使用 CocoaPods 将 DNSPageView 整合到您的 Xcode 项目中,请在您的 Podfile 中指定它:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'

target '<Your Target Name>' do
    pod 'DNSPageView-ObjC'
end

然后,运行以下命令:

$ pod install

手动操作

如果您不想使用上述任何依赖管理器,可以将 DNSPageView-ObjC 手动整合到项目中。

示例

要运行示例项目,请克隆仓库,并运行 DNSPageView.xcodeproj

使用方式

直接使用 DNSPageView 初始化

// 创建 DNSPageStyle,设置样式
DNSPageStyle *style = [[DNSPageStyle alloc] init];
style.titleViewScrollEnabled = YES;
style.titleScaleEnabled = YES;

// 设置标题内容
NSArray <NSString *>*titles = @[@"头条", @"视频", @"娱乐", @"要问", @"体育", @"科技", @"汽车", @"时尚", @"图片", @"游戏", @"房产"];

// 创建每一页对应的 controller
for (int i = 0; i < titles.count; i++) {
    ContentViewController *controller = [[ContentViewController alloc] init];
    [self addChildViewController:controller];
}

CGFloat y = [UIApplication sharedApplication].statusBarFrame.size.height + self.navigationController.navigationBar.frame.size.height;
CGSize size = [UIScreen mainScreen].bounds.size;

// 创建对应的 DNSPageView,并设置它的 frame
DNSPageView *pageView = [[DNSPageView alloc] initWithFrame:CGRectMake(0, y, size.width, size.height - y) style:style titles:titles childViewControllers:self.childViewControllers currentIndex:7];
[self.view addSubview:pageView];

使用 xib 或 storyboard 初始化

xibstoryboard 中拖出两个 UIView,让它们分别继承 DNSPageTitleViewDNSPageContentView,然后将它们拖到代码中:

@property (weak, nonatomic) IBOutlet DNSPageTitleView *titleView;

@property (weak, nonatomic) IBOutlet DNSPageContentView *contentView;

设置 DNSPageTitleView 和 DNSPageContentView。

// 创建 DNSPageStyle,设置样式
DNSPageStyle *style = [[DNSPageStyle alloc] init];
style.titleViewBackgroundColor = [UIColor redColor];
style.showCoverView = YES;

// 设置标题内容
NSArray <NSString *>*titles = @[@"头条", @"视频", @"娱乐", @"要问", @"体育"];

// 设置默认的起始位置
NSInteger startIndex = 2;

// 创建每一页对应的 controller
for (int i = 0; i < titles.count; i++) {
    ContentViewController *controller = [[ContentViewController alloc] init];
    [self addChildViewController:controller];
}

// 创建 DNSPageViewManager 来设置它们的样式和布局
DNSPageViewManager *pageViewManager = [[DNSPageViewManager alloc] initWithStyle:style
                                                     titles:titles
                                       childViewControllers:self.childViewControllers
                                               currentIndex:currentIndex
                                                  titleView:self.titleView
                                                contentView:self.contentView];

使用 DNSPageViewManager 初始化

创建 DNSPageViewManager

- (DNSPageViewManager *)pageViewManager {
    if (!_pageViewManager) {
        // 创建 DNSPageStyle,设置样式
        DNSPageStyle *style = [[DNSPageStyle alloc] init];
        style.showBottomLine = YES;
        style.titleViewScrollEnabled = YES;
        style.titleViewBackgroundColor = [UIColor clearColor];
        
        // 设置标题内容
        NSArray <NSString *>*titles = @[@"头条", @"视频", @"娱乐", @"要问", @"体育"];
        
        // 创建每一页对应的 controller
        for (int i = 0; i < titles.count; i++) {
            ContentViewController *controller = [[ContentViewController alloc] init];
            [self addChildViewController:controller];
        }
        _pageViewManager = [[DNSPageViewManager alloc] initWithStyle:style titles:titles childViewControllers:self.childViewControllers];
    }
    return _pageViewManager;
}

布局 titleView 和 contentView

// 单独设置 titleView 的 frame
self.navigationItem.titleView = self.pageViewManager.titleView;
self.pageViewManager.titleView.frame = CGRectMake(0, 0, 180, 44);

// 单独设置 contentView 的大小和位置,可以使用 autolayout 或者 frame
DNSPageContentView *contentView = self.pageViewManager.contentView;
[self.view addSubview:contentView];
[contentView makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(self.view);
}];

样式

DNSPageStyle 提供了常见样式的属性,可以根据不同的需求进行设置,包括可以设置初始显示的页面

事件回调

DNSPageView 提供了常见事件监听的代理,它属于 DNSPageTitleViewDelegate 中的属性

/**
 DNSPageView 的事件回调,如果有需要,请让对应的 childViewController 遵守这个协议
 */
@protocol DNSPageEventHandlerDelegate <NSObject>
@optional


/**
 重复点击 pageTitleView 后调用
 */
- (void)titleViewDidSelectSameTitle;


/**
 pageContentView 的上一页消失的时候,上一页对应的 controller 调用
 */
- (void)contentViewDidDisappear;

/**
 pageContentView 滚动停止的时候,当前页对应的 controller 调用
 */
- (void)contentViewDidEndScroll;

@end

常见问题

  • style.isTitleViewScrollEnabled

    如果标签比较少,建议设置 style.titleViewScrollEnabled = NO,其中 titleView 会被固定,style.titleMargin 不起作用,每个标签将平均分配整个 titleView 的宽度,下划线的宽度等于标签的宽度。

    如果标签比较多,建议设置 style.titleViewScrollEnabled = YES,此时,titleView 将会滑动,下划线的宽度也将根据标签文字的宽度变化而变化

  • 标签下划线的宽度跟随文字宽度

    设置 style.titleViewScrollEnabled = YES 时,可以参考 demo 中的第四种样式。

  • 由于 DNSPageView 是基于 UIScrollView 实现,因此不可避免地会继承其某些特性:

    • 当控制器被 UINavigationController 管理,且 navigationBar.isTranslucent = YES 时,当前控制器的 viewy = 0 开始布局,因此为了防止部分内容被 navigationBar 遮挡,系统默认会给 UIScrollView 添加 offset。如果想取消这个特性:
      • iOS 11 之前,在控制器中设置 self.automaticallyAdjustsScrollViewInsets = NO
      • iOS 11 之后,引入了 SafeArea 概念,设置 UIScrollView 的属性 contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever
      • 事实上,这个效果还与其他 UIViewController 属性有关,但由于组合情况复杂,此处不一一描述。
    • DNSPageContentView 通过 UICollectionView 实现,因此这种特性可能会造成 UICollectionView 的高度小于其 item 的高度,从而引发奇特的 Bug。
    • 以上只是可能出现的 Bug 之一,由于 demo 无法覆盖所有场景,不同的布局需求可能会引起不同的 Bug,开发者需要明确自己的布局需求,注意细节,了解 iOS 的布局特性,并做出相应的调整,不能完全依赖于 demo

许可证

DNSPageView-ObjC 以 MIT 许可证提供。有关更多信息,请参阅 LICENSE 文件。