├── ScreenShot ├── TYPagerController1.gif ├── TYPagerController2.gif ├── TYPagerController3.gif ├── TYPagerController4.gif ├── TYPagerController5.gif ├── TYPagerController6.gif └── TYPagerController7.gif ├── TYPagerControllerDemo.xcodeproj ├── xcuserdata │ ├── tany.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ └── TYPagerControllerDemo.xcscheme │ └── tanyang.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── TYPagerControllerDemo.xcscheme └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── tany.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── TYPagerControllerDemo_swift.xcodeproj ├── xcuserdata │ ├── tany.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ └── TYPagerControllerDemo_swift.xcscheme │ └── tanyang.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── TYPagerControllerDemo_swift.xcscheme └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── tany.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── TYPagerControllerDemo ├── ViewController.h ├── PagerViewDmeoController.h ├── TabPagerViewDmeoController.h ├── PagerControllerDmeoController.h ├── TabPagerControllerDemoController.h ├── ListViewController.h ├── CustomViewController.h ├── AppDelegate.h ├── CollectionViewController.h ├── main.m ├── TYPagerController │ ├── TabPager │ │ ├── TYTabPagerBarCell.h │ │ ├── TYTabPagerBarCell.m │ │ ├── TYTabPagerView.h │ │ ├── TYTabPagerController.h │ │ ├── TYTabPagerBar.h │ │ ├── TYTabPagerBarLayout.h │ │ ├── TYTabPagerView.m │ │ ├── TYTabPagerController.m │ │ ├── TYTabPagerBar.m │ │ └── TYTabPagerBarLayout.m │ ├── TYPagerView.h │ ├── TYPagerController.h │ ├── TYPagerViewLayout.h │ ├── TYPagerView.m │ └── TYPagerController.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── ViewController.m ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── AppDelegate.m ├── TabPagerViewDmeoController.m ├── TabPagerControllerDemoController.m ├── CollectionViewController.m ├── ListViewController.m ├── CustomViewController.m ├── PagerControllerDmeoController.m └── PagerViewDmeoController.m ├── TYPagerControllerDemo_swift ├── TYPagerControllerDemo_swift-Brdging-Header.h ├── ViewController.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── TabPagerControllerDemoController.swift ├── AppDelegate.swift ├── TabPagerViewDemoController.swift └── PagerControlerDemoController.swift ├── TYPagerController.podspec ├── LICENSE └── README.md /ScreenShot/TYPagerController1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/12207480/TYPagerController/HEAD/ScreenShot/TYPagerController1.gif -------------------------------------------------------------------------------- /ScreenShot/TYPagerController2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/12207480/TYPagerController/HEAD/ScreenShot/TYPagerController2.gif -------------------------------------------------------------------------------- /ScreenShot/TYPagerController3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/12207480/TYPagerController/HEAD/ScreenShot/TYPagerController3.gif -------------------------------------------------------------------------------- /ScreenShot/TYPagerController4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/12207480/TYPagerController/HEAD/ScreenShot/TYPagerController4.gif -------------------------------------------------------------------------------- /ScreenShot/TYPagerController5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/12207480/TYPagerController/HEAD/ScreenShot/TYPagerController5.gif -------------------------------------------------------------------------------- /ScreenShot/TYPagerController6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/12207480/TYPagerController/HEAD/ScreenShot/TYPagerController6.gif -------------------------------------------------------------------------------- /ScreenShot/TYPagerController7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/12207480/TYPagerController/HEAD/ScreenShot/TYPagerController7.gif -------------------------------------------------------------------------------- /TYPagerControllerDemo.xcodeproj/xcuserdata/tany.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /TYPagerControllerDemo.xcodeproj/xcuserdata/tanyang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift.xcodeproj/xcuserdata/tany.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift.xcodeproj/xcuserdata/tanyang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TYPagerControllerDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TYPagerControllerDemo.xcodeproj/project.xcworkspace/xcuserdata/tany.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/12207480/TYPagerController/HEAD/TYPagerControllerDemo.xcodeproj/project.xcworkspace/xcuserdata/tany.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift.xcodeproj/project.xcworkspace/xcuserdata/tany.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/12207480/TYPagerController/HEAD/TYPagerControllerDemo_swift.xcodeproj/project.xcworkspace/xcuserdata/tany.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /TYPagerControllerDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/6. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/PagerViewDmeoController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PagerViewDmeoController.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 2017/7/6. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PagerViewDmeoController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TabPagerViewDmeoController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TabPagerViewDmeoController.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/19. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TabPagerViewDmeoController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/PagerControllerDmeoController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PagerControllerDmeoController.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/19. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PagerControllerDmeoController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TabPagerControllerDemoController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PagerControllerDemoController.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 2017/7/18. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import "TYTabPagerController.h" 10 | 11 | @interface TabPagerControllerDemoController : TYTabPagerController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/ListViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ListViewController.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 16/5/17. 6 | // Copyright © 2016年 tanyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ListViewController : UIViewController 12 | 13 | @property (nonatomic, strong) NSString *text; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/CustomViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CustomViewController.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 16/4/20. 6 | // Copyright © 2016年 tanyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CustomViewController : UIViewController 12 | 13 | @property (nonatomic, strong) NSString *text; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/6. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/CollectionViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewController.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 16/5/17. 6 | // Copyright © 2016年 tanyang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CollectionViewController : UIViewController 12 | 13 | @property (nonatomic, strong) NSString *text; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/6. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift/TYPagerControllerDemo_swift-Brdging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // TYPagerControllerDemo_swift-Brdging-Header.h 3 | // TYPagerControllerDemo_swift 4 | // 5 | // Created by tany on 2017/7/19. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #ifndef TYPagerControllerDemo_swift_Brdging_Header_h 10 | #define TYPagerControllerDemo_swift_Brdging_Header_h 11 | 12 | #import "TYTabPagerView.h" 13 | #import "TYTabPagerController.h" 14 | 15 | #endif /* TYPagerControllerDemo_swift_Brdging_Header_h */ 16 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift.xcodeproj/xcuserdata/tany.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TYPagerControllerDemo_swift.xcscheme 8 | 9 | orderHint 10 | 1 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 2BE687901F1F3D67001FE46D 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift.xcodeproj/xcuserdata/tanyang.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TYPagerControllerDemo_swift.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 2BE687901F1F3D67001FE46D 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TabPager/TYTabPagerBarCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // TYTabTitleViewCell.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 16/5/4. 6 | // Copyright © 2016年 tanyang. All rights reserved. 7 | // 8 | 9 | #import 10 | NS_ASSUME_NONNULL_BEGIN 11 | @protocol TYTabPagerBarCellProtocol 12 | 13 | /** 14 | font ,textColor will use TYTabPagerBarLayout's textFont,textColor 15 | */ 16 | @property (nonatomic, strong, readonly) UILabel *titleLabel; 17 | 18 | @end 19 | 20 | @interface TYTabPagerBarCell : UICollectionViewCell 21 | @property (nonatomic, weak,readonly) UILabel *titleLabel; 22 | 23 | + (NSString *)cellIdentifier; 24 | @end 25 | NS_ASSUME_NONNULL_END 26 | -------------------------------------------------------------------------------- /TYPagerControllerDemo.xcodeproj/xcuserdata/tany.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TYPagerControllerDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 2B9C0F471F0E11E7009BC0BD 16 | 17 | primary 18 | 19 | 20 | 2B9C0F601F0E11E7009BC0BD 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /TYPagerControllerDemo.xcodeproj/xcuserdata/tanyang.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TYPagerControllerDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 2B9C0F471F0E11E7009BC0BD 16 | 17 | primary 18 | 19 | 20 | 2B9C0F601F0E11E7009BC0BD 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /TYPagerController.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | # 名称 使用的时候pod search [name] 3 | s.name = "TYPagerController" 4 | # 代码库的版本 5 | s.version = "2.1.2" 6 | # 简介 7 | s.summary = "page scroll View controller,simple,high custom,and have tabBar styles." 8 | # 主页 9 | s.homepage = "https://github.com/12207480/TYPagerController" 10 | # 许可证书类型,要和仓库的LICENSE 的类型一致 11 | s.license = { :type => 'MIT', :file => 'LICENSE' } 12 | # 作者名称 和 邮箱 13 | s.author = { "tany" => "122074809@qq.com" } 14 | # 作者主页 s.social_media_url ="" 15 | # 代码库最低支持的版本 16 | s.platform = :ios, "7.0" 17 | # 代码的Clone 地址 和 tag 版本 18 | s.source = { :git => "https://github.com/12207480/TYPagerController.git", :tag => s.version.to_s } 19 | # 如果使用pod 需要导入哪些资源 20 | s.source_files = "TYPagerControllerDemo/TYPagerController/**/*.{h,m}" 21 | # s.resources = "**/*/*.bundle" 22 | # 框架是否使用的ARC 23 | s.requires_arc = true 24 | end 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 tany 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // TYPagerControllerDemo_swift 4 | // 5 | // Created by tany on 2017/7/19. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view, typically from a nib. 16 | 17 | } 18 | 19 | @IBAction func turnToPagerController(_ sender: Any) { 20 | let vc = PagerControlerDemoController() 21 | self.navigationController?.pushViewController(vc, animated: true) 22 | } 23 | 24 | @IBAction func turnToTabPagerView(_ sender: Any) { 25 | let vc = TabPagerViewDemoController() 26 | self.navigationController?.pushViewController(vc, animated: true) 27 | } 28 | 29 | 30 | @IBAction func turnToTabPagerController(_ sender: Any) { 31 | let vc = TabPagerControllerDemoController() 32 | self.navigationController?.pushViewController(vc, animated: true) 33 | } 34 | 35 | override func didReceiveMemoryWarning() { 36 | super.didReceiveMemoryWarning() 37 | // Dispose of any resources that can be recreated. 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TabPager/TYTabPagerBarCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // TYTabTitleViewCell.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 16/5/4. 6 | // Copyright © 2016年 tanyang. All rights reserved. 7 | // 8 | 9 | #import "TYTabPagerBarCell.h" 10 | 11 | @interface TYTabPagerBarCell () 12 | @property (nonatomic, weak) UILabel *titleLabel; 13 | @end 14 | 15 | @implementation TYTabPagerBarCell 16 | 17 | - (instancetype)initWithFrame:(CGRect)frame 18 | { 19 | if (self = [super initWithFrame:frame]) { 20 | [self addTabTitleLabel]; 21 | } 22 | return self; 23 | } 24 | 25 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 26 | { 27 | if (self = [super initWithCoder:aDecoder]) { 28 | [self addTabTitleLabel]; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)addTabTitleLabel 34 | { 35 | UILabel *titleLabel = [[UILabel alloc]init]; 36 | titleLabel.font = [UIFont systemFontOfSize:15]; 37 | titleLabel.textColor = [UIColor darkTextColor]; 38 | titleLabel.textAlignment = NSTextAlignmentCenter; 39 | [self.contentView addSubview:titleLabel]; 40 | _titleLabel = titleLabel; 41 | } 42 | 43 | + (NSString *)cellIdentifier { 44 | return @"TYTabPagerBarCell"; 45 | } 46 | 47 | - (void)layoutSubviews 48 | { 49 | [super layoutSubviews]; 50 | _titleLabel.frame = self.contentView.bounds; 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /TYPagerControllerDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/6. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "PagerViewDmeoController.h" 11 | #import "PagerControllerDmeoController.h" 12 | #import "TabPagerControllerDemoController.h" 13 | #import "TabPagerViewDmeoController.h" 14 | 15 | @interface ViewController () 16 | 17 | @end 18 | 19 | @implementation ViewController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | // Do any additional setup after loading the view, typically from a nib. 24 | 25 | } 26 | 27 | #pragma mark - action 28 | 29 | - (IBAction)turnToPageViewDemo:(id)sender { 30 | PagerViewDmeoController *vc = [[PagerViewDmeoController alloc]init]; 31 | [self.navigationController pushViewController:vc animated:YES]; 32 | } 33 | 34 | - (IBAction)turnToTabPagerViewDemo:(id)sender { 35 | TabPagerViewDmeoController *vc = [[TabPagerViewDmeoController alloc]init]; 36 | [self.navigationController pushViewController:vc animated:YES]; 37 | } 38 | 39 | - (IBAction)turnToPageControllerDemo:(id)sender { 40 | PagerControllerDmeoController *pagerController = [[PagerControllerDmeoController alloc]init]; 41 | [self.navigationController pushViewController:pagerController animated:YES]; 42 | } 43 | 44 | - (IBAction)turnToTabPagerControllerDemo:(id)sender { 45 | TabPagerControllerDemoController *pagerController = [[TabPagerControllerDemoController alloc]init]; 46 | //pagerController.pagerController.layout.prefetchItemCount = 1; 47 | [self.navigationController pushViewController:pagerController animated:YES]; 48 | } 49 | - (void)didReceiveMemoryWarning { 50 | [super didReceiveMemoryWarning]; 51 | // Dispose of any resources that can be recreated. 52 | } 53 | 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift/TabPagerControllerDemoController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TabPagerControllerDemoController.swift 3 | // TYPagerControllerDemo_swift 4 | // 5 | // Created by tany on 2017/7/19. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TabPagerControllerDemoController: TYTabPagerController { 12 | 13 | lazy var datas = [String]() 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | // Do any additional setup after loading the view. 19 | self.tabBar.layout.barStyle = TYPagerBarStyle.progressView 20 | self.dataSource = self 21 | self.delegate = self 22 | 23 | self.loadData() 24 | } 25 | 26 | func loadData() { 27 | var i = 0 28 | while i < 20 { 29 | self.datas.append(i%2==0 ?"Tab \(i)":"Tab Tab \(i)") 30 | i += 1 31 | } 32 | self.reloadData() 33 | } 34 | 35 | override func didReceiveMemoryWarning() { 36 | super.didReceiveMemoryWarning() 37 | // Dispose of any resources that can be recreated. 38 | } 39 | 40 | } 41 | 42 | extension TabPagerControllerDemoController: TYTabPagerControllerDataSource, TYTabPagerControllerDelegate { 43 | func numberOfControllersInTabPagerController() -> Int { 44 | return self.datas.count 45 | } 46 | 47 | func tabPagerController(_ tabPagerController: TYTabPagerController, controllerFor index: Int, prefetching: Bool) -> UIViewController { 48 | let vc = UIViewController() 49 | vc.view.backgroundColor = UIColor(red: CGFloat(arc4random()%255)/255.0, green: CGFloat(arc4random()%255)/255.0, blue: CGFloat(arc4random()%255)/255.0, alpha: 1) 50 | return vc 51 | } 52 | 53 | func tabPagerController(_ tabPagerController: TYTabPagerController, titleFor index: Int) -> String { 54 | let title = self.datas[index] 55 | return title 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/6. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // TYPagerControllerDemo_swift 4 | // 5 | // Created by tany on 2017/7/19. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift/TabPagerViewDemoController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TabPagerViewDemoController.swift 3 | // TYPagerControllerDemo_swift 4 | // 5 | // Created by tany on 2017/7/19. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TabPagerViewDemoController: UIViewController { 12 | 13 | lazy var pagerView = TYTabPagerView() 14 | lazy var datas = [String]() 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | // Do any additional setup after loading the view, typically from a nib. 19 | self.view.backgroundColor = UIColor.white 20 | addTabPagerView() 21 | 22 | loadData() 23 | } 24 | 25 | func addTabPagerView() { 26 | self.pagerView.tabBarHeight = 40 27 | self.pagerView.dataSource = self 28 | self.pagerView.delegate = self 29 | // you can rigsiter cell like tableView 30 | self.pagerView.register(UIView.classForCoder(), forPagerCellWithReuseIdentifier: "cellId"); 31 | self.view.addSubview(self.pagerView) 32 | } 33 | 34 | func loadData() { 35 | var i = 0 36 | while i < 20 { 37 | self.datas.append(i%2==0 ?"Tab \(i)":"Tab Tab \(i)") 38 | i += 1 39 | } 40 | self.pagerView.reloadData() 41 | } 42 | 43 | override func viewWillLayoutSubviews() { 44 | super.viewWillLayoutSubviews(); 45 | self.pagerView.frame = CGRect(x: 0, y: 64, width: self.view.frame.width, height: self.view.frame.height - 64); 46 | } 47 | 48 | override func didReceiveMemoryWarning() { 49 | super.didReceiveMemoryWarning() 50 | // Dispose of any resources that can be recreated. 51 | } 52 | } 53 | 54 | extension TabPagerViewDemoController: TYTabPagerViewDataSource, TYTabPagerViewDelegate { 55 | func numberOfViewsInTabPagerView() -> Int { 56 | return self.datas.count 57 | } 58 | 59 | func tabPagerView(_ tabPagerView: TYTabPagerView, viewFor index: Int, prefetching: Bool) -> UIView { 60 | //you can let view = UIView() or let view = UIView(frame: tabPagerView.layout.frameForItem(at: index)) 61 | // or reigster and dequeue cell like tableView 62 | let view = tabPagerView.dequeueReusablePagerCell(withReuseIdentifier: "cellId", for: index) 63 | view.backgroundColor = UIColor(red: CGFloat(arc4random()%255)/255.0, green: CGFloat(arc4random()%255)/255.0, blue: CGFloat(arc4random()%255)/255.0, alpha: 1) 64 | return view 65 | } 66 | 67 | func tabPagerView(_ tabPagerView: TYTabPagerView, titleFor index: Int) -> String { 68 | let title = self.datas[index] 69 | return title 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TabPager/TYTabPagerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TYTabPagerView.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 2017/7/18. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TYPagerView.h" 11 | #import "TYTabPagerBar.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @class TYTabPagerView; 16 | @protocol TYTabPagerViewDataSource 17 | 18 | - (NSInteger)numberOfViewsInTabPagerView; 19 | 20 | - (UIView *)tabPagerView:(TYTabPagerView *)tabPagerView viewForIndex:(NSInteger)index prefetching:(BOOL)prefetching; 21 | 22 | - (NSString *)tabPagerView:(TYTabPagerView *)tabPagerView titleForIndex:(NSInteger)index; 23 | 24 | @end 25 | 26 | @protocol TYTabPagerViewDelegate 27 | @optional 28 | 29 | // display cell 30 | - (void)tabPagerView:(TYTabPagerView *)tabPagerView willDisplayCell:(UICollectionViewCell *)cell atIndex:(NSInteger)index; 31 | 32 | // did select cell item 33 | - (void)tabPagerView:(TYTabPagerView *)tabPagerView didSelectTabBarItemAtIndex:(NSInteger)index; 34 | 35 | // appear && disappear 36 | - (void)tabPagerView:(TYTabPagerView *)tabPagerView willAppearView:(UIView *)view forIndex:(NSInteger)index; 37 | - (void)tabPagerView:(TYTabPagerView *)tabPagerView didDisappearView:(UIView *)view forIndex:(NSInteger)index; 38 | 39 | // scrolling 40 | - (void)tabPagerViewWillBeginScrolling:(TYTabPagerView *)tabPagerView animate:(BOOL)animate; 41 | - (void)tabPagerViewDidEndScrolling:(TYTabPagerView *)tabPagerView animate:(BOOL)animate; 42 | 43 | @end 44 | 45 | @interface TYTabPagerView : UIView 46 | 47 | @property (nonatomic, weak, readonly) TYTabPagerBar *tabBar; 48 | @property (nonatomic, weak, readonly) TYPagerView *pageView; 49 | 50 | @property (nonatomic, strong, readonly) TYPagerViewLayout *layout; 51 | 52 | @property (nonatomic, weak, nullable) id dataSource; 53 | @property (nonatomic, weak, nullable) id delegate; 54 | 55 | @property (nonatomic, assign) CGFloat tabBarHeight; 56 | 57 | // register tabBar cell 58 | - (void)registerClass:(Class)Class forTabBarCellWithReuseIdentifier:(NSString *)identifier; 59 | - (void)registerNib:(UINib *)nib forTabBarCellWithReuseIdentifier:(NSString *)identifier; 60 | 61 | // register && dequeue pager Cell, usage like tableView 62 | - (void)registerClass:(Class)Class forPagerCellWithReuseIdentifier:(NSString *)identifier; 63 | - (void)registerNib:(UINib *)nib forPagerCellWithReuseIdentifier:(NSString *)identifier; 64 | - (UIView *)dequeueReusablePagerCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index; 65 | 66 | 67 | - (void)scrollToViewAtIndex:(NSInteger)index animate:(BOOL)animate; 68 | 69 | - (void)updateData; 70 | 71 | - (void)reloadData; 72 | 73 | @end 74 | 75 | NS_ASSUME_NONNULL_END 76 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TabPager/TYTabPagerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TYTabPagerController.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 2017/7/18. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TYTabPagerBar.h" 11 | #import "TYPagerController.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @class TYTabPagerController; 16 | @protocol TYTabPagerControllerDataSource 17 | 18 | - (NSInteger)numberOfControllersInTabPagerController; 19 | 20 | - (UIViewController *)tabPagerController:(TYTabPagerController *)tabPagerController controllerForIndex:(NSInteger)index prefetching:(BOOL)prefetching; 21 | 22 | - (NSString *)tabPagerController:(TYTabPagerController *)tabPagerController titleForIndex:(NSInteger)index; 23 | 24 | @end 25 | 26 | @protocol TYTabPagerControllerDelegate 27 | @optional 28 | 29 | // display cell 30 | - (void)tabPagerController:(TYTabPagerController *)tabPagerController willDisplayCell:(UICollectionViewCell *)cell atIndex:(NSInteger)index; 31 | 32 | // did select cell item 33 | - (void)tabPagerController:(TYTabPagerController *)tabPagerController didSelectTabBarItemAtIndex:(NSInteger)index; 34 | 35 | // scrolling 36 | - (void)tabPagerControllerWillBeginScrolling:(TYTabPagerController *)tabPagerController animate:(BOOL)animate; 37 | - (void)tabPagerControllerDidEndScrolling:(TYTabPagerController *)tabPagerController animate:(BOOL)animate; 38 | 39 | @end 40 | 41 | @interface TYTabPagerController : UIViewController 42 | 43 | @property (nonatomic, strong, readonly) TYTabPagerBar *tabBar; 44 | @property (nonatomic, strong, readonly) TYPagerController *pagerController; 45 | @property (nonatomic, strong, readonly) TYPagerViewLayout *layout; 46 | 47 | @property (nonatomic, weak, nullable) id dataSource; 48 | @property (nonatomic, weak, nullable) id delegate; 49 | 50 | // you can custom tabBar orignY and height. 51 | @property (nonatomic, assign) CGFloat tabBarOrignY; 52 | @property (nonatomic, assign) CGFloat tabBarHeight; 53 | 54 | // register tabBar cell 55 | - (void)registerClass:(Class)Class forTabBarCellWithReuseIdentifier:(NSString *)identifier; 56 | - (void)registerNib:(UINib *)nib forTabBarCellWithReuseIdentifier:(NSString *)identifier; 57 | 58 | // register && dequeue pager Cell, usage like tableView 59 | - (void)registerClass:(Class)Class forPagerCellWithReuseIdentifier:(NSString *)identifier; 60 | - (void)registerNib:(UINib *)nib forPagerCellWithReuseIdentifier:(NSString *)identifier; 61 | - (UIViewController *)dequeueReusablePagerCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index; 62 | 63 | 64 | - (void)scrollToControllerAtIndex:(NSInteger)index animate:(BOOL)animate; 65 | 66 | - (void)updateData; 67 | 68 | - (void)reloadData; 69 | 70 | 71 | @end 72 | 73 | NS_ASSUME_NONNULL_END 74 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TabPagerViewDmeoController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TabPagerViewDmeoController.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/19. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import "TabPagerViewDmeoController.h" 10 | #import "TYTabPagerView.h" 11 | 12 | @interface TabPagerViewDmeoController () 13 | 14 | @property (nonatomic, weak) TYTabPagerView *pagerView; 15 | 16 | @property (nonatomic, strong) NSArray *datas; 17 | 18 | @end 19 | 20 | @implementation TabPagerViewDmeoController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | // Do any additional setup after loading the view. 25 | self.title = @"TabPagerViewDmeoController"; 26 | self.view.backgroundColor = [UIColor whiteColor]; 27 | [self addTabPagerView]; 28 | 29 | [self loadData]; 30 | } 31 | 32 | - (void)addTabPagerView { 33 | TYTabPagerView *pagerView = [[TYTabPagerView alloc]init]; 34 | pagerView.tabBar.layout.barStyle = TYPagerBarStyleCoverView; 35 | pagerView.tabBar.progressView.backgroundColor = [UIColor lightGrayColor]; 36 | pagerView.dataSource = self; 37 | pagerView.delegate = self; 38 | [self.view addSubview:pagerView]; 39 | _pagerView = pagerView; 40 | } 41 | 42 | - (void)viewWillLayoutSubviews { 43 | [super viewWillLayoutSubviews]; 44 | _pagerView.frame = CGRectMake(0, CGRectGetMaxY(self.navigationController.navigationBar.frame), CGRectGetWidth(self.view.frame),CGRectGetHeight(self.view.frame)-CGRectGetMaxY(self.navigationController.navigationBar.frame)); 45 | } 46 | 47 | - (void)loadData { 48 | NSMutableArray *datas = [NSMutableArray array]; 49 | for (NSInteger i = 0; i < 20; ++i) { 50 | [datas addObject:i%2 == 0 ? [NSString stringWithFormat:@"Tab %ld",i]:[NSString stringWithFormat:@"Tab Tab %ld",i]]; 51 | } 52 | _datas = [datas copy]; 53 | 54 | [_pagerView reloadData]; 55 | //[_pagerView scrollToViewAtIndex:1 animate:YES]; 56 | } 57 | 58 | 59 | #pragma mark - TYTabPagerViewDataSource 60 | 61 | - (NSInteger)numberOfViewsInTabPagerView { 62 | return _datas.count; 63 | } 64 | 65 | - (UIView *)tabPagerView:(TYTabPagerView *)tabPagerView viewForIndex:(NSInteger)index prefetching:(BOOL)prefetching { 66 | UIView *view = [[UIView alloc]initWithFrame:[tabPagerView.layout frameForItemAtIndex:index]]; 67 | view.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:arc4random()%255/255.0]; 68 | //NSLog(@"viewForIndex:%ld prefetching:%d",index,prefetching); 69 | return view; 70 | } 71 | 72 | - (NSString *)tabPagerView:(TYTabPagerView *)tabPagerView titleForIndex:(NSInteger)index { 73 | NSString *title = _datas[index]; 74 | return title; 75 | } 76 | 77 | - (void)didReceiveMemoryWarning { 78 | [super didReceiveMemoryWarning]; 79 | // Dispose of any resources that can be recreated. 80 | } 81 | 82 | /* 83 | #pragma mark - Navigation 84 | 85 | // In a storyboard-based application, you will often want to do a little preparation before navigation 86 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 87 | // Get the new view controller using [segue destinationViewController]. 88 | // Pass the selected object to the new view controller. 89 | } 90 | */ 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TabPagerControllerDemoController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PagerControllerDemoController.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 2017/7/18. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import "TabPagerControllerDemoController.h" 10 | #import "CustomViewController.h" 11 | #import "ListViewController.h" 12 | #import "CollectionViewController.h" 13 | 14 | @interface TabPagerControllerDemoController () 15 | 16 | @property (nonatomic, strong) NSArray *datas; 17 | 18 | @end 19 | 20 | @implementation TabPagerControllerDemoController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | // Do any additional setup after loading the view. 25 | self.title = @"TabPagerControllerDemoController"; 26 | self.tabBarHeight = 50; 27 | self.tabBar.layout.barStyle = TYPagerBarStyleProgressView; 28 | self.tabBar.layout.cellWidth = CGRectGetWidth(self.view.frame)/3; 29 | self.tabBar.layout.cellSpacing = 0; 30 | self.tabBar.layout.cellEdging = 0; 31 | self.tabBar.layout.adjustContentCellsCenter = YES; 32 | self.dataSource = self; 33 | self.delegate = self; 34 | 35 | [self loadData]; 36 | } 37 | 38 | - (void)loadData { 39 | NSMutableArray *datas = [NSMutableArray array]; 40 | for (NSInteger i = 0; i < 3; ++i) { 41 | [datas addObject:i%2 == 0 ? [NSString stringWithFormat:@"Tab %ld",i]:[NSString stringWithFormat:@"Tab Tab %ld",i]]; 42 | } 43 | _datas = [datas copy]; 44 | 45 | // only add controller at index 1 46 | [self scrollToControllerAtIndex:1 animate:YES]; 47 | [self reloadData]; 48 | 49 | // first reloadData add controller at index 0,and scroll to index 1 50 | // [self reloadData]; 51 | // [self scrollToControllerAtIndex:1 animate:YES]; 52 | } 53 | 54 | #pragma mark - TYTabPagerControllerDataSource 55 | 56 | - (NSInteger)numberOfControllersInTabPagerController { 57 | return _datas.count; 58 | } 59 | 60 | - (UIViewController *)tabPagerController:(TYTabPagerController *)tabPagerController controllerForIndex:(NSInteger)index prefetching:(BOOL)prefetching { 61 | if (index%3 == 0) { 62 | CustomViewController *VC = [[CustomViewController alloc]init]; 63 | VC.text = [@(index) stringValue]; 64 | return VC; 65 | }else if (index%3 == 1) { 66 | ListViewController *VC = [[ListViewController alloc]init]; 67 | VC.text = [@(index) stringValue]; 68 | return VC; 69 | }else { 70 | CollectionViewController *VC = [[CollectionViewController alloc]init]; 71 | VC.text = [@(index) stringValue]; 72 | return VC; 73 | } 74 | } 75 | 76 | - (NSString *)tabPagerController:(TYTabPagerController *)tabPagerController titleForIndex:(NSInteger)index { 77 | NSString *title = _datas[index]; 78 | return title; 79 | } 80 | 81 | - (void)didReceiveMemoryWarning { 82 | [super didReceiveMemoryWarning]; 83 | // Dispose of any resources that can be recreated. 84 | } 85 | 86 | /* 87 | #pragma mark - Navigation 88 | 89 | // In a storyboard-based application, you will often want to do a little preparation before navigation 90 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 91 | // Get the new view controller using [segue destinationViewController]. 92 | // Pass the selected object to the new view controller. 93 | } 94 | */ 95 | 96 | @end 97 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TabPager/TYTabPagerBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // TYTabPagerBar.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/13. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TYTabPagerBarLayout.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @class TYTabPagerBar; 15 | @protocol TYTabPagerBarDataSource 16 | 17 | - (NSInteger)numberOfItemsInPagerTabBar; 18 | 19 | - (UICollectionViewCell *)pagerTabBar:(TYTabPagerBar *)pagerTabBar cellForItemAtIndex:(NSInteger)index; 20 | 21 | @end 22 | 23 | @protocol TYTabPagerBarDelegate 24 | 25 | @optional 26 | 27 | // configure layout 28 | - (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar configureLayout:(TYTabPagerBarLayout *)layout; 29 | 30 | // if cell wdith is not variable,you can set layout.cellWidth. otherwise ,you can implement this return cell width. cell width not contain cell edge 31 | - (CGFloat)pagerTabBar:(TYTabPagerBar *)pagerTabBar widthForItemAtIndex:(NSInteger)index; 32 | 33 | // did select cell item 34 | - (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar didSelectItemAtIndex:(NSInteger)index; 35 | 36 | // transition frome cell to cell with animated 37 | - (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar transitionFromeCell:(UICollectionViewCell * _Nullable)fromCell toCell:(UICollectionViewCell * _Nullable)toCell animated:(BOOL)animated; 38 | 39 | // transition frome cell to cell with progress 40 | - (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar transitionFromeCell:(UICollectionViewCell * _Nullable)fromCell toCell:(UICollectionViewCell * _Nullable)toCell progress:(CGFloat)progress; 41 | 42 | @end 43 | 44 | @interface TYTabPagerBar : UIView 45 | 46 | @property (nonatomic, weak, readonly) UICollectionView *collectionView; 47 | @property (nonatomic, strong) UIView *progressView; 48 | // automatically resized to self.bounds 49 | @property (nonatomic, strong) UIView *backgroundView; 50 | 51 | @property (nonatomic, weak, nullable) id dataSource; 52 | 53 | @property (nonatomic, weak, nullable) id delegate; 54 | 55 | @property (nonatomic, strong) TYTabPagerBarLayout *layout; 56 | 57 | @property (nonatomic, assign) BOOL autoScrollItemToCenter; 58 | 59 | @property (nonatomic, assign, readonly) NSInteger countOfItems; 60 | 61 | @property (nonatomic, assign, readonly) NSInteger curIndex; 62 | 63 | @property (nonatomic, assign) UIEdgeInsets contentInset; 64 | 65 | - (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier; 66 | - (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier; 67 | 68 | - (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index; 69 | 70 | - (void)reloadData; 71 | 72 | - (void)scrollToItemFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animate:(BOOL)animate; 73 | - (void)scrollToItemFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress; 74 | - (void)scrollToItemAtIndex:(NSInteger)index atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated; 75 | 76 | - (CGFloat)cellWidthForTitle:(NSString * _Nullable)title; 77 | - (CGRect)cellFrameWithIndex:(NSInteger)index; 78 | - (nullable UICollectionViewCell *)cellForIndex:(NSInteger)index; 79 | 80 | @end 81 | 82 | NS_ASSUME_NONNULL_END 83 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/CollectionViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewController.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 16/5/17. 6 | // Copyright © 2016年 tanyang. All rights reserved. 7 | // 8 | 9 | #import "CollectionViewController.h" 10 | 11 | @interface CollectionViewController () 12 | @property (nonatomic, weak) UICollectionView *collectionView; 13 | @end 14 | 15 | static NSString *const cellId = @"collectCellId"; 16 | 17 | @implementation CollectionViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | // Do any additional setup after loading the view. 22 | 23 | [self addCollectionView]; 24 | [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellId]; 25 | } 26 | 27 | - (void)viewWillAppear:(BOOL)animated 28 | { 29 | [super viewWillAppear:animated]; 30 | NSLog(@"viewWillAppear index %@",_text); 31 | } 32 | 33 | - (void)viewDidAppear:(BOOL)animated 34 | { 35 | [super viewWillAppear:animated]; 36 | NSLog(@"viewDidAppear index %@",_text); 37 | } 38 | 39 | - (void)viewWillDisappear:(BOOL)animated 40 | { 41 | [super viewWillDisappear:animated]; 42 | NSLog(@"viewWillDisappear index %@",_text); 43 | } 44 | 45 | - (void)viewDidDisappear:(BOOL)animated 46 | { 47 | [super viewWillDisappear:animated]; 48 | NSLog(@"viewDidDisappear index %@",_text); 49 | } 50 | 51 | 52 | - (void)viewWillLayoutSubviews 53 | { 54 | [super viewWillLayoutSubviews]; 55 | _collectionView.frame = self.view.bounds; 56 | } 57 | 58 | - (void)addCollectionView 59 | { 60 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init]; 61 | layout.itemSize = CGSizeMake((CGRectGetWidth(self.view.frame)-20)/3, (CGRectGetWidth(self.view.frame)-20)/3); 62 | layout.minimumLineSpacing = 10; 63 | layout.sectionInset = UIEdgeInsetsMake(10, 0, 0, 0); 64 | 65 | UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:layout]; 66 | collectionView.backgroundColor = [UIColor whiteColor]; 67 | collectionView.dataSource = self; 68 | [self.view addSubview:collectionView]; 69 | _collectionView = collectionView; 70 | } 71 | 72 | #pragma mark - UIViewControllerDisplayViewDelegate 73 | 74 | - (UIScrollView *)displayView 75 | { 76 | return _collectionView; 77 | } 78 | 79 | #pragma mark - UICollectionViewDataSource 80 | 81 | - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView 82 | { 83 | return 3; 84 | } 85 | 86 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 87 | { 88 | return 3*3; 89 | } 90 | 91 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 92 | { 93 | UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellId forIndexPath:indexPath]; 94 | cell.backgroundColor = [UIColor colorWithRed:255/255.0 green:204/255.0 blue:204/255.0 alpha:1.0]; 95 | return cell; 96 | } 97 | 98 | - (void)didReceiveMemoryWarning { 99 | [super didReceiveMemoryWarning]; 100 | // Dispose of any resources that can be recreated. 101 | } 102 | 103 | /* 104 | #pragma mark - Navigation 105 | 106 | // In a storyboard-based application, you will often want to do a little preparation before navigation 107 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 108 | // Get the new view controller using [segue destinationViewController]. 109 | // Pass the selected object to the new view controller. 110 | } 111 | */ 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TabPager/TYTabPagerBarLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // TYTabPagerBarLayout.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 2017/7/17. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TYTabPagerBarCell.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | typedef NS_ENUM(NSUInteger, TYPagerBarStyle) { 15 | TYPagerBarStyleNoneView, 16 | TYPagerBarStyleProgressView, 17 | TYPagerBarStyleProgressBounceView, 18 | TYPagerBarStyleProgressElasticView, 19 | TYPagerBarStyleCoverView, 20 | }; 21 | 22 | @class TYTabPagerBar; 23 | @interface TYTabPagerBarLayout : NSObject 24 | 25 | @property (nonatomic, weak, readonly) TYTabPagerBar *pagerTabBar; 26 | @property (nonatomic, assign, readonly) CGFloat selectFontScale; 27 | 28 | // set barStyle will reset propertys, so you should first time set it, 29 | @property (nonatomic, assign) TYPagerBarStyle barStyle; // default TYPagerBarStyleProgressElasticView 30 | 31 | @property (nonatomic, assign) UIEdgeInsets sectionInset; 32 | 33 | // progress view 34 | @property (nonatomic, assign) CGFloat progressHeight; // default 2 35 | @property (nonatomic, assign) CGFloat progressWidth; //if > 0 progress width is equal,else progress width is cell width 36 | @property (nonatomic, strong, nullable) UIColor *progressColor; 37 | 38 | @property (nonatomic, assign) CGFloat progressRadius; // height/2 39 | @property (nonatomic, assign) CGFloat progressBorderWidth; 40 | @property (nonatomic, strong, nullable) UIColor *progressBorderColor; 41 | 42 | @property (nonatomic, assign) CGFloat progressHorEdging; // default 6, if < 0 width + edge ,if >0 width - edge 43 | @property (nonatomic, assign) CGFloat progressVerEdging; // default 0, cover style is 3. 44 | 45 | // cell frame 46 | @property (nonatomic, assign) CGFloat cellWidth; // default 0, if > 0 cells width is equal,else if = 0 cell will call delegate 47 | @property (nonatomic, assign) CGFloat cellSpacing; // default 2,cell space 48 | @property (nonatomic, assign) CGFloat cellEdging; // default 0,cell left right edge 49 | @property (nonatomic, assign) BOOL adjustContentCellsCenter;// default NO, cells center if contentSize < bar's width ,will set sectionInset 50 | 51 | // TYTabPagerBarCellProtocol -> cell's label 52 | @property (nonatomic, strong) UIFont *normalTextFont; // default 15 53 | @property (nonatomic, strong) UIFont *selectedTextFont; // default 17 54 | @property (nonatomic, strong) UIColor *normalTextColor; // default 51.51.51 55 | @property (nonatomic, strong) UIColor *selectedTextColor; // default white 56 | @property (nonatomic, assign) BOOL textColorProgressEnable; // default YES 57 | 58 | // animate duration 59 | @property (nonatomic, assign) CGFloat animateDuration; // default 0.3 60 | 61 | - (instancetype)init NS_UNAVAILABLE; 62 | + (instancetype)new NS_UNAVAILABLE; 63 | 64 | - (instancetype)initWithPagerTabBar:(TYTabPagerBar *)pagerTabBar NS_DESIGNATED_INITIALIZER; 65 | 66 | - (void)layoutIfNeed; 67 | 68 | - (void)invalidateLayout; 69 | 70 | - (void)layoutSubViews; 71 | 72 | - (void)adjustContentCellsCenterInBar; 73 | 74 | // override 75 | - (void)transitionFromCell:(UICollectionViewCell *_Nullable)fromCell toCell:(UICollectionViewCell *_Nullable)toCell animate:(BOOL)animate; 76 | 77 | - (void)transitionFromCell:(UICollectionViewCell *_Nullable)fromCell toCell:(UICollectionViewCell *_Nullable)toCell progress:(CGFloat)progress; 78 | 79 | - (void)setUnderLineFrameWithIndex:(NSInteger)index animated:(BOOL)animated; 80 | 81 | - (void)setUnderLineFrameWithfromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress; 82 | @end 83 | 84 | NS_ASSUME_NONNULL_END 85 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/ListViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ListViewController.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 16/5/17. 6 | // Copyright © 2016年 tanyang. All rights reserved. 7 | // 8 | 9 | #import "ListViewController.h" 10 | 11 | @interface ListViewController () 12 | @property (nonatomic, weak) UITableView *tableView; 13 | @end 14 | 15 | @implementation ListViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view. 20 | 21 | [self addTableView]; 22 | 23 | [self addHorHeaderScrollView]; 24 | } 25 | 26 | - (void)viewWillAppear:(BOOL)animated 27 | { 28 | [super viewWillAppear:animated]; 29 | NSLog(@"viewWillAppear index %@",_text); 30 | } 31 | 32 | - (void)viewDidAppear:(BOOL)animated 33 | { 34 | [super viewWillAppear:animated]; 35 | NSLog(@"viewDidAppear index %@",_text); 36 | } 37 | 38 | - (void)viewWillDisappear:(BOOL)animated 39 | { 40 | [super viewWillDisappear:animated]; 41 | NSLog(@"viewWillDisappear index %@",_text); 42 | } 43 | 44 | - (void)viewDidDisappear:(BOOL)animated 45 | { 46 | [super viewWillDisappear:animated]; 47 | NSLog(@"viewDidDisappear index %@",_text); 48 | } 49 | 50 | - (void)viewDidLayoutSubviews 51 | { 52 | [super viewDidLayoutSubviews]; 53 | self.tableView.frame = self.view.bounds; 54 | } 55 | 56 | - (void)addTableView 57 | { 58 | UITableView *tableView = [[UITableView alloc]init]; 59 | tableView.delegate = self; 60 | tableView.dataSource = self; 61 | 62 | [self.view addSubview:tableView]; 63 | _tableView = tableView; 64 | [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cellId"]; 65 | } 66 | 67 | - (void)addHorHeaderScrollView 68 | { 69 | UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), 200)]; 70 | scrollView.pagingEnabled = YES; 71 | scrollView.showsHorizontalScrollIndicator = NO; 72 | scrollView.contentSize = CGSizeMake(2*CGRectGetWidth(self.view.frame), 0); 73 | [self.view addSubview:scrollView]; 74 | 75 | UIView *page1View = [[UIView alloc]initWithFrame:scrollView.bounds]; 76 | page1View.backgroundColor = [UIColor orangeColor]; 77 | [scrollView addSubview:page1View]; 78 | UIView *page2View = [[UIView alloc]initWithFrame:CGRectMake(CGRectGetWidth(self.view.frame), 0, CGRectGetWidth(self.view.frame), 200)]; 79 | page2View.backgroundColor = [UIColor redColor]; 80 | [scrollView addSubview:page2View]; 81 | 82 | _tableView.tableHeaderView = scrollView; 83 | } 84 | 85 | #pragma mark - delegate 86 | 87 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 88 | { 89 | return 20; 90 | } 91 | 92 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 93 | { 94 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellId" forIndexPath:indexPath]; 95 | cell.textLabel.text = [NSString stringWithFormat:@"text row %ld",indexPath.row]; 96 | return cell; 97 | } 98 | 99 | - (void)didReceiveMemoryWarning { 100 | [super didReceiveMemoryWarning]; 101 | // Dispose of any resources that can be recreated. 102 | } 103 | 104 | /* 105 | #pragma mark - Navigation 106 | 107 | // In a storyboard-based application, you will often want to do a little preparation before navigation 108 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 109 | // Get the new view controller using [segue destinationViewController]. 110 | // Pass the selected object to the new view controller. 111 | } 112 | */ 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TYPagerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TYPagerView.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/5. 6 | // Copyright © 2017年 tanyang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TYPagerViewLayout.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @class TYPagerView; 15 | @protocol TYPagerViewDataSource 16 | 17 | - (NSInteger)numberOfViewsInPagerView; 18 | 19 | /* 1.if prefetching is YES, the prefetch view not display. 20 | 2.if view will diaplay,will call willAppearView:forIndex:. 21 | 3.layout.frameForItemAtIndex can get view's frame 22 | 4.you can register && dequeue view, usage like tableView 23 | */ 24 | - (UIView *)pagerView:(TYPagerView *)pagerView viewForIndex:(NSInteger)index prefetching:(BOOL)prefetching; 25 | 26 | @end 27 | 28 | @protocol TYPagerViewDelegate 29 | @optional 30 | 31 | // Display customization 32 | // if want do something in view will display,you can implement this 33 | - (void)pagerView:(TYPagerView *)pagerView willAppearView:(UIView *)view forIndex:(NSInteger)index; 34 | - (void)pagerView:(TYPagerView *)pagerView didAppearView:(UIView *)view forIndex:(NSInteger)index; 35 | 36 | // Disappear customization 37 | 38 | - (void)pagerView:(TYPagerView *)pagerView willDisappearView:(UIView *)view forIndex:(NSInteger)index; 39 | - (void)pagerView:(TYPagerView *)pagerView didDisappearView:(UIView *)view forIndex:(NSInteger)index; 40 | 41 | // Transition animation customization 42 | 43 | // if you implement ↓↓↓transitionFromIndex:toIndex:progress:,only tap change index will call this, you can set progressAnimateEnabel NO that not call progress method 44 | - (void)pagerView:(TYPagerView *)pagerView transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated; 45 | 46 | // if you implement the method,also you need implement ↑↑↑transitionFromIndex:toIndex:animated:,deal with tap change index animate 47 | - (void)pagerView:(TYPagerView *)pagerView transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress; 48 | 49 | // scrollView delegate 50 | 51 | - (void)pagerViewDidScroll:(TYPagerView *)pageView; 52 | - (void)pagerViewWillBeginScrolling:(TYPagerView *)pageView animate:(BOOL)animate; 53 | - (void)pagerViewDidEndScrolling:(TYPagerView *)pageView animate:(BOOL)animate; 54 | 55 | 56 | @end 57 | 58 | @interface TYPagerView : UIView 59 | 60 | @property (nonatomic, weak, nullable) id dataSource; 61 | @property (nonatomic, weak, nullable) id delegate; 62 | // pagerView's layout,don't set layout's dataSource to other 63 | @property (nonatomic, strong, readonly) TYPagerViewLayout *layout; 64 | @property (nonatomic, strong, readonly) UIScrollView *scrollView; 65 | 66 | @property (nonatomic, assign, readonly) NSInteger countOfPagerViews; 67 | @property (nonatomic, assign, readonly) NSInteger curIndex;// default -1 68 | 69 | @property (nonatomic, assign, nullable, readonly) NSArray *visibleViews; 70 | 71 | @property (nonatomic, assign) UIEdgeInsets contentInset; 72 | 73 | //if not visible, prefecth, cache view at index, return nil 74 | - (UIView *_Nullable)viewForIndex:(NSInteger)index; 75 | 76 | // register && dequeue's usage like tableView 77 | - (void)registerClass:(Class)Class forViewWithReuseIdentifier:(NSString *)identifier; 78 | - (void)registerNib:(UINib *)nib forViewWithReuseIdentifier:(NSString *)identifier; 79 | - (UIView *)dequeueReusableViewWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index; 80 | 81 | // scroll to index 82 | - (void)scrollToViewAtIndex:(NSInteger)index animate:(BOOL)animate; 83 | 84 | // update data and layout,but don't reset propertys(curIndex,visibleDatas,prefechDatas) 85 | - (void)updateData; 86 | 87 | // reload data and reset propertys 88 | - (void)reloadData; 89 | 90 | @end 91 | 92 | NS_ASSUME_NONNULL_END 93 | 94 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift.xcodeproj/xcuserdata/tany.xcuserdatad/xcschemes/TYPagerControllerDemo_swift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift.xcodeproj/xcuserdata/tanyang.xcuserdatad/xcschemes/TYPagerControllerDemo_swift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TYPagerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TYPagerController.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 16/4/13. 6 | // Copyright © 2016年 tanyang. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "TYPagerViewLayout.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @class TYPagerController; 15 | @protocol TYPagerControllerDataSource 16 | 17 | // viewController's count in pagerController 18 | - (NSInteger)numberOfControllersInPagerController; 19 | 20 | /* 1.viewController at index in pagerController 21 | 2.if prefetching is YES,the controller is preload,not display. 22 | 3.if controller will display,will call viewWillAppear. 23 | 4.you can register && dequeue controller, usage like tableView 24 | */ 25 | - (UIViewController *)pagerController:(TYPagerController *)pagerController controllerForIndex:(NSInteger)index prefetching:(BOOL)prefetching; 26 | 27 | @end 28 | 29 | @protocol TYPagerControllerDelegate 30 | 31 | @optional 32 | 33 | // Display customization 34 | // the same to viewWillAppear, also can use viewController's viewWillAppear 35 | - (void)pagerController:(TYPagerController *)pagerController viewWillAppear:(UIViewController *)viewController forIndex:(NSInteger)index; 36 | - (void)pagerController:(TYPagerController *)pagerController viewDidAppear:(UIViewController *)viewController forIndex:(NSInteger)index; 37 | 38 | // Disappear customization 39 | // the same to viewWillDisappear, also can use viewController's viewWillDisappear 40 | - (void)pagerController:(TYPagerController *)pagerController viewWillDisappear:(UIViewController *)viewController forIndex:(NSInteger)index; 41 | - (void)pagerController:(TYPagerController *)pagerController viewDidDisappear:(UIViewController *)viewController forIndex:(NSInteger)index; 42 | 43 | // Transition animation customization 44 | 45 | - (void)pagerController:(TYPagerController *)pagerController transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated; 46 | 47 | - (void)pagerController:(TYPagerController *)pagerController transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress; 48 | 49 | 50 | // ScrollViewDelegate 51 | 52 | - (void)pagerControllerDidScroll:(TYPagerController *)pagerController; 53 | - (void)pagerControllerWillBeginScrolling:(TYPagerController *)pagerController animate:(BOOL)animate; 54 | - (void)pagerControllerDidEndScrolling:(TYPagerController *)pagerController animate:(BOOL)animate; 55 | 56 | @end 57 | 58 | @interface TYPagerController : UIViewController 59 | 60 | @property (nonatomic, weak, nullable) id dataSource; 61 | @property (nonatomic, weak, nullable) id delegate; 62 | // pagerController's layout,don't set layout's dataSource to other 63 | @property (nonatomic, strong, readonly) TYPagerViewLayout *layout; 64 | @property (nonatomic, weak, readonly) UIScrollView *scrollView; 65 | 66 | @property (nonatomic, assign, readonly) NSInteger countOfControllers; 67 | @property (nonatomic, assign, readonly) NSInteger curIndex;// default -1 68 | 69 | @property (nonatomic, strong, nullable, readonly) NSArray *visibleControllers; 70 | 71 | @property (nonatomic, assign) BOOL automaticallySystemManagerViewAppearanceMethods;// default YES.if YES system auto call view Appearance Methods(eg. viewWillAppear...) 72 | 73 | @property (nonatomic, assign) UIEdgeInsets contentInset; 74 | 75 | //if not visible, prefecth, cache view at index, return nil 76 | - (UIViewController *_Nullable)controllerForIndex:(NSInteger)index; 77 | 78 | // register && dequeue's usage like tableView 79 | - (void)registerClass:(Class)Class forControllerWithReuseIdentifier:(NSString *)identifier; 80 | - (void)registerNib:(UINib *)nib forControllerWithReuseIdentifier:(NSString *)identifier; 81 | - (UIViewController *)dequeueReusableControllerWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index; 82 | 83 | // scroll to index 84 | - (void)scrollToControllerAtIndex:(NSInteger)index animate:(BOOL)animate; 85 | 86 | // update data and layout,but don't reset propertys(curIndex,visibleDatas,prefechDatas) 87 | - (void)updateData; 88 | 89 | // reload data and reset propertys 90 | - (void)reloadData; 91 | 92 | @end 93 | 94 | NS_ASSUME_NONNULL_END 95 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/CustomViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CustomViewController.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 16/4/20. 6 | // Copyright © 2016年 tanyang. All rights reserved. 7 | // 8 | 9 | #import "CustomViewController.h" 10 | #import "PagerControllerDmeoController.h" 11 | 12 | @interface CustomViewController () 13 | @property (nonatomic, weak) UILabel *label; 14 | @property (nonatomic, weak) UIButton *pushBtn; 15 | @property (nonatomic, weak) UIButton *cancelBtn; 16 | @end 17 | 18 | @implementation CustomViewController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | // Do any additional setup after loading the view. 23 | //NSLog(@"text %@",_text); 24 | [self addPageLabel]; 25 | [self addPushButton]; 26 | [self addPopButton]; 27 | } 28 | 29 | - (void)viewWillLayoutSubviews 30 | { 31 | [super viewWillLayoutSubviews]; 32 | _label.center = CGPointMake(CGRectGetWidth(self.view.frame)/2, CGRectGetHeight(self.view.frame)/2); 33 | _cancelBtn.center = CGPointMake(_label.center.x,_label.center.y + 100); 34 | _pushBtn.center = CGPointMake(_label.center.x,_label.center.y + 50); 35 | } 36 | 37 | - (void)addPageLabel 38 | { 39 | UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 200, 50)]; 40 | label.text = _text; 41 | label.font = [UIFont systemFontOfSize:32]; 42 | label.textAlignment = NSTextAlignmentCenter; 43 | [self.view addSubview:label]; 44 | _label = label; 45 | self.view.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:arc4random()%255/255.0]; 46 | } 47 | 48 | - (void)addPushButton 49 | { 50 | UIButton *cancelBtn = [UIButton buttonWithType:UIButtonTypeSystem]; 51 | cancelBtn.titleLabel.font = [UIFont systemFontOfSize:21]; 52 | [cancelBtn setTitle:@"posh VC" forState:UIControlStateNormal]; 53 | [cancelBtn addTarget:self action:@selector(pushVC) forControlEvents:UIControlEventTouchUpInside]; 54 | cancelBtn.frame = CGRectMake(0, 0, 100, 40); 55 | cancelBtn.center = CGPointMake(self.view.center.x, self.view.center.y + 60); 56 | [self.view addSubview:cancelBtn]; 57 | _pushBtn = cancelBtn; 58 | } 59 | 60 | - (void)addPopButton 61 | { 62 | UIButton *cancelBtn = [UIButton buttonWithType:UIButtonTypeSystem]; 63 | cancelBtn.titleLabel.font = [UIFont systemFontOfSize:21]; 64 | [cancelBtn setTitle:@"pop back" forState:UIControlStateNormal]; 65 | [cancelBtn addTarget:self action:@selector(popBack) forControlEvents:UIControlEventTouchUpInside]; 66 | cancelBtn.frame = CGRectMake(0, 0, 100, 40); 67 | cancelBtn.center = CGPointMake(self.view.center.x, self.view.center.y + 60); 68 | [self.view addSubview:cancelBtn]; 69 | _cancelBtn = cancelBtn; 70 | } 71 | 72 | - (void)viewWillAppear:(BOOL)animated 73 | { 74 | [super viewWillAppear:animated]; 75 | NSLog(@"viewWillAppear index %@",_text); 76 | } 77 | 78 | - (void)viewDidAppear:(BOOL)animated 79 | { 80 | [super viewWillAppear:animated]; 81 | NSLog(@"viewDidAppear index %@",_text); 82 | } 83 | 84 | - (void)viewWillDisappear:(BOOL)animated 85 | { 86 | [super viewWillDisappear:animated]; 87 | NSLog(@"viewWillDisappear index %@",_text); 88 | } 89 | 90 | - (void)viewDidDisappear:(BOOL)animated 91 | { 92 | [super viewWillDisappear:animated]; 93 | NSLog(@"viewDidDisappear index %@",_text); 94 | } 95 | 96 | 97 | - (void)pushVC { 98 | PagerControllerDmeoController *vc = [[PagerControllerDmeoController alloc]init]; 99 | [self.navigationController pushViewController:vc animated:YES]; 100 | } 101 | 102 | - (void)popBack 103 | { 104 | [self.navigationController popViewControllerAnimated:YES]; 105 | } 106 | 107 | - (void)didReceiveMemoryWarning { 108 | [super didReceiveMemoryWarning]; 109 | // Dispose of any resources that can be recreated. 110 | } 111 | 112 | /* 113 | #pragma mark - Navigation 114 | 115 | // In a storyboard-based application, you will often want to do a little preparation before navigation 116 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 117 | // Get the new view controller using [segue destinationViewController]. 118 | // Pass the selected object to the new view controller. 119 | } 120 | */ 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift/PagerControlerDemoController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PagerControlerDemoController.swift 3 | // TYPagerControllerDemo_swift 4 | // 5 | // Created by tany on 2017/7/19. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PagerControlerDemoController: UIViewController { 12 | 13 | lazy var tabBar = TYTabPagerBar() 14 | lazy var pagerController = TYPagerController() 15 | 16 | lazy var datas = [String]() 17 | 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | // Do any additional setup after loading the view. 21 | self.view.backgroundColor = UIColor.white 22 | self.addTabPagerBar() 23 | self.addPagerController() 24 | 25 | self.loadData() 26 | } 27 | 28 | func addTabPagerBar() { 29 | self.tabBar.delegate = self 30 | self.tabBar.dataSource = self 31 | self.tabBar.register(TYTabPagerBarCell.classForCoder(), forCellWithReuseIdentifier: NSStringFromClass(TYTabPagerBarCell.classForCoder())) 32 | self.view.addSubview(self.tabBar) 33 | } 34 | 35 | func addPagerController() { 36 | self.pagerController.dataSource = self 37 | self.pagerController.delegate = self 38 | self.addChildViewController(self.pagerController) 39 | self.view.addSubview(self.pagerController.view) 40 | } 41 | 42 | override func viewWillLayoutSubviews() { 43 | super.viewWillLayoutSubviews() 44 | self.tabBar.frame = CGRect(x: 0, y: 64, width: self.view.frame.width, height: 40) 45 | self.pagerController.view.frame = CGRect(x: 0, y: self.tabBar.frame.maxY, width: self.view.frame.width, height: self.view.frame.height - self.tabBar.frame.maxY) 46 | } 47 | 48 | func loadData() { 49 | var i = 0 50 | while i < 20 { 51 | self.datas.append(i%2==0 ?"Tab \(i)":"Tab Tab \(i)") 52 | i += 1 53 | } 54 | self.reloadData() 55 | } 56 | 57 | func reloadData() { 58 | self.tabBar.reloadData() 59 | self.pagerController.reloadData() 60 | } 61 | 62 | override func didReceiveMemoryWarning() { 63 | super.didReceiveMemoryWarning() 64 | // Dispose of any resources that can be recreated. 65 | } 66 | } 67 | 68 | extension PagerControlerDemoController: TYTabPagerBarDataSource, TYTabPagerBarDelegate { 69 | func numberOfItemsInPagerTabBar() -> Int { 70 | return self.datas.count 71 | } 72 | 73 | func pagerTabBar(_ pagerTabBar: TYTabPagerBar, cellForItemAt index: Int) -> UICollectionViewCell { 74 | let cell = pagerTabBar.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(TYTabPagerBarCell.classForCoder()), for: index) 75 | (cell as? TYTabPagerBarCellProtocol)?.titleLabel.text = self.datas[index] 76 | return cell 77 | } 78 | 79 | func pagerTabBar(_ pagerTabBar: TYTabPagerBar, widthForItemAt index: Int) -> CGFloat { 80 | let title = self.datas[index] 81 | return pagerTabBar.cellWidth(forTitle: title) 82 | } 83 | 84 | func pagerTabBar(_ pagerTabBar: TYTabPagerBar, didSelectItemAt index: Int) { 85 | self.pagerController.scrollToController(at: index, animate: true); 86 | } 87 | } 88 | 89 | extension PagerControlerDemoController: TYPagerControllerDataSource, TYPagerControllerDelegate { 90 | func numberOfControllersInPagerController() -> Int { 91 | return self.datas.count 92 | } 93 | 94 | func pagerController(_ pagerController: TYPagerController, controllerFor index: Int, prefetching: Bool) -> UIViewController { 95 | let vc = UIViewController() 96 | vc.view.backgroundColor = UIColor(red: CGFloat(arc4random()%255)/255.0, green: CGFloat(arc4random()%255)/255.0, blue: CGFloat(arc4random()%255)/255.0, alpha: 1) 97 | return vc 98 | } 99 | 100 | func pagerController(_ pagerController: TYPagerController, transitionFrom fromIndex: Int, to toIndex: Int, animated: Bool) { 101 | self.tabBar.scrollToItem(from: fromIndex, to: toIndex, animate: animated) 102 | } 103 | func pagerController(_ pagerController: TYPagerController, transitionFrom fromIndex: Int, to toIndex: Int, progress: CGFloat) { 104 | self.tabBar.scrollToItem(from: fromIndex, to: toIndex, progress: progress) 105 | } 106 | } 107 | 108 | -------------------------------------------------------------------------------- /TYPagerControllerDemo.xcodeproj/xcuserdata/tany.xcuserdatad/xcschemes/TYPagerControllerDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /TYPagerControllerDemo.xcodeproj/xcuserdata/tanyang.xcuserdatad/xcschemes/TYPagerControllerDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/PagerControllerDmeoController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PagerControllerDmeoController.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/19. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import "PagerControllerDmeoController.h" 10 | #import "TYTabPagerBar.h" 11 | #import "TYPagerController.h" 12 | #import "ListViewController.h" 13 | #import "CollectionViewController.h" 14 | #import "CustomViewController.h" 15 | 16 | @interface PagerControllerDmeoController () 17 | 18 | @property (nonatomic, weak) TYTabPagerBar *tabBar; 19 | @property (nonatomic, weak) TYPagerController *pagerController; 20 | 21 | @property (nonatomic, strong) NSArray *datas; 22 | 23 | @end 24 | 25 | @implementation PagerControllerDmeoController 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | // Do any additional setup after loading the view. 30 | self.title = @"PagerControllerDmeoController"; 31 | self.view.backgroundColor = [UIColor whiteColor]; 32 | 33 | [self addTabPageBar]; 34 | 35 | [self addPagerController]; 36 | 37 | [self loadData]; 38 | } 39 | 40 | - (void)addTabPageBar { 41 | TYTabPagerBar *tabBar = [[TYTabPagerBar alloc]init]; 42 | tabBar.layout.barStyle = TYPagerBarStyleProgressElasticView; 43 | tabBar.dataSource = self; 44 | tabBar.delegate = self; 45 | [tabBar registerClass:[TYTabPagerBarCell class] forCellWithReuseIdentifier:[TYTabPagerBarCell cellIdentifier]]; 46 | [self.view addSubview:tabBar]; 47 | _tabBar = tabBar; 48 | } 49 | 50 | - (void)addPagerController { 51 | TYPagerController *pagerController = [[TYPagerController alloc]init]; 52 | pagerController.layout.prefetchItemCount = 1; 53 | //pagerController.layout.autoMemoryCache = NO; 54 | // 只有当scroll滚动动画停止时才加载pagerview,用于优化滚动时性能 55 | pagerController.layout.addVisibleItemOnlyWhenScrollAnimatedEnd = YES; 56 | pagerController.dataSource = self; 57 | pagerController.delegate = self; 58 | [self addChildViewController:pagerController]; 59 | [self.view addSubview:pagerController.view]; 60 | _pagerController = pagerController; 61 | } 62 | 63 | - (void)viewWillAppear:(BOOL)animated { 64 | [super viewWillAppear:animated]; 65 | } 66 | 67 | - (void)viewWillDisappear:(BOOL)animated { 68 | [super viewWillDisappear:animated]; 69 | } 70 | 71 | - (void)viewWillLayoutSubviews { 72 | [super viewWillLayoutSubviews]; 73 | _tabBar.frame = CGRectMake(0, CGRectGetMaxY(self.navigationController.navigationBar.frame), CGRectGetWidth(self.view.frame), 36); 74 | _pagerController.view.frame = CGRectMake(0, CGRectGetMaxY(_tabBar.frame), CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)- CGRectGetMaxY(_tabBar.frame)); 75 | } 76 | 77 | - (void)loadData { 78 | NSMutableArray *datas = [NSMutableArray array]; 79 | for (NSInteger i = 0; i < 20; ++i) { 80 | [datas addObject:i%2 == 0 ? [NSString stringWithFormat:@"Tab %ld",i]:[NSString stringWithFormat:@"Tab Tab %ld",i]]; 81 | } 82 | _datas = [datas copy]; 83 | 84 | [self reloadData]; 85 | } 86 | 87 | #pragma mark - TYTabPagerBarDataSource 88 | 89 | - (NSInteger)numberOfItemsInPagerTabBar { 90 | return _datas.count; 91 | } 92 | 93 | - (UICollectionViewCell *)pagerTabBar:(TYTabPagerBar *)pagerTabBar cellForItemAtIndex:(NSInteger)index { 94 | UICollectionViewCell *cell = [pagerTabBar dequeueReusableCellWithReuseIdentifier:[TYTabPagerBarCell cellIdentifier] forIndex:index]; 95 | cell.titleLabel.text = _datas[index]; 96 | return cell; 97 | } 98 | 99 | #pragma mark - TYTabPagerBarDelegate 100 | 101 | - (CGFloat)pagerTabBar:(TYTabPagerBar *)pagerTabBar widthForItemAtIndex:(NSInteger)index { 102 | NSString *title = _datas[index]; 103 | return [pagerTabBar cellWidthForTitle:title]; 104 | } 105 | 106 | - (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar didSelectItemAtIndex:(NSInteger)index { 107 | [_pagerController scrollToControllerAtIndex:index animate:YES]; 108 | } 109 | 110 | #pragma mark - TYPagerControllerDataSource 111 | 112 | - (NSInteger)numberOfControllersInPagerController { 113 | return 20; 114 | } 115 | 116 | - (UIViewController *)pagerController:(TYPagerController *)pagerController controllerForIndex:(NSInteger)index prefetching:(BOOL)prefetching { 117 | if (index%3 == 0) { 118 | CustomViewController *VC = [[CustomViewController alloc]init]; 119 | VC.text = [@(index) stringValue]; 120 | return VC; 121 | }else if (index%3 == 1) { 122 | ListViewController *VC = [[ListViewController alloc]init]; 123 | VC.text = [@(index) stringValue]; 124 | return VC; 125 | }else { 126 | CollectionViewController *VC = [[CollectionViewController alloc]init]; 127 | VC.text = [@(index) stringValue]; 128 | return VC; 129 | } 130 | } 131 | 132 | #pragma mark - TYPagerControllerDelegate 133 | 134 | - (void)pagerController:(TYPagerController *)pagerController transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated { 135 | [_tabBar scrollToItemFromIndex:fromIndex toIndex:toIndex animate:animated]; 136 | } 137 | 138 | -(void)pagerController:(TYPagerController *)pagerController transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress { 139 | [_tabBar scrollToItemFromIndex:fromIndex toIndex:toIndex progress:progress]; 140 | } 141 | 142 | - (void)reloadData { 143 | [_tabBar reloadData]; 144 | [_pagerController reloadData]; 145 | } 146 | 147 | - (void)didReceiveMemoryWarning { 148 | [super didReceiveMemoryWarning]; 149 | // Dispose of any resources that can be recreated. 150 | } 151 | @end 152 | -------------------------------------------------------------------------------- /TYPagerControllerDemo_swift/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 31 | 38 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TYPagerViewLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // TYPagerViewLayout.h 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 2017/7/9. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NSObject (TY_PagerReuseIdentify) 14 | // resueId 15 | @property (nonatomic, strong, readonly, nullable) NSString *ty_pagerReuseIdentify; 16 | 17 | @end 18 | 19 | @class TYPagerViewLayout; 20 | @protocol TYPagerViewLayoutDataSource 21 | 22 | - (NSInteger)numberOfItemsInPagerViewLayout; 23 | 24 | // if item is preload, prefetch will YES 25 | - (id)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout itemForIndex:(NSInteger)index prefetching:(BOOL)prefetching; 26 | 27 | // return item's view 28 | - (UIView *)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout viewForItem:(id)item atIndex:(NSInteger)index; 29 | 30 | // see TYPagerView&&TYPagerController, add&&remove item ,must implement scrollView addSubView item's view 31 | - (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout addVisibleItem:(id)item atIndex:(NSInteger)index; 32 | - (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout removeInVisibleItem:(id)item atIndex:(NSInteger)index; 33 | 34 | @optional 35 | 36 | // if have not viewController return nil. 37 | - (UIViewController *)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout viewControllerForItem:(id)item atIndex:(NSInteger)index; 38 | 39 | @end 40 | 41 | @protocol TYPagerViewLayoutDelegate 42 | 43 | @optional 44 | 45 | // Transition animation customization 46 | 47 | // if you implement ↓↓↓transitionFromIndex:toIndex:progress:,only tap change index will call this, you can set progressAnimateEnabel NO that not call progress method 48 | - (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated; 49 | 50 | // if you implement the method,also you need implement ↑↑↑transitionFromIndex:toIndex:animated:,deal with tap change index animate 51 | - (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress; 52 | 53 | // ScrollViewDelegate 54 | 55 | - (void)pagerViewLayoutDidScroll:(TYPagerViewLayout *)pagerViewLayout; 56 | - (void)pagerViewLayoutWillBeginScrollToView:(TYPagerViewLayout *)pagerViewLayout animate:(BOOL)animate; 57 | - (void)pagerViewLayoutDidEndScrollToView:(TYPagerViewLayout *)pagerViewLayout animate:(BOOL)animate; 58 | - (void)pagerViewLayoutWillBeginDragging:(TYPagerViewLayout *)pagerViewLayout; 59 | - (void)pagerViewLayoutDidEndDragging:(TYPagerViewLayout *)pagerViewLayout willDecelerate:(BOOL)decelerate; 60 | - (void)pagerViewLayoutWillBeginDecelerating:(TYPagerViewLayout *)pagerViewLayout; 61 | - (void)pagerViewLayoutDidEndDecelerating:(TYPagerViewLayout *)pagerViewLayout; 62 | - (void)pagerViewLayoutDidEndScrollingAnimation:(TYPagerViewLayout *)pagerViewLayout; 63 | 64 | @end 65 | 66 | @interface TYPagerViewLayout<__covariant ItemType> : NSObject 67 | 68 | @property (nonatomic, weak, nullable) id dataSource; 69 | @property (nonatomic, weak, nullable) id delegate; 70 | 71 | // strong,will control the delegate,don't set delegate on other place. 72 | @property (nonatomic, strong, readonly) UIScrollView *scrollView; 73 | // if viewcontroller's automaticallyAdjustsScrollViewInsets YES ,will cause frame problems, you can set YES, default YES 74 | @property (nonatomic, assign) BOOL adjustScrollViewInset; 75 | 76 | @property (nonatomic, assign, readonly) NSInteger countOfPagerItems; 77 | @property (nonatomic, assign, readonly) NSInteger curIndex;// default -1 78 | 79 | @property (nonatomic, strong, readonly) NSCache *memoryCache;; // will cache pagerView,you can set countLimit 80 | @property (nonatomic, assign) BOOL autoMemoryCache; // default YES 81 | 82 | @property (nonatomic, assign) NSInteger prefetchItemCount;// preload left and right item's count , default 0 83 | // because when superview add subview(have tableView) will call relodData,if set Yes will optimize. default NO 84 | @property (nonatomic, assign) BOOL prefetchItemWillAddToSuperView; 85 | 86 | @property (nonatomic, assign, readonly) NSRange prefetchRange; 87 | @property (nonatomic, assign, readonly) NSRange visibleRange; 88 | 89 | @property (nonatomic, strong, nullable, readonly) NSArray * visibleIndexs; 90 | @property (nonatomic, strong, nullable, readonly) NSArray * visibleItems; 91 | 92 | // default YES, if NO,will not call delegate transitionFromIndex:toIndex:progress:,but will call transitionFromIndex:toIndex: 93 | @property (nonatomic, assign) BOOL progressAnimateEnabel; 94 | 95 | // default NO, when scroll visible range change will add item.If YES add item only when scroll animate end, suggest set prefetchItemCount 1 or more 96 | @property (nonatomic, assign) BOOL addVisibleItemOnlyWhenScrollAnimatedEnd; 97 | 98 | // default 0.5,when scroll progress percent will change index, only progressAnimateEnabel is NO or don't implement delegate transitionFromIndex: toIndex: progress: 99 | @property (nonatomic, assign) CGFloat changeIndexWhenScrollProgress; 100 | 101 | - (instancetype)init NS_UNAVAILABLE; 102 | + (instancetype)new NS_UNAVAILABLE; 103 | 104 | /** 105 | initializer will strong scrollView,and control delegate,don't set delegate on other place. 106 | */ 107 | - (instancetype)initWithScrollView:(UIScrollView *)scrollView NS_DESIGNATED_INITIALIZER; // strong scrollView 108 | 109 | - (ItemType _Nullable)itemForIndex:(NSInteger)idx; 110 | 111 | - (UIView *)viewForItem:(ItemType)item atIndex:(NSInteger)index; 112 | // if have not viewController return nil. 113 | - (UIViewController *_Nullable)viewControllerForItem:(id)item atIndex:(NSInteger)index; 114 | 115 | // view's frame at index 116 | - (CGRect)frameForItemAtIndex:(NSInteger)index; 117 | 118 | // register && dequeue's usage like tableView 119 | - (void)registerClass:(Class)Class forItemWithReuseIdentifier:(NSString *)identifier; 120 | - (void)registerNib:(UINib *)nib forItemWithReuseIdentifier:(NSString *)identifier; 121 | - (ItemType)dequeueReusableItemWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index; 122 | 123 | // scroll to index 124 | - (void)scrollToItemAtIndex:(NSInteger)index animate:(BOOL)animate; 125 | 126 | // update data and layout,the same to relaodData,but don't reset propertys(curIndex,visibleDatas,prefechDatas) 127 | - (void)updateData; 128 | 129 | // reload data and reset propertys 130 | - (void)reloadData; 131 | 132 | @end 133 | 134 | NS_ASSUME_NONNULL_END 135 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/PagerViewDmeoController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PagerViewDmeoController.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 2017/7/6. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import "PagerViewDmeoController.h" 10 | #import "TYPagerView.h" 11 | #import "TYTabPagerBar.h" 12 | 13 | @interface PagerViewDmeoController () 14 | @property (nonatomic, weak) TYTabPagerBar *tabBar; 15 | @property (nonatomic, weak) TYPagerView *pageView; 16 | 17 | @property (nonatomic, strong) NSArray *datas; 18 | 19 | @end 20 | 21 | @implementation PagerViewDmeoController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | // Do any additional setup after loading the view. 26 | //self.automaticallyAdjustsScrollViewInsets = NO; 27 | self.view.backgroundColor = [UIColor whiteColor]; 28 | UIBarButtonItem *reloadItem = [[UIBarButtonItem alloc]initWithTitle:@"reload" style:UIBarButtonItemStylePlain target:self action:@selector(reloadData)]; 29 | UIBarButtonItem *scrollItem = [[UIBarButtonItem alloc]initWithTitle:@"update" style:UIBarButtonItemStylePlain target:self action:@selector(updateData)]; 30 | self.navigationItem.rightBarButtonItems = @[reloadItem,scrollItem]; 31 | [self addPagerTabBar]; 32 | [self addPagerView]; 33 | 34 | [self loadData]; 35 | } 36 | 37 | - (void)addPagerTabBar { 38 | TYTabPagerBar *tabBar = [[TYTabPagerBar alloc]init]; 39 | tabBar.layout.barStyle = TYPagerBarStyleProgressElasticView; 40 | tabBar.dataSource = self; 41 | tabBar.delegate = self; 42 | [tabBar registerClass:[TYTabPagerBarCell class] forCellWithReuseIdentifier:[TYTabPagerBarCell cellIdentifier]]; 43 | [self.view addSubview:tabBar]; 44 | _tabBar = tabBar; 45 | } 46 | 47 | - (void)addPagerView { 48 | TYPagerView *pageView = [[TYPagerView alloc]init]; 49 | //pageView.layout.progressAnimateEnabel = NO; 50 | //pageView.layout.prefetchItemCount = 1; 51 | pageView.layout.autoMemoryCache = NO; 52 | pageView.dataSource = self; 53 | pageView.delegate = self; 54 | // you can rigsiter cell like tableView 55 | [pageView.layout registerClass:[UIView class] forItemWithReuseIdentifier:@"cellId"]; 56 | [self.view addSubview:pageView]; 57 | _pageView = pageView; 58 | } 59 | 60 | - (void)loadData { 61 | NSMutableArray *datas = [NSMutableArray array]; 62 | for (NSInteger i = 0; i < 10; ++i) { 63 | [datas addObject:i%2 == 0 ? [NSString stringWithFormat:@"Tab %ld",i]:[NSString stringWithFormat:@"Tab Tab %ld",i]]; 64 | } 65 | _datas = [datas copy]; 66 | 67 | [self reloadData]; 68 | } 69 | 70 | - (void)updateData { 71 | NSMutableArray *datas = [NSMutableArray array]; 72 | for (NSInteger i = 0; i *)pagerTabBar:(TYTabPagerBar *)pagerTabBar cellForItemAtIndex:(NSInteger)index { 100 | UICollectionViewCell *cell = [pagerTabBar dequeueReusableCellWithReuseIdentifier:[TYTabPagerBarCell cellIdentifier] forIndex:index]; 101 | cell.titleLabel.text = _datas[index]; 102 | return cell; 103 | } 104 | 105 | #pragma mark - TYTabPagerBarDelegate 106 | 107 | - (CGFloat)pagerTabBar:(TYTabPagerBar *)pagerTabBar widthForItemAtIndex:(NSInteger)index { 108 | NSString *title = _datas[index]; 109 | return [pagerTabBar cellWidthForTitle:title]; 110 | } 111 | 112 | - (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar didSelectItemAtIndex:(NSInteger)index { 113 | [_pageView scrollToViewAtIndex:index animate:YES]; 114 | } 115 | 116 | #pragma mark - TYPagerViewDataSource 117 | 118 | - (NSInteger)numberOfViewsInPagerView { 119 | return _datas.count; 120 | } 121 | 122 | - (UIView *)pagerView:(TYPagerView *)pagerView viewForIndex:(NSInteger)index prefetching:(BOOL)prefetching { 123 | //you can set UIView *view = [[UIView alloc]initWithFrame:[pagerView.layout frameForItemAtIndex:index]]; or UIView *view = [[UIView alloc]init]; 124 | //or reigster and dequeue item like tableView 125 | UIView *view = [pagerView.layout dequeueReusableItemWithReuseIdentifier:@"cellId" forIndex:index]; 126 | view.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:arc4random()%255/255.0]; 127 | //NSLog(@"viewForIndex:%ld prefetching:%d",index,prefetching); 128 | return view; 129 | } 130 | 131 | #pragma mark - TYPagerViewDelegate 132 | 133 | - (void)pagerView:(TYPagerView *)pagerView willAppearView:(UIView *)view forIndex:(NSInteger)index { 134 | //NSLog(@"+++++++++willAppearViewIndex:%ld",index); 135 | } 136 | 137 | - (void)pagerView:(TYPagerView *)pagerView willDisappearView:(UIView *)view forIndex:(NSInteger)index { 138 | //NSLog(@"---------willDisappearView:%ld",index); 139 | } 140 | 141 | - (void)pagerView:(TYPagerView *)pagerView transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated { 142 | NSLog(@"fromIndex:%ld, toIndex:%ld",fromIndex,toIndex); 143 | [_tabBar scrollToItemFromIndex:fromIndex toIndex:toIndex animate:animated]; 144 | } 145 | 146 | - (void)pagerView:(TYPagerView *)pagerView transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress { 147 | //NSLog(@"fromIndex:%ld, toIndex:%ld progress%.3f",fromIndex,toIndex,progress); 148 | [_tabBar scrollToItemFromIndex:fromIndex toIndex:toIndex progress:progress]; 149 | } 150 | 151 | - (void)pagerViewWillBeginScrolling:(TYPagerView *)pageView animate:(BOOL)animate { 152 | //NSLog(@"pagerViewWillBeginScrolling"); 153 | } 154 | 155 | - (void)pagerViewDidEndScrolling:(TYPagerView *)pageView animate:(BOOL)animate { 156 | //NSLog(@"pagerViewDidEndScrolling"); 157 | } 158 | 159 | - (void)didReceiveMemoryWarning { 160 | [super didReceiveMemoryWarning]; 161 | // Dispose of any resources that can be recreated. 162 | } 163 | 164 | /* 165 | #pragma mark - Navigation 166 | 167 | // In a storyboard-based application, you will often want to do a little preparation before navigation 168 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 169 | // Get the new view controller using [segue destinationViewController]. 170 | // Pass the selected object to the new view controller. 171 | } 172 | */ 173 | 174 | @end 175 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 31 | 38 | 45 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TabPager/TYTabPagerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TYTabPagerView.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 2017/7/18. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import "TYTabPagerView.h" 10 | 11 | @interface TYTabPagerView () 12 | 13 | // UI 14 | @property (nonatomic, weak) TYTabPagerBar *tabBar; 15 | @property (nonatomic, weak) TYPagerView *pageView; 16 | 17 | // Data 18 | @property (nonatomic, strong) NSString *identifier; 19 | 20 | @end 21 | 22 | @implementation TYTabPagerView 23 | 24 | - (instancetype)initWithFrame:(CGRect)frame { 25 | if (self = [super initWithFrame:frame]) { 26 | _tabBarHeight = 36; 27 | self.backgroundColor = [UIColor clearColor]; 28 | [self addTabBar]; 29 | 30 | [self addPagerView]; 31 | } 32 | return self; 33 | } 34 | 35 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 36 | if (self = [super initWithCoder:aDecoder]) { 37 | _tabBarHeight = 36; 38 | self.backgroundColor = [UIColor clearColor]; 39 | [self addTabBar]; 40 | 41 | [self addPagerView]; 42 | } 43 | return self; 44 | } 45 | 46 | - (void)addTabBar { 47 | TYTabPagerBar *tabBar = [[TYTabPagerBar alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.frame), _tabBarHeight)]; 48 | tabBar.dataSource = self; 49 | tabBar.delegate = self; 50 | [self addSubview:tabBar]; 51 | _tabBar = tabBar; 52 | [self registerClass:[TYTabPagerBarCell class] forTabBarCellWithReuseIdentifier:[TYTabPagerBarCell cellIdentifier]]; 53 | } 54 | 55 | - (void)addPagerView { 56 | TYPagerView *pageView = [[TYPagerView alloc]initWithFrame:CGRectMake(0, _tabBarHeight, CGRectGetWidth(self.frame), MAX(CGRectGetHeight(self.frame) - _tabBarHeight, 0))]; 57 | pageView.dataSource = self; 58 | pageView.delegate = self; 59 | [self addSubview:pageView]; 60 | _pageView = pageView; 61 | } 62 | 63 | #pragma mark - getter setter 64 | 65 | - (void)setTabBarHeight:(CGFloat)tabBarHeight { 66 | BOOL isChangeValue = _tabBarHeight != tabBarHeight; 67 | _tabBarHeight = tabBarHeight; 68 | if (isChangeValue && self.superview && !CGRectEqualToRect(self.bounds, CGRectZero)) { 69 | [self setNeedsLayout]; 70 | [self layoutIfNeeded]; 71 | } 72 | } 73 | 74 | - (TYPagerViewLayout *)layout { 75 | return _pageView.layout; 76 | } 77 | 78 | #pragma mark - public 79 | 80 | - (void)updateData { 81 | [_tabBar reloadData]; 82 | [_pageView updateData]; 83 | } 84 | 85 | - (void)reloadData { 86 | [_tabBar reloadData]; 87 | [_pageView reloadData]; 88 | } 89 | 90 | // scroll to index 91 | - (void)scrollToViewAtIndex:(NSInteger)index animate:(BOOL)animate { 92 | [_pageView scrollToViewAtIndex:index animate:animate]; 93 | } 94 | 95 | - (void)registerClass:(Class)Class forTabBarCellWithReuseIdentifier:(NSString *)identifier { 96 | _identifier = identifier; 97 | [_tabBar registerClass:Class forCellWithReuseIdentifier:identifier]; 98 | } 99 | - (void)registerNib:(UINib *)nib forTabBarCellWithReuseIdentifier:(NSString *)identifier { 100 | _identifier = identifier; 101 | [_tabBar registerNib:nib forCellWithReuseIdentifier:identifier]; 102 | } 103 | 104 | - (void)registerClass:(Class)Class forPagerCellWithReuseIdentifier:(NSString *)identifier { 105 | [_pageView registerClass:Class forViewWithReuseIdentifier:identifier]; 106 | } 107 | - (void)registerNib:(UINib *)nib forPagerCellWithReuseIdentifier:(NSString *)identifier { 108 | [_pageView registerNib:nib forViewWithReuseIdentifier:identifier]; 109 | } 110 | - (UIView *)dequeueReusablePagerCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index { 111 | return [_pageView dequeueReusableViewWithReuseIdentifier:identifier forIndex:index]; 112 | } 113 | 114 | #pragma mark - TYTabPagerBarDataSource 115 | 116 | - (NSInteger)numberOfItemsInPagerTabBar { 117 | return [_dataSource numberOfViewsInTabPagerView]; 118 | } 119 | 120 | - (UICollectionViewCell *)pagerTabBar:(TYTabPagerBar *)pagerTabBar cellForItemAtIndex:(NSInteger)index { 121 | UICollectionViewCell *cell = [pagerTabBar dequeueReusableCellWithReuseIdentifier:_identifier forIndex:index]; 122 | cell.titleLabel.text = [_dataSource tabPagerView:self titleForIndex:index]; 123 | if ([_delegate respondsToSelector:@selector(tabPagerView:willDisplayCell:atIndex:)]) { 124 | [_delegate tabPagerView:self willDisplayCell:cell atIndex:index]; 125 | } 126 | return cell; 127 | } 128 | 129 | #pragma mark - TYTabPagerBarDelegate 130 | 131 | - (CGFloat)pagerTabBar:(TYTabPagerBar *)pagerTabBar widthForItemAtIndex:(NSInteger)index { 132 | NSString *title = [_dataSource tabPagerView:self titleForIndex:index]; 133 | return [pagerTabBar cellWidthForTitle:title]; 134 | } 135 | 136 | - (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar didSelectItemAtIndex:(NSInteger)index { 137 | [_pageView scrollToViewAtIndex:index animate:YES]; 138 | if ([_delegate respondsToSelector:@selector(tabPagerView:didSelectTabBarItemAtIndex:)]) { 139 | [_delegate tabPagerView:self didSelectTabBarItemAtIndex:index]; 140 | } 141 | } 142 | 143 | #pragma mark - TYPagerViewDataSource 144 | 145 | - (NSInteger)numberOfViewsInPagerView { 146 | return [_dataSource numberOfViewsInTabPagerView]; 147 | } 148 | 149 | - (UIView *)pagerView:(TYPagerView *)pagerView viewForIndex:(NSInteger)index prefetching:(BOOL)prefetching { 150 | UIView *view = [_dataSource tabPagerView:self viewForIndex:index prefetching:prefetching]; 151 | return view; 152 | } 153 | 154 | #pragma mark - TYPagerViewDelegate 155 | 156 | - (void)pagerView:(TYPagerView *)pagerView transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated { 157 | [_tabBar scrollToItemFromIndex:fromIndex toIndex:toIndex animate:animated]; 158 | } 159 | 160 | - (void)pagerView:(TYPagerView *)pagerView transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress { 161 | [_tabBar scrollToItemFromIndex:fromIndex toIndex:toIndex progress:progress]; 162 | } 163 | 164 | - (void)pagerView:(TYPagerView *)pagerView willAppearView:(UIView *)view forIndex:(NSInteger)index { 165 | if ([_delegate respondsToSelector:@selector(tabPagerView:willAppearView:forIndex:)]) { 166 | [_delegate tabPagerView:self willAppearView:view forIndex:index]; 167 | } 168 | } 169 | 170 | - (void)pagerView:(TYPagerView *)pagerView didDisappearView:(UIView *)view forIndex:(NSInteger)index { 171 | if ([_delegate respondsToSelector:@selector(tabPagerView:didDisappearView:forIndex:)]) { 172 | [_delegate tabPagerView:self didDisappearView:view forIndex:index]; 173 | } 174 | } 175 | 176 | - (void)pagerViewWillBeginScrolling:(TYPagerView *)pageView animate:(BOOL)animate { 177 | if ([_delegate respondsToSelector:@selector(tabPagerViewWillBeginScrolling:animate:)]) { 178 | [_delegate tabPagerViewWillBeginScrolling:self animate:animate]; 179 | } 180 | } 181 | 182 | - (void)pagerViewDidEndScrolling:(TYPagerView *)pageView animate:(BOOL)animate { 183 | if ([_delegate respondsToSelector:@selector(tabPagerViewDidEndScrolling:animate:)]) { 184 | [_delegate tabPagerViewDidEndScrolling:self animate:animate]; 185 | } 186 | } 187 | 188 | - (void)layoutSubviews { 189 | [super layoutSubviews]; 190 | _tabBar.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), _tabBarHeight); 191 | _pageView.frame = CGRectMake(0, _tabBarHeight, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame) - _tabBarHeight); 192 | } 193 | 194 | @end 195 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TabPager/TYTabPagerController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TYTabPagerController.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 2017/7/18. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import "TYTabPagerController.h" 10 | 11 | @interface TYTabPagerController () 12 | 13 | // UI 14 | @property (nonatomic, strong) TYTabPagerBar *tabBar; 15 | @property (nonatomic, strong) TYPagerController *pagerController; 16 | 17 | // Data 18 | @property (nonatomic, strong) NSString *identifier; 19 | 20 | @end 21 | 22 | #define kTabBarOrignY -999999 23 | 24 | @implementation TYTabPagerController 25 | 26 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 27 | if (self = [super initWithCoder:aDecoder]) { 28 | _tabBarHeight = 36; 29 | _tabBarOrignY = kTabBarOrignY; 30 | } 31 | return self; 32 | } 33 | 34 | - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { 35 | if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { 36 | _tabBarHeight = 36; 37 | _tabBarOrignY = kTabBarOrignY; 38 | } 39 | return self; 40 | } 41 | 42 | - (void)viewDidLoad { 43 | [super viewDidLoad]; 44 | // Do any additional setup after loading the view. 45 | self.view.backgroundColor = [UIColor whiteColor]; 46 | 47 | [self addTabBar]; 48 | 49 | [self addPagerController]; 50 | } 51 | 52 | - (void)addTabBar { 53 | self.tabBar.dataSource = self; 54 | self.tabBar.delegate = self; 55 | [self registerClass:[TYTabPagerBarCell class] forTabBarCellWithReuseIdentifier:[TYTabPagerBarCell cellIdentifier]]; 56 | [self.view addSubview:self.tabBar];; 57 | } 58 | 59 | - (void)addPagerController { 60 | self.pagerController.dataSource = self; 61 | self.pagerController.delegate = self; 62 | [self addChildViewController:self.pagerController]; 63 | [self.view addSubview:self.pagerController.view]; 64 | } 65 | 66 | - (void)viewWillLayoutSubviews { 67 | [super viewWillLayoutSubviews]; 68 | CGFloat orignY = [self fixedTabBarOriginY]; 69 | self.tabBar.frame = CGRectMake(0, orignY, CGRectGetWidth(self.view.frame), _tabBarHeight); 70 | self.pagerController.view.frame = CGRectMake(0, orignY+_tabBarHeight, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame) - _tabBarHeight-orignY); 71 | } 72 | 73 | - (CGFloat)fixedTabBarOriginY { 74 | if (_tabBarOrignY > kTabBarOrignY) { 75 | return _tabBarOrignY; 76 | } 77 | if (!self.navigationController || self.parentViewController != self.navigationController) { 78 | return 0; 79 | } 80 | if (self.navigationController.navigationBarHidden || !(self.edgesForExtendedLayout&UIRectEdgeTop)) { 81 | return 0; 82 | } 83 | return CGRectGetMaxY(self.navigationController.navigationBar.frame); 84 | } 85 | 86 | #pragma mark - getter setter 87 | 88 | - (TYTabPagerBar *)tabBar { 89 | if (!_tabBar) { 90 | _tabBar = [[TYTabPagerBar alloc]init]; 91 | } 92 | return _tabBar; 93 | } 94 | 95 | - (void)setTabBarOrignY:(CGFloat)tabBarOrignY { 96 | BOOL isChangeValue = _tabBarOrignY != tabBarOrignY; 97 | _tabBarOrignY = tabBarOrignY; 98 | if (isChangeValue && _tabBar.superview) { 99 | [self.view layoutIfNeeded]; 100 | } 101 | } 102 | 103 | - (void)setTabBarHeight:(CGFloat)tabBarHeight { 104 | BOOL isChangeValue = _tabBarHeight != tabBarHeight; 105 | _tabBarHeight = tabBarHeight; 106 | if (isChangeValue && _tabBar.superview) { 107 | [self.view layoutIfNeeded]; 108 | } 109 | } 110 | 111 | - (TYPagerController *)pagerController { 112 | if (!_pagerController) { 113 | _pagerController = [[TYPagerController alloc]init]; 114 | } 115 | return _pagerController; 116 | } 117 | 118 | - (TYPagerViewLayout *)layout { 119 | return self.pagerController.layout; 120 | } 121 | 122 | #pragma mark - public 123 | 124 | - (void)updateData { 125 | [self.tabBar reloadData]; 126 | [self.pagerController updateData]; 127 | } 128 | 129 | - (void)reloadData { 130 | [self.tabBar reloadData]; 131 | [self.pagerController reloadData]; 132 | } 133 | 134 | - (void)scrollToControllerAtIndex:(NSInteger)index animate:(BOOL)animate { 135 | [self.pagerController scrollToControllerAtIndex:index animate:animate]; 136 | } 137 | 138 | - (void)registerClass:(Class)Class forTabBarCellWithReuseIdentifier:(NSString *)identifier { 139 | _identifier = identifier; 140 | [self.tabBar registerClass:Class forCellWithReuseIdentifier:identifier]; 141 | } 142 | - (void)registerNib:(UINib *)nib forTabBarCellWithReuseIdentifier:(NSString *)identifier { 143 | _identifier = identifier; 144 | [self.tabBar registerNib:nib forCellWithReuseIdentifier:identifier]; 145 | } 146 | 147 | - (void)registerClass:(Class)Class forPagerCellWithReuseIdentifier:(NSString *)identifier { 148 | [_pagerController registerClass:Class forControllerWithReuseIdentifier:identifier]; 149 | } 150 | - (void)registerNib:(UINib *)nib forPagerCellWithReuseIdentifier:(NSString *)identifier { 151 | [_pagerController registerNib:nib forControllerWithReuseIdentifier:identifier]; 152 | } 153 | - (UIViewController *)dequeueReusablePagerCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index { 154 | return [_pagerController dequeueReusableControllerWithReuseIdentifier:identifier forIndex:index]; 155 | } 156 | 157 | #pragma mark - TYTabPagerBarDataSource 158 | 159 | - (NSInteger)numberOfItemsInPagerTabBar { 160 | return [_dataSource numberOfControllersInTabPagerController]; 161 | } 162 | 163 | - (UICollectionViewCell *)pagerTabBar:(TYTabPagerBar *)pagerTabBar cellForItemAtIndex:(NSInteger)index { 164 | UICollectionViewCell *cell = [pagerTabBar dequeueReusableCellWithReuseIdentifier:_identifier forIndex:index]; 165 | cell.titleLabel.text = [_dataSource tabPagerController:self titleForIndex:index]; 166 | if ([_delegate respondsToSelector:@selector(tabPagerController:willDisplayCell:atIndex:)]) { 167 | [_delegate tabPagerController:self willDisplayCell:cell atIndex:index]; 168 | } 169 | return cell; 170 | } 171 | 172 | #pragma mark - TYTabPagerBarDelegate 173 | 174 | - (CGFloat)pagerTabBar:(TYTabPagerBar *)pagerTabBar widthForItemAtIndex:(NSInteger)index { 175 | NSString *title = [_dataSource tabPagerController:self titleForIndex:index]; 176 | return [pagerTabBar cellWidthForTitle:title]; 177 | } 178 | 179 | - (void)pagerTabBar:(TYTabPagerBar *)pagerTabBar didSelectItemAtIndex:(NSInteger)index { 180 | [_pagerController scrollToControllerAtIndex:index animate:YES]; 181 | if ([_delegate respondsToSelector:@selector(tabPagerController:didSelectTabBarItemAtIndex:)]) { 182 | [_delegate tabPagerController:self didSelectTabBarItemAtIndex:index]; 183 | } 184 | } 185 | 186 | #pragma mark - TYPagerControllerDataSource 187 | 188 | - (NSInteger)numberOfControllersInPagerController { 189 | return [_dataSource numberOfControllersInTabPagerController]; 190 | } 191 | 192 | - (UIViewController *)pagerController:(TYPagerController *)pagerController controllerForIndex:(NSInteger)index prefetching:(BOOL)prefetching { 193 | UIViewController *viewController = [_dataSource tabPagerController:self controllerForIndex:index prefetching:prefetching]; 194 | return viewController; 195 | } 196 | 197 | #pragma mark - TYPagerControllerDelegate 198 | 199 | - (void)pagerController:(TYPagerController *)pagerController transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated { 200 | [self.tabBar scrollToItemFromIndex:fromIndex toIndex:toIndex animate:animated]; 201 | } 202 | 203 | -(void)pagerController:(TYPagerController *)pagerController transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress { 204 | [self.tabBar scrollToItemFromIndex:fromIndex toIndex:toIndex progress:progress]; 205 | } 206 | 207 | - (void)pagerControllerWillBeginScrolling:(TYPagerController *)pagerController animate:(BOOL)animate { 208 | if ([_delegate respondsToSelector:@selector(tabPagerControllerWillBeginScrolling:animate:)]) { 209 | [_delegate tabPagerControllerWillBeginScrolling:self animate:animate]; 210 | } 211 | } 212 | - (void)pagerControllerDidEndScrolling:(TYPagerController *)pagerController animate:(BOOL)animate { 213 | if ([_delegate respondsToSelector:@selector(tabPagerControllerDidEndScrolling:animate:)]) { 214 | [_delegate tabPagerControllerDidEndScrolling:self animate:animate]; 215 | } 216 | } 217 | 218 | - (void)didReceiveMemoryWarning { 219 | [super didReceiveMemoryWarning]; 220 | // Dispose of any resources that can be recreated. 221 | } 222 | 223 | @end 224 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TYPagerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TYPagerView.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/5. 6 | // Copyright © 2017年 tanyang. All rights reserved. 7 | // 8 | 9 | #import "TYPagerView.h" 10 | 11 | @interface TYPagerView () { 12 | // private 13 | struct { 14 | unsigned int willAppearViewForIndex :1; 15 | unsigned int didAppearViewForIndex :1; 16 | unsigned int willDisappearViewForIndex :1; 17 | unsigned int didDisappearViewForIndex :1; 18 | unsigned int transitionFromIndexToIndex :1; 19 | unsigned int transitionFromIndexToIndexProgress :1; 20 | unsigned int viewDidScroll: 1; 21 | unsigned int viewWillBeginScrolling: 1; 22 | unsigned int viewDidEndScrolling: 1; 23 | }_delegateFlags; 24 | } 25 | 26 | // Data 27 | @property (nonatomic, strong) TYPagerViewLayout *layout; 28 | 29 | @end 30 | 31 | @implementation TYPagerView 32 | 33 | #pragma mark - life cycle 34 | 35 | - (instancetype)initWithFrame:(CGRect)frame { 36 | if (self = [super initWithFrame:frame]) { 37 | self.backgroundColor = [UIColor clearColor]; 38 | // prevent sysytem automaticallyAdjustsScrollViewInsets 39 | [self addFixAutoAdjustInsetScrollView]; 40 | [self addLayoutScrollView]; 41 | } 42 | return self; 43 | } 44 | 45 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 46 | if (self = [super initWithCoder:aDecoder]) { 47 | self.backgroundColor = [UIColor clearColor]; 48 | // prevent sysytem automaticallyAdjustsScrollViewInsets 49 | [self addFixAutoAdjustInsetScrollView]; 50 | [self addLayoutScrollView]; 51 | } 52 | return self; 53 | } 54 | 55 | - (void)addFixAutoAdjustInsetScrollView { 56 | UIView *view = [[UIView alloc]init]; 57 | [self addSubview:view]; 58 | } 59 | 60 | - (void)addLayoutScrollView { 61 | UIScrollView *contentView = [[UIScrollView alloc]init]; 62 | TYPagerViewLayout *layout = [[TYPagerViewLayout alloc]initWithScrollView:contentView]; 63 | layout.dataSource = self; 64 | layout.delegate = self; 65 | [self addSubview:contentView]; 66 | _layout = layout; 67 | _layout.scrollView.frame = self.bounds; 68 | } 69 | 70 | #pragma mark - getter && setter 71 | 72 | - (NSInteger)curIndex { 73 | return _layout.curIndex; 74 | } 75 | 76 | - (NSInteger)countOfPagerViews { 77 | return _layout.countOfPagerItems; 78 | } 79 | 80 | - (NSArray *)visibleViews { 81 | return _layout.visibleItems; 82 | } 83 | 84 | - (UIScrollView *)scrollView { 85 | return _layout.scrollView; 86 | } 87 | 88 | - (void)setContentInset:(UIEdgeInsets)contentInset { 89 | _contentInset = contentInset; 90 | [self setNeedsLayout]; 91 | } 92 | 93 | - (void)setDelegate:(id)delegate { 94 | _delegate = delegate; 95 | 96 | _delegateFlags.willAppearViewForIndex = [delegate respondsToSelector:@selector(pagerView:willAppearView:forIndex:)]; 97 | _delegateFlags.didAppearViewForIndex = [delegate respondsToSelector:@selector(pagerView:didAppearView:forIndex:)]; 98 | _delegateFlags.willDisappearViewForIndex = [delegate respondsToSelector:@selector(pagerView:willDisappearView:forIndex:)]; 99 | _delegateFlags.didDisappearViewForIndex = [delegate respondsToSelector:@selector(pagerView:didDisappearView:forIndex:)]; 100 | 101 | _delegateFlags.transitionFromIndexToIndex = [delegate respondsToSelector:@selector(pagerView:transitionFromIndex:toIndex:animated:)]; 102 | _delegateFlags.transitionFromIndexToIndexProgress = [delegate respondsToSelector:@selector(pagerView:transitionFromIndex:toIndex:progress:)]; 103 | 104 | _delegateFlags.viewDidScroll = [delegate respondsToSelector:@selector(pagerViewDidScroll:)]; 105 | _delegateFlags.viewWillBeginScrolling = [delegate respondsToSelector:@selector(pagerViewWillBeginScrolling:animate:)]; 106 | _delegateFlags.viewDidEndScrolling = [delegate respondsToSelector:@selector(pagerViewDidEndScrolling:animate:)]; 107 | } 108 | 109 | #pragma mark - public 110 | 111 | - (void)updateData { 112 | [_layout updateData]; 113 | } 114 | 115 | - (void)reloadData { 116 | [_layout reloadData]; 117 | } 118 | 119 | - (void)scrollToViewAtIndex:(NSInteger)index animate:(BOOL)animate { 120 | [_layout scrollToItemAtIndex:index animate:animate]; 121 | } 122 | 123 | - (UIView *)viewForIndex:(NSInteger)idx { 124 | return [_layout itemForIndex:idx]; 125 | } 126 | 127 | - (void)registerClass:(Class)Class forViewWithReuseIdentifier:(NSString *)identifier { 128 | [_layout registerClass:Class forItemWithReuseIdentifier:identifier]; 129 | } 130 | - (void)registerNib:(UINib *)nib forViewWithReuseIdentifier:(NSString *)identifier { 131 | [_layout registerNib:nib forItemWithReuseIdentifier:identifier]; 132 | } 133 | - (UIView *)dequeueReusableViewWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index { 134 | return [_layout dequeueReusableItemWithReuseIdentifier:identifier forIndex:index]; 135 | } 136 | 137 | #pragma mark - private 138 | 139 | - (void)willBeginScrollingAnimate:(BOOL)animate { 140 | if (_delegateFlags.viewWillBeginScrolling) { 141 | [_delegate pagerViewWillBeginScrolling:self animate:animate]; 142 | } 143 | } 144 | 145 | - (void)didEndScrollingAnimate:(BOOL)animate { 146 | if (_delegateFlags.viewDidEndScrolling) { 147 | [_delegate pagerViewDidEndScrolling:self animate:animate]; 148 | } 149 | } 150 | 151 | #pragma mark - TYPagerViewLayoutDataSource 152 | 153 | - (NSInteger)numberOfItemsInPagerViewLayout { 154 | return [_dataSource numberOfViewsInPagerView]; 155 | } 156 | 157 | - (id)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout itemForIndex:(NSInteger)index prefetching:(BOOL)prefetching { 158 | return [_dataSource pagerView:self viewForIndex:index prefetching:prefetching]; 159 | } 160 | 161 | - (UIView *)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout viewForItem:(id)item atIndex:(NSInteger)index { 162 | return item; 163 | } 164 | 165 | - (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout addVisibleItem:(id)item atIndex:(NSInteger)index { 166 | UIView *visibleView = item; 167 | if (_delegateFlags.willAppearViewForIndex) { 168 | [_delegate pagerView:self willAppearView:visibleView forIndex:index]; 169 | } 170 | [pagerViewLayout.scrollView addSubview:visibleView]; 171 | if (_delegateFlags.didAppearViewForIndex) { 172 | [_delegate pagerView:self didAppearView:visibleView forIndex:index]; 173 | } 174 | } 175 | 176 | - (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout removeInVisibleItem:(id)item atIndex:(NSInteger)index { 177 | UIView *invisibleView = item; 178 | if (_delegateFlags.willDisappearViewForIndex) { 179 | [_delegate pagerView:self willDisappearView:invisibleView forIndex:index]; 180 | } 181 | [invisibleView removeFromSuperview]; 182 | if (_delegateFlags.didDisappearViewForIndex) { 183 | [_delegate pagerView:self didDisappearView:invisibleView forIndex:index]; 184 | } 185 | } 186 | 187 | #pragma mark - TYPagerViewLayoutDelegate 188 | 189 | - (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated { 190 | if (_delegateFlags.transitionFromIndexToIndex) { 191 | [_delegate pagerView:self transitionFromIndex:fromIndex toIndex:toIndex animated:animated]; 192 | } 193 | } 194 | 195 | - (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress { 196 | if (_delegateFlags.transitionFromIndexToIndexProgress) { 197 | [_delegate pagerView:self transitionFromIndex:fromIndex toIndex:toIndex progress:progress]; 198 | } 199 | } 200 | 201 | - (void)pagerViewLayoutDidScroll:(TYPagerViewLayout *)pagerViewLayout { 202 | if (_delegateFlags.viewDidScroll) { 203 | [_delegate pagerViewDidScroll:self]; 204 | } 205 | } 206 | 207 | - (void)pagerViewLayoutWillBeginDragging:(TYPagerViewLayout *)pagerViewLayout { 208 | [self willBeginScrollingAnimate:YES]; 209 | } 210 | 211 | - (void)pagerViewLayoutWillBeginScrollToView:(TYPagerViewLayout *)pagerViewLayout animate:(BOOL)animate { 212 | [self willBeginScrollingAnimate:animate]; 213 | } 214 | 215 | - (void)pagerViewLayoutDidEndDecelerating:(TYPagerViewLayout *)pagerViewLayout { 216 | [self didEndScrollingAnimate:YES]; 217 | } 218 | 219 | - (void)pagerViewLayoutDidEndScrollToView:(TYPagerViewLayout *)pagerViewLayout animate:(BOOL)animate { 220 | [self didEndScrollingAnimate:animate]; 221 | } 222 | 223 | - (void)pagerViewLayoutDidEndScrollingAnimation:(TYPagerViewLayout *)pagerViewLayout { 224 | [self didEndScrollingAnimate:YES]; 225 | } 226 | 227 | #pragma mark - layoutSubviews 228 | 229 | - (void)layoutSubviews { 230 | [super layoutSubviews]; 231 | _layout.scrollView.frame = UIEdgeInsetsInsetRect(self.bounds,_contentInset); 232 | } 233 | 234 | - (void)dealloc { 235 | _layout = nil; 236 | } 237 | 238 | @end 239 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TYPagerController v2.0 2 | TYPagerController 简单,强大,高度定制,页面控制器,水平滚动内容和标题栏,包含多种barStyle。
3 | TYPagerController v2.0 重构优化代码,分离出TYPagerViewLayout布局类,添加更多功能,更加强大,稳定,已经在项目中使用
4 | 如果还想使用以前的版本可以查看分支v1.0.6 和 pod 'TYPagerController', '~> 1.0.6'
5 | 6 | * TYPagerViewLayout 水平滚动页面的layout类,只需要initWithScrollView:即可实现水平滚动页面. 7 | * TYPagerView 包含TYPagerViewLayout的水平滚动页面View 8 | * TYPagerController 包含TYPagerViewLayout的水平滚动页面Controller。 9 | * TYTabPagerBar Pager的标题 tabBar 10 | * TYTabPagerView 包含TabBar的TYPagerView 11 | * TYTabPagerController 包含TabBar的TYPagerController 12 | 13 | 注意:获取数据后必须调用reloadData.
14 | 更详细的使用请看[LovePlayNews](https://github.com/12207480/LovePlayNews)项目 15 | 16 | ## CocoaPods 17 | ``` 18 | pod 'TYPagerController' 19 | ``` 20 | 21 | ## Requirements 22 | * Xcode 7 or higher 23 | * iOS 7.0 or higher 24 | * ARC 25 | 26 | ## ScreenShot 27 | ### TYPagerBarStyle 28 | 29 | New TYPagerBarStyleProgressElasticView
30 | ![image](https://github.com/12207480/TYPagerController/blob/master/ScreenShot/TYPagerController6.gif) 31 | 32 | 1 TYPagerBarStyleProgressBounceView
33 | ![image](https://raw.githubusercontent.com/12207480/TYPagerController/master/ScreenShot/TYPagerController1.gif) 34 | 35 | 2 TYPagerBarStyleProgressView
36 | ![image](https://raw.githubusercontent.com/12207480/TYPagerController/master/ScreenShot/TYPagerController2.gif) 37 | 38 | 3 TYPagerBarStyleCoverView
39 | ![image](https://raw.githubusercontent.com/12207480/TYPagerController/master/ScreenShot/TYPagerController3.gif) 40 | ![image](https://raw.githubusercontent.com/12207480/TYPagerController/master/ScreenShot/TYPagerController7.gif) 41 | 42 | 4 TYPagerBarStyleNoneView
43 | ![image](https://raw.githubusercontent.com/12207480/TYPagerController/master/ScreenShot/TYPagerController4.gif) 44 | 45 | ## API 46 | 47 | ### Class 48 | * TYPagerViewLayout 49 | ```objc 50 | @interface TYPagerViewLayout<__covariant ItemType> : NSObject 51 | 52 | @property (nonatomic, weak, nullable) id dataSource; 53 | @property (nonatomic, weak, nullable) id delegate; 54 | 55 | // strong,will control the delegate,don't set delegate on other place. 56 | @property (nonatomic, strong, readonly) UIScrollView *scrollView; 57 | // if viewcontroller's automaticallyAdjustsScrollViewInsets YES ,will cause frame problems, you can set YES, default YES 58 | @property (nonatomic, assign) BOOL adjustScrollViewInset; 59 | 60 | @property (nonatomic, assign, readonly) NSInteger countOfPagerItems; 61 | @property (nonatomic, assign, readonly) NSInteger curIndex;// default -1 62 | 63 | @property (nonatomic, strong, readonly) NSCache *memoryCache;; // will cache pagerView,you can set countLimit 64 | @property (nonatomic, assign) BOOL autoMemoryCache; // default YES 65 | 66 | @property (nonatomic, assign) NSInteger prefetchItemCount;// preload left and right item's count , default 0 67 | 68 | @property (nonatomic, assign, readonly) NSRange prefetchRange; 69 | @property (nonatomic, assign, readonly) NSRange visibleRange; 70 | 71 | @property (nonatomic, strong, nullable, readonly) NSArray * visibleIndexs; 72 | @property (nonatomic, strong, nullable, readonly) NSArray * visibleItems; 73 | 74 | // default YES, if NO,will not call delegate transitionFromIndex:toIndex:progress:,but will call transitionFromIndex:toIndex: 75 | @property (nonatomic, assign) BOOL progressAnimateEnabel; 76 | 77 | // default NO, when scroll visible range change will add item.If YES add item only when scroll animate end, suggest set prefetchItemCount 1 or more 78 | @property (nonatomic, assign) BOOL addVisibleItemOnlyWhenScrollAnimatedEnd; 79 | 80 | // default 0.5,when scroll progress percent will change index, only progressAnimateEnabel is NO or don't implement delegate transitionFromIndex: toIndex: progress: 81 | @property (nonatomic, assign) CGFloat changeIndexWhenScrollProgress; 82 | ``` 83 | * TYPagerView 84 | ```objc 85 | @interface TYPagerView : UIView 86 | 87 | @property (nonatomic, weak, nullable) id dataSource; 88 | @property (nonatomic, weak, nullable) id delegate; 89 | // pagerView's layout,don't set layout's dataSource to other 90 | @property (nonatomic, strong, readonly) TYPagerViewLayout *layout; 91 | @property (nonatomic, strong, readonly) UIScrollView *scrollView; 92 | 93 | @property (nonatomic, assign, readonly) NSInteger countOfPagerViews; 94 | @property (nonatomic, assign, readonly) NSInteger curIndex;// default -1 95 | 96 | @property (nonatomic, assign, nullable, readonly) NSArray *visibleViews; 97 | 98 | @property (nonatomic, assign) UIEdgeInsets contentInset; 99 | 100 | //if not visible, prefecth, cache view at index, return nil 101 | - (UIView *_Nullable)viewForIndex:(NSInteger)index; 102 | 103 | // register && dequeue's usage like tableView 104 | - (void)registerClass:(Class)Class forViewWithReuseIdentifier:(NSString *)identifier; 105 | - (void)registerNib:(UINib *)nib forViewWithReuseIdentifier:(NSString *)identifier; 106 | - (UIView *)dequeueReusableViewWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index; 107 | 108 | // scroll to index 109 | - (void)scrollToViewAtIndex:(NSInteger)index animate:(BOOL)animate; 110 | 111 | // update data and layout,but don't reset propertys(curIndex,visibleDatas,prefechDatas) 112 | - (void)updateData; 113 | 114 | // reload data and reset propertys 115 | - (void)reloadData; 116 | ``` 117 | ```objc 118 | @protocol TYTabPagerControllerDelegate 119 | 120 | // configre collectionview cell 121 | - (void)pagerController:(TYTabPagerController *)pagerController configreCell:(UICollectionViewCell *)cell forItemTitle:(NSString *)title atIndexPath:(NSIndexPath *)indexPath; 122 | 123 | // transition frome cell to cell with animated 124 | - (void)pagerController:(TYTabPagerController *)pagerController transitionFromeCell:(UICollectionViewCell *)fromCell toCell:(UICollectionViewCell *)toCell animated:(BOOL)animated; 125 | 126 | // transition frome cell to cell with progress 127 | - (void)pagerController:(TYTabPagerController *)pagerController transitionFromeCell:(UICollectionViewCell *)fromCell toCell:(UICollectionViewCell *)toCell progress:(CGFloat)progress; 128 | 129 | @end 130 | ``` 131 | * TYPagerController 132 | ```objc 133 | @interface TYPagerController : UIViewController 134 | 135 | @property (nonatomic, weak, nullable) id dataSource; 136 | @property (nonatomic, weak, nullable) id delegate; 137 | // pagerController's layout,don't set layout's dataSource to other 138 | @property (nonatomic, strong, readonly) TYPagerViewLayout *layout; 139 | @property (nonatomic, weak, readonly) UIScrollView *scrollView; 140 | 141 | @property (nonatomic, assign, readonly) NSInteger countOfControllers; 142 | @property (nonatomic, assign, readonly) NSInteger curIndex;// default -1 143 | 144 | @property (nonatomic, strong, nullable, readonly) NSArray *visibleControllers; 145 | 146 | @property (nonatomic, assign) UIEdgeInsets contentInset; 147 | 148 | //if not visible, prefecth, cache view at index, return nil 149 | - (UIViewController *_Nullable)controllerForIndex:(NSInteger)index; 150 | 151 | // register && dequeue's usage like tableView 152 | - (void)registerClass:(Class)Class forControllerWithReuseIdentifier:(NSString *)identifier; 153 | - (void)registerNib:(UINib *)nib forControllerWithReuseIdentifier:(NSString *)identifier; 154 | - (UIViewController *)dequeueReusableControllerWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index; 155 | 156 | // scroll to index 157 | - (void)scrollToControllerAtIndex:(NSInteger)index animate:(BOOL)animate; 158 | 159 | // update data and layout,but don't reset propertys(curIndex,visibleDatas,prefechDatas) 160 | - (void)updateData; 161 | 162 | // reload data and reset propertys 163 | - (void)reloadData; 164 | ``` 165 | 166 | ##Usage Demo 167 | * TYTabPagerView 168 | ```objc 169 | - (void)addTabPagerView { 170 | TYTabPagerView *pagerView = [[TYTabPagerView alloc]init]; 171 | pagerView.tabBar.layout.barStyle = TYPagerBarStyleCoverView; 172 | pagerView.tabBar.progressView.backgroundColor = [UIColor lightGrayColor]; 173 | pagerView.dataSource = self; 174 | pagerView.delegate = self; 175 | [self.view addSubview:pagerView]; 176 | _pagerView = pagerView; 177 | } 178 | 179 | #pragma mark - TYTabPagerViewDataSource 180 | 181 | - (NSInteger)numberOfViewsInTabPagerView { 182 | return _datas.count; 183 | } 184 | 185 | - (UIView *)tabPagerView:(TYTabPagerView *)tabPagerView viewForIndex:(NSInteger)index prefetching:(BOOL)prefetching { 186 | UIView *view = [[UIView alloc]initWithFrame:[tabPagerView.layout frameForItemAtIndex:index]]; 187 | view.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:arc4random()%255/255.0]; 188 | //NSLog(@"viewForIndex:%ld prefetching:%d",index,prefetching); 189 | return view; 190 | } 191 | 192 | - (NSString *)tabPagerView:(TYTabPagerView *)tabPagerView titleForIndex:(NSInteger)index { 193 | NSString *title = _datas[index]; 194 | return title; 195 | } 196 | ``` 197 | 198 | * TYTabPagerController 199 | ```objc 200 | @interface TabPagerControllerDemoController : TYTabPagerController 201 | 202 | - (void)viewDidLoad { 203 | [super viewDidLoad]; 204 | // Do any additional setup after loading the view. 205 | self.title = @"TabPagerControllerDemoController"; 206 | self.tabBar.layout.barStyle = TYPagerBarStyleProgressView; 207 | self.dataSource = self; 208 | self.delegate = self; 209 | 210 | [self loadData]; 211 | } 212 | 213 | - (void)loadData { 214 | _datas = [datas copy]; 215 | // must call reloadData 216 | [self reloadData]; 217 | } 218 | 219 | #pragma mark - TYTabPagerControllerDataSource 220 | 221 | - (NSInteger)numberOfControllersInTabPagerController { 222 | return _datas.count; 223 | } 224 | 225 | - (UIViewController *)tabPagerController:(TYTabPagerController *)tabPagerController controllerForIndex:(NSInteger)index prefetching:(BOOL)prefetching { 226 | if (index%3 == 0) { 227 | CustomViewController *VC = [[CustomViewController alloc]init]; 228 | VC.text = [@(index) stringValue]; 229 | return VC; 230 | }else if (index%3 == 1) { 231 | ListViewController *VC = [[ListViewController alloc]init]; 232 | VC.text = [@(index) stringValue]; 233 | return VC; 234 | }else { 235 | CollectionViewController *VC = [[CollectionViewController alloc]init]; 236 | VC.text = [@(index) stringValue]; 237 | return VC; 238 | } 239 | } 240 | 241 | - (NSString *)tabPagerController:(TYTabPagerController *)tabPagerController titleForIndex:(NSInteger)index { 242 | NSString *title = _datas[index]; 243 | return title; 244 | } 245 | ``` 246 | 247 | 248 | 更多的使用方法 请查看 demo。 249 | 250 | ### Contact 251 | 如果你发现bug,please pull reqeust me
252 | 如果你有更好的改进,please pull reqeust me
253 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TYPagerController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TYPagerController.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 16/4/13. 6 | // Copyright © 2016年 tanyang. All rights reserved. 7 | // 8 | 9 | #import "TYPagerController.h" 10 | 11 | @interface TYPagerController () { 12 | // private 13 | struct { 14 | unsigned int viewWillAppearForIndex :1; 15 | unsigned int viewDidAppearForIndex :1; 16 | unsigned int viewWillDisappearForIndex :1; 17 | unsigned int viewDidDisappearForIndex :1; 18 | 19 | unsigned int transitionFromIndexToIndex :1; 20 | unsigned int transitionFromIndexToIndexProgress :1; 21 | unsigned int viewDidScroll: 1; 22 | unsigned int viewWillBeginScrolling: 1; 23 | unsigned int viewDidEndScrolling: 1; 24 | }_delegateFlags; 25 | } 26 | 27 | // Data 28 | @property (nonatomic, strong) TYPagerViewLayout *layout; 29 | 30 | @end 31 | 32 | 33 | @implementation TYPagerController 34 | 35 | - (TYPagerViewLayout *)layout { 36 | if (!_layout) { 37 | UIScrollView *scrollView = [[UIScrollView alloc]init]; 38 | TYPagerViewLayout *layout = [[TYPagerViewLayout alloc]initWithScrollView:scrollView]; 39 | layout.dataSource = self; 40 | layout.delegate = self; 41 | layout.adjustScrollViewInset = YES; 42 | _layout = layout; 43 | } 44 | return _layout; 45 | } 46 | 47 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 48 | if (self = [super initWithCoder:aDecoder]) { 49 | _automaticallySystemManagerViewAppearanceMethods = YES; 50 | } 51 | return self; 52 | } 53 | 54 | - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { 55 | if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { 56 | _automaticallySystemManagerViewAppearanceMethods = YES; 57 | } 58 | return self; 59 | } 60 | 61 | #pragma mark - life cycle 62 | 63 | - (void)viewDidLoad { 64 | [super viewDidLoad]; 65 | // Do any additional setup after loading the view. 66 | self.view.backgroundColor = [UIColor whiteColor]; 67 | // prevent sysytem automaticallyAdjustsScrollViewInsets 68 | [self addFixAutoAdjustInsetScrollView]; 69 | [self.view addSubview:self.layout.scrollView]; 70 | } 71 | 72 | - (void)addFixAutoAdjustInsetScrollView { 73 | UIView *view = [[UIView alloc]init]; 74 | [self.view addSubview:view]; 75 | } 76 | 77 | - (void)viewWillAppear:(BOOL)animated { 78 | [super viewWillAppear:animated]; 79 | _layout.scrollView.frame = UIEdgeInsetsInsetRect(self.view.bounds,_contentInset); 80 | } 81 | 82 | - (void)viewWillLayoutSubviews 83 | { 84 | [super viewWillLayoutSubviews]; 85 | _layout.scrollView.frame = UIEdgeInsetsInsetRect(self.view.bounds,_contentInset); 86 | } 87 | 88 | #pragma mark - getter && setter 89 | 90 | - (void)setDelegate:(id)delegate 91 | { 92 | _delegate = delegate; 93 | 94 | _delegateFlags.viewWillAppearForIndex = [delegate respondsToSelector:@selector(pagerController:viewWillAppear:forIndex:)]; 95 | _delegateFlags.viewDidAppearForIndex = [delegate respondsToSelector:@selector(pagerController:viewDidAppear:forIndex:)]; 96 | _delegateFlags.viewWillDisappearForIndex = [delegate respondsToSelector:@selector(pagerController:viewWillDisappear:forIndex:)]; 97 | _delegateFlags.viewDidDisappearForIndex = [delegate respondsToSelector:@selector(pagerController:viewDidDisappear:forIndex:)]; 98 | 99 | _delegateFlags.transitionFromIndexToIndex = [delegate respondsToSelector:@selector(pagerController:transitionFromIndex:toIndex:animated:)]; 100 | _delegateFlags.transitionFromIndexToIndexProgress = [delegate respondsToSelector:@selector(pagerController:transitionFromIndex:toIndex:progress:)]; 101 | 102 | _delegateFlags.viewDidScroll = [delegate respondsToSelector:@selector(pagerControllerDidScroll:)]; 103 | _delegateFlags.viewWillBeginScrolling = [delegate respondsToSelector:@selector(pagerControllerWillBeginScrolling:animate:)]; 104 | _delegateFlags.viewDidEndScrolling = [delegate respondsToSelector:@selector(pagerControllerDidEndScrolling:animate:)]; 105 | } 106 | 107 | - (NSInteger)curIndex { 108 | return _layout.curIndex; 109 | } 110 | 111 | - (NSInteger)countOfControllers { 112 | return _layout.countOfPagerItems; 113 | } 114 | 115 | - (NSArray *)visibleControllers { 116 | return _layout.visibleItems; 117 | } 118 | 119 | - (UIScrollView *)scrollView { 120 | return _layout.scrollView; 121 | } 122 | 123 | - (void)setContentInset:(UIEdgeInsets)contentInset { 124 | _contentInset = contentInset; 125 | [self.view setNeedsLayout]; 126 | } 127 | 128 | - (BOOL)shouldAutomaticallyForwardAppearanceMethods { 129 | return _automaticallySystemManagerViewAppearanceMethods; 130 | } 131 | 132 | - (void)childViewController:(UIViewController *)childViewController BeginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated { 133 | if (!_automaticallySystemManagerViewAppearanceMethods) { 134 | [childViewController beginAppearanceTransition:isAppearing animated:animated]; 135 | } 136 | } 137 | 138 | - (void)childViewControllerEndAppearanceTransition:(UIViewController *)childViewController { 139 | if (!_automaticallySystemManagerViewAppearanceMethods) { 140 | [childViewController endAppearanceTransition]; 141 | } 142 | } 143 | 144 | #pragma mark - public method 145 | 146 | - (UIViewController *)controllerForIndex:(NSInteger)index { 147 | return [_layout itemForIndex:index]; 148 | } 149 | 150 | - (void)scrollToControllerAtIndex:(NSInteger)index animate:(BOOL)animate { 151 | [_layout scrollToItemAtIndex:index animate:animate]; 152 | } 153 | 154 | - (void)updateData { 155 | [_layout updateData]; 156 | } 157 | 158 | - (void)reloadData { 159 | [_layout reloadData]; 160 | } 161 | 162 | - (void)registerClass:(Class)Class forControllerWithReuseIdentifier:(NSString *)identifier { 163 | [_layout registerClass:Class forItemWithReuseIdentifier:identifier]; 164 | } 165 | - (void)registerNib:(UINib *)nib forControllerWithReuseIdentifier:(NSString *)identifier { 166 | [_layout registerNib:nib forItemWithReuseIdentifier:identifier]; 167 | } 168 | - (UIViewController *)dequeueReusableControllerWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index { 169 | return [_layout dequeueReusableItemWithReuseIdentifier:identifier forIndex:index]; 170 | } 171 | 172 | #pragma mark - private 173 | 174 | - (void)willBeginScrollingAnimate:(BOOL)animate { 175 | if (_delegateFlags.viewWillBeginScrolling) { 176 | [_delegate pagerControllerWillBeginScrolling:self animate:animate]; 177 | } 178 | } 179 | 180 | - (void)didEndScrollingAnimate:(BOOL)animate { 181 | if (_delegateFlags.viewDidEndScrolling) { 182 | [_delegate pagerControllerDidEndScrolling:self animate:animate]; 183 | } 184 | } 185 | 186 | #pragma mark - TYPagerViewLayoutDataSource 187 | 188 | - (NSInteger)numberOfItemsInPagerViewLayout { 189 | return [_dataSource numberOfControllersInPagerController]; 190 | } 191 | 192 | - (id)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout itemForIndex:(NSInteger)index prefetching:(BOOL)prefetching { 193 | return [_dataSource pagerController:self controllerForIndex:index prefetching:prefetching]; 194 | } 195 | - (UIView *)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout viewForItem:(id)item atIndex:(NSInteger)index { 196 | UIViewController *viewController = item; 197 | return viewController.view; 198 | } 199 | 200 | - (UIViewController *)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout viewControllerForItem:(id)item atIndex:(NSInteger)index { 201 | return item; 202 | } 203 | 204 | - (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout addVisibleItem:(id)item atIndex:(NSInteger)index { 205 | UIViewController *viewController = item; 206 | if (_delegateFlags.viewWillAppearForIndex) { 207 | [_delegate pagerController:self viewWillAppear:viewController forIndex:index]; 208 | } 209 | // addChildViewController 210 | [self addChildViewController:viewController]; 211 | [self childViewController:viewController BeginAppearanceTransition:YES animated:YES]; 212 | [pagerViewLayout.scrollView addSubview:viewController.view]; 213 | [self childViewControllerEndAppearanceTransition:viewController]; 214 | [viewController didMoveToParentViewController:self]; 215 | if (_delegateFlags.viewDidAppearForIndex) { 216 | [_delegate pagerController:self viewDidAppear:viewController forIndex:index]; 217 | } 218 | } 219 | 220 | - (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout removeInVisibleItem:(id)item atIndex:(NSInteger)index { 221 | UIViewController *viewController = item; 222 | if (_delegateFlags.viewWillDisappearForIndex) { 223 | [_delegate pagerController:self viewWillDisappear:viewController forIndex:index]; 224 | } 225 | // removeChildViewController 226 | [viewController willMoveToParentViewController:nil]; 227 | [self childViewController:viewController BeginAppearanceTransition:NO animated:YES]; 228 | [viewController.view removeFromSuperview]; 229 | [self childViewControllerEndAppearanceTransition:viewController]; 230 | [viewController removeFromParentViewController]; 231 | if (_delegateFlags.viewDidDisappearForIndex) { 232 | [_delegate pagerController:self viewDidDisappear:viewController forIndex:index]; 233 | } 234 | } 235 | 236 | #pragma mark - TYPagerViewLayoutDelegate 237 | 238 | - (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated { 239 | if (_delegateFlags.transitionFromIndexToIndex) { 240 | [_delegate pagerController:self transitionFromIndex:fromIndex toIndex:toIndex animated:animated]; 241 | } 242 | } 243 | 244 | - (void)pagerViewLayout:(TYPagerViewLayout *)pagerViewLayout transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress { 245 | if (_delegateFlags.transitionFromIndexToIndexProgress) { 246 | [_delegate pagerController:self transitionFromIndex:fromIndex toIndex:toIndex progress:progress]; 247 | } 248 | } 249 | 250 | - (void)pagerViewLayoutDidScroll:(TYPagerViewLayout *)pagerViewLayout { 251 | if (_delegateFlags.viewDidScroll) { 252 | [_delegate pagerControllerDidScroll:self]; 253 | } 254 | } 255 | 256 | - (void)pagerViewLayoutWillBeginDragging:(TYPagerViewLayout *)pagerViewLayout { 257 | [self willBeginScrollingAnimate:YES]; 258 | } 259 | 260 | - (void)pagerViewLayoutWillBeginScrollToView:(TYPagerViewLayout *)pagerViewLayout animate:(BOOL)animate { 261 | [self willBeginScrollingAnimate:animate]; 262 | } 263 | 264 | - (void)pagerViewLayoutDidEndDecelerating:(TYPagerViewLayout *)pagerViewLayout { 265 | [self didEndScrollingAnimate:YES]; 266 | } 267 | 268 | - (void)pagerViewLayoutDidEndScrollToView:(TYPagerViewLayout *)pagerViewLayout animate:(BOOL)animate { 269 | [self didEndScrollingAnimate:animate]; 270 | } 271 | 272 | - (void)pagerViewLayoutDidEndScrollingAnimation:(TYPagerViewLayout *)pagerViewLayout { 273 | [self didEndScrollingAnimate:YES]; 274 | } 275 | 276 | - (void)dealloc 277 | { 278 | _layout = nil; 279 | } 280 | 281 | @end 282 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TabPager/TYTabPagerBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // TYTabPagerBar.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tany on 2017/7/13. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import "TYTabPagerBar.h" 10 | 11 | @interface TYTabPagerBar () { 12 | struct { 13 | unsigned int transitionFromeCellAnimated :1; 14 | unsigned int transitionFromeCellProgress :1; 15 | unsigned int widthForItemAtIndex :1; 16 | }_delegateFlags; 17 | TYTabPagerBarLayout *_layout; 18 | } 19 | 20 | // UI 21 | @property (nonatomic, weak) UICollectionView *collectionView; 22 | 23 | // Data 24 | 25 | @property (nonatomic, assign) NSInteger countOfItems; 26 | 27 | @property (nonatomic, assign) NSInteger curIndex; 28 | 29 | @property (nonatomic, assign) BOOL isFirstLayout; 30 | @property (nonatomic, assign) BOOL didLayoutSubViews; 31 | 32 | @end 33 | 34 | @implementation TYTabPagerBar 35 | 36 | - (instancetype)initWithFrame:(CGRect)frame { 37 | if (self = [super initWithFrame:frame]) { 38 | _isFirstLayout = YES; 39 | _didLayoutSubViews = NO; 40 | _autoScrollItemToCenter = YES; 41 | self.backgroundColor = [UIColor clearColor]; 42 | [self addFixAutoAdjustInsetScrollView]; 43 | [self addCollectionView]; 44 | [self addUnderLineView]; 45 | } 46 | return self; 47 | } 48 | 49 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 50 | if (self = [super initWithCoder:aDecoder]) { 51 | _isFirstLayout = YES; 52 | _didLayoutSubViews = NO; 53 | _autoScrollItemToCenter = YES; 54 | self.backgroundColor = [UIColor clearColor]; 55 | [self addFixAutoAdjustInsetScrollView]; 56 | [self addCollectionView]; 57 | [self addUnderLineView]; 58 | } 59 | return self; 60 | } 61 | 62 | - (void)addFixAutoAdjustInsetScrollView { 63 | UIView *view = [[UIView alloc]init]; 64 | [self addSubview:view]; 65 | } 66 | 67 | - (void)addCollectionView { 68 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init]; 69 | layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; 70 | UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:UIEdgeInsetsInsetRect(self.bounds, _contentInset) collectionViewLayout:layout]; 71 | collectionView.backgroundColor = [UIColor clearColor]; 72 | collectionView.showsHorizontalScrollIndicator = NO; 73 | collectionView.showsVerticalScrollIndicator = NO; 74 | if ([collectionView respondsToSelector:@selector(setPrefetchingEnabled:)]) { 75 | collectionView.prefetchingEnabled = NO; 76 | } 77 | collectionView.delegate = self; 78 | collectionView.dataSource = self; 79 | [self addSubview:collectionView]; 80 | _collectionView = collectionView; 81 | } 82 | 83 | - (void)addUnderLineView { 84 | UIView *progressView = [[UIView alloc]init]; 85 | progressView.backgroundColor = [UIColor redColor]; 86 | [_collectionView addSubview:progressView]; 87 | _progressView = progressView; 88 | } 89 | 90 | #pragma mark - getter setter 91 | 92 | - (void)setProgressView:(UIView *)progressView { 93 | if (_progressView == progressView) { 94 | return; 95 | } 96 | if (_progressView) { 97 | [_progressView removeFromSuperview]; 98 | } 99 | if (_layout && _layout.barStyle == TYPagerBarStyleCoverView) { 100 | progressView.layer.zPosition = -1; 101 | [_collectionView insertSubview: progressView atIndex:0]; 102 | }else { 103 | [_collectionView addSubview:progressView]; 104 | } 105 | if (_layout && self.superview) { 106 | [_layout layoutSubViews]; 107 | } 108 | } 109 | 110 | - (void)setBackgroundView:(UIView *)backgroundView { 111 | if (_backgroundView) { 112 | [_backgroundView removeFromSuperview]; 113 | } 114 | _backgroundView = backgroundView; 115 | backgroundView.frame = self.bounds; 116 | [self insertSubview:backgroundView atIndex:0]; 117 | } 118 | 119 | - (void)setDelegate:(id)delegate { 120 | _delegate = delegate; 121 | _delegateFlags.transitionFromeCellAnimated = [delegate respondsToSelector:@selector(pagerTabBar:transitionFromeCell:toCell:animated:)]; 122 | _delegateFlags.transitionFromeCellProgress = [delegate respondsToSelector:@selector(pagerTabBar:transitionFromeCell:toCell:progress:)]; 123 | _delegateFlags.widthForItemAtIndex = [delegate respondsToSelector:@selector(pagerTabBar:widthForItemAtIndex:)]; 124 | } 125 | 126 | - (void)setLayout:(TYTabPagerBarLayout *)layout { 127 | BOOL updateLayout = _layout && _layout != layout; 128 | _layout = layout; 129 | if (updateLayout) { 130 | [self reloadData]; 131 | } 132 | } 133 | 134 | - (TYTabPagerBarLayout *)layout { 135 | if (!_layout) { 136 | _layout = [[TYTabPagerBarLayout alloc]initWithPagerTabBar:self]; 137 | } 138 | return _layout; 139 | } 140 | 141 | #pragma mark - public 142 | 143 | - (void)reloadData { 144 | _countOfItems = [_dataSource numberOfItemsInPagerTabBar]; 145 | if (_curIndex >= _countOfItems) { 146 | _curIndex = _countOfItems - 1; 147 | } 148 | if ([_delegate respondsToSelector:@selector(pagerTabBar:configureLayout:)]) { 149 | [_delegate pagerTabBar:self configureLayout:self.layout]; 150 | } 151 | [self.layout layoutIfNeed]; 152 | [_collectionView reloadData]; 153 | [self.layout adjustContentCellsCenterInBar]; 154 | [self.layout layoutSubViews]; 155 | } 156 | 157 | - (void)registerClass:(Class)Class forCellWithReuseIdentifier:(NSString *)identifier { 158 | [_collectionView registerClass:Class forCellWithReuseIdentifier:identifier]; 159 | } 160 | 161 | - (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier { 162 | [_collectionView registerNib:nib forCellWithReuseIdentifier:identifier]; 163 | } 164 | 165 | - (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndex:(NSInteger)index { 166 | UICollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; 167 | return cell; 168 | } 169 | 170 | - (CGRect)cellFrameWithIndex:(NSInteger)index 171 | { 172 | if (index < 0) { 173 | return CGRectZero; 174 | } 175 | if (index >= _countOfItems) { 176 | return CGRectZero; 177 | } 178 | UICollectionViewLayoutAttributes * cellAttrs = [_collectionView layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; 179 | if (!cellAttrs) { 180 | return CGRectZero; 181 | } 182 | return cellAttrs.frame; 183 | } 184 | 185 | - (UICollectionViewCell *)cellForIndex:(NSInteger)index 186 | { 187 | if (index >= _countOfItems) { 188 | return nil; 189 | } 190 | return (UICollectionViewCell *)[_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; 191 | } 192 | 193 | - (void)scrollToItemFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animate:(BOOL)animate { 194 | if (toIndex < _countOfItems && toIndex >= 0 && fromIndex < _countOfItems && fromIndex >= 0) { 195 | _curIndex = toIndex; 196 | [self transitionFromIndex:fromIndex toIndex:toIndex animated:animate]; 197 | if (_autoScrollItemToCenter) { 198 | if (!_didLayoutSubViews) { 199 | dispatch_async(dispatch_get_main_queue(), ^{ 200 | [self scrollToItemAtIndex:toIndex atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:animate]; 201 | }); 202 | }else { 203 | [self scrollToItemAtIndex:toIndex atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:animate]; 204 | } 205 | } 206 | } 207 | } 208 | 209 | - (void)scrollToItemFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress { 210 | if (toIndex < _countOfItems && toIndex >= 0 && fromIndex < _countOfItems && fromIndex >= 0) { 211 | [self transitionFromIndex:fromIndex toIndex:toIndex progress:progress]; 212 | } 213 | } 214 | 215 | - (void)scrollToItemAtIndex:(NSInteger)index atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated { 216 | [_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0] atScrollPosition:scrollPosition animated:animated]; 217 | } 218 | 219 | - (CGFloat)cellWidthForTitle:(NSString *)title { 220 | if (!title) { 221 | return CGSizeZero.width; 222 | } 223 | //iOS 7 224 | CGRect frame = [title boundingRectWithSize:CGSizeMake(1000, 1000) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{ NSFontAttributeName:self.layout.selectedTextFont} context:nil]; 225 | return CGSizeMake(ceil(frame.size.width), ceil(frame.size.height) + 1).width; 226 | } 227 | 228 | #pragma mark - UICollectionViewDataSource 229 | 230 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 231 | { 232 | _countOfItems = [_dataSource numberOfItemsInPagerTabBar]; 233 | return _countOfItems; 234 | } 235 | 236 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 237 | { 238 | UICollectionViewCell *cell = [_dataSource pagerTabBar:self cellForItemAtIndex:indexPath.item]; 239 | [self.layout transitionFromCell:(indexPath.item == _curIndex ? nil : cell) toCell:(indexPath.item == _curIndex ? cell : nil) animate:NO]; 240 | return cell; 241 | } 242 | 243 | #pragma mark - UICollectionViewDelegateFlowLayout 244 | 245 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath 246 | { 247 | if ([_delegate respondsToSelector:@selector(pagerTabBar:didSelectItemAtIndex:)]) { 248 | [_delegate pagerTabBar:self didSelectItemAtIndex:indexPath.item]; 249 | } 250 | } 251 | 252 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 253 | { 254 | if (self.layout.cellWidth > 0) { 255 | return CGSizeMake(self.layout.cellWidth+self.layout.cellEdging*2, CGRectGetHeight(_collectionView.frame)); 256 | }else if(_delegateFlags.widthForItemAtIndex){ 257 | CGFloat width = [_delegate pagerTabBar:self widthForItemAtIndex:indexPath.item]+self.layout.cellEdging*2; 258 | return CGSizeMake(width, CGRectGetHeight(_collectionView.frame)); 259 | }else { 260 | NSAssert(NO, @"you must return cell width!"); 261 | } 262 | return CGSizeZero; 263 | } 264 | 265 | #pragma mark - transition cell 266 | 267 | - (void)transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex animated:(BOOL)animated 268 | { 269 | UICollectionViewCell *fromCell = [self cellForIndex:fromIndex]; 270 | UICollectionViewCell *toCell = [self cellForIndex:toIndex]; 271 | if (_delegateFlags.transitionFromeCellAnimated) { 272 | [_delegate pagerTabBar:self transitionFromeCell:fromCell toCell:toCell animated:animated]; 273 | }else { 274 | [self.layout transitionFromCell:fromCell toCell:toCell animate:animated]; 275 | } 276 | [self.layout setUnderLineFrameWithIndex:toIndex animated:fromCell && animated ? animated: NO]; 277 | } 278 | 279 | - (void)transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress 280 | { 281 | UICollectionViewCell *fromCell = [self cellForIndex:fromIndex]; 282 | UICollectionViewCell *toCell = [self cellForIndex:toIndex]; 283 | if (_delegateFlags.transitionFromeCellProgress) { 284 | [_delegate pagerTabBar:self transitionFromeCell:fromCell toCell:toCell progress:progress]; 285 | }else { 286 | [self.layout transitionFromCell:fromCell toCell:toCell progress:progress]; 287 | } 288 | [self.layout setUnderLineFrameWithfromIndex:fromIndex toIndex:toIndex progress:progress]; 289 | } 290 | 291 | -(void)layoutSubviews { 292 | [super layoutSubviews]; 293 | _backgroundView.frame = self.bounds; 294 | CGRect frame = UIEdgeInsetsInsetRect(self.bounds, _contentInset); 295 | BOOL needUpdateLayout = (frame.size.height > 0 && _collectionView.frame.size.height != frame.size.height) || (frame.size.width > 0 && _collectionView.frame.size.width != frame.size.width); 296 | _collectionView.frame = frame; 297 | if (!_didLayoutSubViews && !CGRectIsEmpty(_collectionView.frame)) { 298 | _didLayoutSubViews = YES; 299 | } 300 | if (needUpdateLayout) { 301 | [_layout invalidateLayout]; 302 | } 303 | if (frame.size.height > 0 && frame.size.width > 0) { 304 | [_layout adjustContentCellsCenterInBar]; 305 | } 306 | _isFirstLayout = NO; 307 | [_layout layoutSubViews]; 308 | } 309 | 310 | - (void)dealloc { 311 | _collectionView.dataSource = nil; 312 | _collectionView.delegate = nil; 313 | } 314 | 315 | @end 316 | -------------------------------------------------------------------------------- /TYPagerControllerDemo/TYPagerController/TabPager/TYTabPagerBarLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // TYTabPagerBarLayout.m 3 | // TYPagerControllerDemo 4 | // 5 | // Created by tanyang on 2017/7/17. 6 | // Copyright © 2017年 tany. All rights reserved. 7 | // 8 | 9 | #import "TYTabPagerBarLayout.h" 10 | #import "TYTabPagerBar.h" 11 | 12 | @interface TYTabPagerBarLayout () 13 | 14 | @property (nonatomic, weak) TYTabPagerBar *pagerTabBar; 15 | 16 | @property (nonatomic, assign) CGFloat selectFontScale; 17 | 18 | @end 19 | 20 | #define kUnderLineViewHeight 2 21 | 22 | @implementation TYTabPagerBarLayout 23 | 24 | - (instancetype)initWithPagerTabBar:(TYTabPagerBar *)pagerTabBar { 25 | if (self = [super init]) { 26 | _pagerTabBar = pagerTabBar; 27 | [self configurePropertys]; 28 | self.barStyle = TYPagerBarStyleProgressElasticView; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)configurePropertys { 34 | _cellSpacing = 2; 35 | _cellEdging = 3; 36 | _cellWidth = 0; 37 | _progressHorEdging = 6; 38 | _progressWidth = 0; 39 | _animateDuration = 0.25; 40 | 41 | _normalTextFont = [UIFont systemFontOfSize:15]; 42 | _selectedTextFont = [UIFont systemFontOfSize:18]; 43 | _normalTextColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1]; 44 | _selectedTextColor = [UIColor redColor]; 45 | _textColorProgressEnable = YES; 46 | //_adjustContentCellsCenter = YES; 47 | } 48 | 49 | #pragma mark - geter setter 50 | 51 | - (void)setProgressRadius:(CGFloat)progressRadius { 52 | _progressRadius = progressRadius; 53 | _pagerTabBar.progressView.layer.cornerRadius = progressRadius; 54 | } 55 | 56 | - (void)setProgressBorderWidth:(CGFloat)progressBorderWidth { 57 | _progressBorderWidth = progressBorderWidth; 58 | _pagerTabBar.progressView.layer.borderWidth = progressBorderWidth; 59 | } 60 | 61 | - (void)setProgressBorderColor:(UIColor *)progressBorderColor { 62 | _progressBorderColor = progressBorderColor; 63 | if (!_progressColor) { 64 | _pagerTabBar.progressView.backgroundColor = [UIColor clearColor]; 65 | } 66 | _pagerTabBar.progressView.layer.borderColor = progressBorderColor.CGColor; 67 | } 68 | 69 | - (void)setProgressColor:(UIColor *)progressColor { 70 | _progressColor = progressColor; 71 | _pagerTabBar.progressView.backgroundColor = progressColor; 72 | } 73 | 74 | - (void)setProgressHeight:(CGFloat)progressHeight { 75 | _progressHeight = progressHeight; 76 | CGRect frame = _pagerTabBar.progressView.frame; 77 | CGFloat height = CGRectGetHeight(_pagerTabBar.collectionView.frame); 78 | frame.origin.y = _barStyle == TYPagerBarStyleCoverView ? (height - _progressHeight)/2:(height - _progressHeight - _progressVerEdging); 79 | frame.size.height = progressHeight; 80 | _pagerTabBar.progressView.frame = frame; 81 | } 82 | 83 | - (UIEdgeInsets)sectionInset { 84 | if (!UIEdgeInsetsEqualToEdgeInsets(_sectionInset, UIEdgeInsetsZero) || _barStyle != TYPagerBarStyleCoverView) { 85 | return _sectionInset; 86 | } 87 | if (_barStyle == TYPagerBarStyleCoverView && _adjustContentCellsCenter) { 88 | return _sectionInset; 89 | } 90 | CGFloat horEdging = -_progressHorEdging+_cellSpacing; 91 | return UIEdgeInsetsMake(0, horEdging, 0, horEdging); 92 | } 93 | 94 | - (void)setAdjustContentCellsCenter:(BOOL)adjustContentCellsCenter { 95 | BOOL change = _adjustContentCellsCenter != adjustContentCellsCenter; 96 | _adjustContentCellsCenter = adjustContentCellsCenter; 97 | if (change && _pagerTabBar.superview) { 98 | [_pagerTabBar setNeedsLayout]; 99 | } 100 | } 101 | 102 | - (void)setBarStyle:(TYPagerBarStyle)barStyle 103 | { 104 | if (barStyle == _barStyle) { 105 | return; 106 | } 107 | if (_barStyle == TYPagerBarStyleCoverView) { 108 | self.progressBorderWidth = 0; 109 | self.progressBorderColor = nil; 110 | } 111 | _barStyle = barStyle; 112 | switch (barStyle) { 113 | case TYPagerBarStyleProgressView: 114 | self.progressWidth = 0; 115 | self.progressHorEdging = 6; 116 | self.progressVerEdging = 0; 117 | self.progressHeight = kUnderLineViewHeight; 118 | break; 119 | case TYPagerBarStyleProgressBounceView: 120 | case TYPagerBarStyleProgressElasticView: 121 | self.progressWidth = 30; 122 | self.progressVerEdging = 0; 123 | self.progressHorEdging = 0; 124 | self.progressHeight = kUnderLineViewHeight; 125 | break; 126 | case TYPagerBarStyleCoverView: 127 | self.progressWidth = 0; 128 | self.progressHorEdging = -self.progressHeight/4; 129 | self.progressVerEdging = 3; 130 | break; 131 | default: 132 | break; 133 | } 134 | _pagerTabBar.progressView.hidden = barStyle == TYPagerBarStyleNoneView; 135 | if (barStyle == TYPagerBarStyleCoverView) { 136 | _progressRadius = 0; 137 | _pagerTabBar.progressView.layer.zPosition = -1; 138 | [_pagerTabBar.progressView removeFromSuperview]; 139 | [_pagerTabBar.collectionView insertSubview: _pagerTabBar.progressView atIndex:0]; 140 | }else { 141 | self.progressRadius = _progressHeight/2; 142 | if (_pagerTabBar.progressView.layer.zPosition == -1) { 143 | _pagerTabBar.progressView.layer.zPosition = 0; 144 | [_pagerTabBar.progressView removeFromSuperview]; 145 | [_pagerTabBar.collectionView addSubview:_pagerTabBar.progressView]; 146 | } 147 | 148 | } 149 | } 150 | 151 | #pragma mark - public 152 | 153 | - (void)layoutIfNeed { 154 | UICollectionViewFlowLayout *collectionLayout = (UICollectionViewFlowLayout *)_pagerTabBar.collectionView.collectionViewLayout; 155 | collectionLayout.minimumLineSpacing = _cellSpacing; 156 | collectionLayout.minimumInteritemSpacing = _cellSpacing; 157 | _selectFontScale = self.normalTextFont.pointSize/(self.selectedTextFont ? self.selectedTextFont.pointSize:self.normalTextFont.pointSize); 158 | collectionLayout.sectionInset = _sectionInset; 159 | } 160 | 161 | - (void)invalidateLayout { 162 | [_pagerTabBar.collectionView.collectionViewLayout invalidateLayout]; 163 | } 164 | 165 | - (void)adjustContentCellsCenterInBar { 166 | if (!_adjustContentCellsCenter || !_pagerTabBar.superview) { 167 | return; 168 | } 169 | CGRect frame = self.pagerTabBar.collectionView.frame; 170 | if (CGRectIsEmpty(frame)) { 171 | return; 172 | } 173 | 174 | UICollectionViewFlowLayout *collectionLayout = (UICollectionViewFlowLayout *)_pagerTabBar.collectionView.collectionViewLayout; 175 | CGSize contentSize = collectionLayout.collectionViewContentSize; 176 | NSArray *layoutAttribulte = [collectionLayout layoutAttributesForElementsInRect:CGRectMake(0, 0, MAX(contentSize.width, CGRectGetWidth(frame)), MAX(contentSize.height,CGRectGetHeight(frame)))]; 177 | if (layoutAttribulte.count == 0) { 178 | return; 179 | } 180 | 181 | UICollectionViewLayoutAttributes *firstAttribute = layoutAttribulte.firstObject; 182 | UICollectionViewLayoutAttributes *lastAttribute = layoutAttribulte.lastObject; 183 | CGFloat left = CGRectGetMinX(firstAttribute.frame); 184 | CGFloat right = CGRectGetMaxX(lastAttribute.frame); 185 | if (right - left > CGRectGetWidth(self.pagerTabBar.frame)) { 186 | return; 187 | } 188 | CGFloat sapce = (CGRectGetWidth(self.pagerTabBar.frame) - (right - left))/2; 189 | _sectionInset = UIEdgeInsetsMake(_sectionInset.top, sapce, _sectionInset.bottom, sapce); 190 | collectionLayout.sectionInset = _sectionInset; 191 | } 192 | 193 | - (CGRect)cellFrameWithIndex:(NSInteger)index { 194 | return [_pagerTabBar cellFrameWithIndex:index]; 195 | } 196 | 197 | #pragma mark - cell 198 | 199 | - (void)transitionFromCell:(UICollectionViewCell *)fromCell toCell:(UICollectionViewCell *)toCell animate:(BOOL)animate { 200 | if (_pagerTabBar.countOfItems == 0) { 201 | return; 202 | } 203 | void (^animateBlock)() = ^{ 204 | if (fromCell) { 205 | fromCell.titleLabel.font = _normalTextFont; 206 | fromCell.titleLabel.textColor = _normalTextColor; 207 | fromCell.transform = CGAffineTransformMakeScale(_selectFontScale, _selectFontScale); 208 | } 209 | if (toCell) { 210 | toCell.titleLabel.font = _normalTextFont; 211 | toCell.titleLabel.textColor = _selectedTextColor ? _selectedTextColor : _normalTextColor; 212 | toCell.transform = CGAffineTransformIdentity; 213 | } 214 | }; 215 | if (animate) { 216 | [UIView animateWithDuration:_animateDuration animations:^{ 217 | animateBlock(); 218 | }]; 219 | }else{ 220 | animateBlock(); 221 | } 222 | 223 | } 224 | 225 | - (void)transitionFromCell:(UICollectionViewCell *)fromCell toCell:(UICollectionViewCell *)toCell progress:(CGFloat)progress { 226 | if (_pagerTabBar.countOfItems == 0 || !_textColorProgressEnable) { 227 | return; 228 | } 229 | CGFloat currentTransform = (1.0 - _selectFontScale)*progress; 230 | fromCell.transform = CGAffineTransformMakeScale(1.0-currentTransform, 1.0-currentTransform); 231 | toCell.transform = CGAffineTransformMakeScale(_selectFontScale+currentTransform, _selectFontScale+currentTransform); 232 | 233 | if (_normalTextColor == _selectedTextColor || !_selectedTextColor) { 234 | return; 235 | } 236 | 237 | CGFloat narR=0,narG=0,narB=0,narA=1; 238 | [_normalTextColor getRed:&narR green:&narG blue:&narB alpha:&narA]; 239 | CGFloat selR=0,selG=0,selB=0,selA=1; 240 | [_selectedTextColor getRed:&selR green:&selG blue:&selB alpha:&selA]; 241 | CGFloat detalR = narR - selR ,detalG = narG - selG,detalB = narB - selB,detalA = narA - selA; 242 | 243 | fromCell.titleLabel.textColor = [UIColor colorWithRed:selR+detalR*progress green:selG+detalG*progress blue:selB+detalB*progress alpha:selA+detalA*progress]; 244 | toCell.titleLabel.textColor = [UIColor colorWithRed:narR-detalR*progress green:narG-detalG*progress blue:narB-detalB*progress alpha:narA-detalA*progress]; 245 | } 246 | 247 | #pragma mark - progress View 248 | 249 | // set up progress view frame 250 | - (void)setUnderLineFrameWithIndex:(NSInteger)index animated:(BOOL)animated 251 | { 252 | UIView *progressView = _pagerTabBar.progressView; 253 | if (progressView.isHidden || _pagerTabBar.countOfItems == 0) { 254 | return; 255 | } 256 | 257 | CGRect cellFrame = [self cellFrameWithIndex:index]; 258 | CGFloat progressHorEdging = _progressWidth > 0 ? (cellFrame.size.width - _progressWidth)/2 : _progressHorEdging; 259 | CGFloat progressX = cellFrame.origin.x+progressHorEdging; 260 | CGFloat progressY = _barStyle == TYPagerBarStyleCoverView ? (cellFrame.size.height - _progressHeight)/2:(cellFrame.size.height - _progressHeight - _progressVerEdging); 261 | CGFloat width = cellFrame.size.width-2*progressHorEdging; 262 | 263 | if (animated) { 264 | [UIView animateWithDuration:_animateDuration animations:^{ 265 | progressView.frame = CGRectMake(progressX, progressY, width, _progressHeight); 266 | }]; 267 | }else { 268 | progressView.frame = CGRectMake(progressX, progressY, width, _progressHeight); 269 | } 270 | } 271 | 272 | - (void)setUnderLineFrameWithfromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress 273 | { 274 | UIView *progressView = _pagerTabBar.progressView; 275 | if (progressView.isHidden || _pagerTabBar.countOfItems == 0) { 276 | return; 277 | } 278 | 279 | CGRect fromCellFrame = [self cellFrameWithIndex:fromIndex]; 280 | CGRect toCellFrame = [self cellFrameWithIndex:toIndex]; 281 | 282 | CGFloat progressFromEdging = _progressWidth > 0 ? (fromCellFrame.size.width - _progressWidth)/2 : _progressHorEdging; 283 | CGFloat progressToEdging = _progressWidth > 0 ? (toCellFrame.size.width - _progressWidth)/2 : _progressHorEdging; 284 | CGFloat progressY = _barStyle == TYPagerBarStyleCoverView ? (toCellFrame.size.height - _progressHeight)/2:(toCellFrame.size.height - _progressHeight - _progressVerEdging); 285 | CGFloat progressX = 0, width = 0; 286 | 287 | if (_barStyle == TYPagerBarStyleProgressBounceView) { 288 | if (fromCellFrame.origin.x < toCellFrame.origin.x) { 289 | if (progress <= 0.5) { 290 | progressX = fromCellFrame.origin.x + progressFromEdging; 291 | width = (toCellFrame.size.width-progressToEdging+progressFromEdging+_cellSpacing)*2*progress + fromCellFrame.size.width-2*progressFromEdging; 292 | }else { 293 | progressX = fromCellFrame.origin.x + progressFromEdging + (fromCellFrame.size.width-progressFromEdging+progressToEdging+_cellSpacing)*(progress-0.5)*2; 294 | width = CGRectGetMaxX(toCellFrame)-progressToEdging - progressX; 295 | } 296 | }else { 297 | if (progress <= 0.5) { 298 | progressX = fromCellFrame.origin.x + progressFromEdging - (toCellFrame.size.width-progressToEdging+progressFromEdging+_cellSpacing)*2*progress; 299 | width = CGRectGetMaxX(fromCellFrame) - progressFromEdging - progressX; 300 | }else { 301 | progressX = toCellFrame.origin.x + progressToEdging; 302 | width = (fromCellFrame.size.width-progressFromEdging+progressToEdging + _cellSpacing)*(1-progress)*2 + toCellFrame.size.width - 2*progressToEdging; 303 | } 304 | } 305 | }else if (_barStyle == TYPagerBarStyleProgressElasticView) { 306 | if (fromCellFrame.origin.x < toCellFrame.origin.x) { 307 | if (progress <= 0.5) { 308 | progressX = fromCellFrame.origin.x + progressFromEdging + (fromCellFrame.size.width-2*progressFromEdging)*progress; 309 | width = (toCellFrame.size.width-progressToEdging+progressFromEdging+_cellSpacing)*2*progress - (toCellFrame.size.width-2*progressToEdging)*progress + fromCellFrame.size.width-2*progressFromEdging-(fromCellFrame.size.width-2*progressFromEdging)*progress; 310 | }else { 311 | progressX = fromCellFrame.origin.x + progressFromEdging + (fromCellFrame.size.width-2*progressFromEdging)*0.5 + (fromCellFrame.size.width-progressFromEdging - (fromCellFrame.size.width-2*progressFromEdging)*0.5 +progressToEdging+_cellSpacing)*(progress-0.5)*2; 312 | width = CGRectGetMaxX(toCellFrame)-progressToEdging - progressX - (toCellFrame.size.width-2*progressToEdging)*(1-progress); 313 | } 314 | }else { 315 | if (progress <= 0.5) { 316 | progressX = fromCellFrame.origin.x + progressFromEdging - (toCellFrame.size.width-(toCellFrame.size.width-2*progressToEdging)/2-progressToEdging+progressFromEdging+_cellSpacing)*2*progress; 317 | width = CGRectGetMaxX(fromCellFrame) - (fromCellFrame.size.width-2*progressFromEdging)*progress - progressFromEdging - progressX; 318 | }else { 319 | progressX = toCellFrame.origin.x + progressToEdging+(toCellFrame.size.width-2*progressToEdging)*(1-progress); 320 | width = (fromCellFrame.size.width-progressFromEdging+progressToEdging-(fromCellFrame.size.width-2*progressFromEdging)/2 + _cellSpacing)*(1-progress)*2 + toCellFrame.size.width - 2*progressToEdging - (toCellFrame.size.width-2*progressToEdging)*(1-progress); 321 | } 322 | } 323 | }else { 324 | progressX = (toCellFrame.origin.x+progressToEdging-(fromCellFrame.origin.x+progressFromEdging))*progress+fromCellFrame.origin.x+progressFromEdging; 325 | width = (toCellFrame.size.width-2*progressToEdging)*progress + (fromCellFrame.size.width-2*progressFromEdging)*(1-progress); 326 | } 327 | 328 | progressView.frame = CGRectMake(progressX,progressY, width, _progressHeight); 329 | } 330 | 331 | - (void)layoutSubViews { 332 | if (CGRectIsEmpty(_pagerTabBar.frame)) { 333 | return; 334 | } 335 | if (_barStyle == TYPagerBarStyleCoverView) { 336 | self.progressHeight = CGRectGetHeight(_pagerTabBar.collectionView.frame) -self.progressVerEdging*2; 337 | self.progressRadius = _progressRadius > 0 ? _progressRadius : self.progressHeight/2; 338 | } 339 | [self setUnderLineFrameWithIndex:_pagerTabBar.curIndex animated:NO]; 340 | } 341 | 342 | @end 343 | --------------------------------------------------------------------------------