├── ERPageController
├── Assets.xcassets
│ ├── Contents.json
│ ├── editButtonImage.imageset
│ │ ├── editButtonImage@2x.png
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── PageOneViewController.h
├── PageTwoViewController.h
├── ViewController.h
├── PageFourViewController.h
├── PageThreeViewController.h
├── AppDelegate.h
├── ERPageController
│ ├── EditMenuControllers
│ │ ├── SectionHeader.h
│ │ ├── EditMenuCollectionViewCell.h
│ │ ├── EditMenuCollectionViewCell.m
│ │ ├── SectionHeader.m
│ │ ├── ERSegmentMenuController.h
│ │ ├── LXReorderableCollectionViewFlowLayout.h
│ │ ├── EditMenuCollectionViewCell.xib
│ │ ├── ERSegmentMenuController.m
│ │ └── LXReorderableCollectionViewFlowLayout.m
│ └── PageViewControllers
│ │ ├── ERSegmentCollectionViewCell.h
│ │ ├── ERSegmentCollectionViewCell.m
│ │ ├── ERPageViewController.h
│ │ ├── ERSegmentController.h
│ │ ├── ERSegmentCollectionViewCell.xib
│ │ ├── ERPageViewController.m
│ │ └── ERSegmentController.m
├── main.m
├── PageFourViewController.m
├── PageOneViewController.m
├── PageTwoViewController.m
├── PageThreeViewController.m
├── Info.plist
├── Base.lproj
│ ├── Main.storyboard
│ └── LaunchScreen.storyboard
├── AppDelegate.m
└── ViewController.m
├── ERPageController.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── huguangyu.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── xcuserdata
│ └── huguangyu.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── ERPageController.xcscheme
└── project.pbxproj
├── ERPageControllerTests
├── Info.plist
└── ERPageControllerTests.m
├── ERPageControllerUITests
├── Info.plist
└── ERPageControllerUITests.m
└── README.md
/ERPageController/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/ERPageController/Assets.xcassets/editButtonImage.imageset/editButtonImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErHu1993/ERPageController/HEAD/ERPageController/Assets.xcassets/editButtonImage.imageset/editButtonImage@2x.png
--------------------------------------------------------------------------------
/ERPageController.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ERPageController.xcodeproj/project.xcworkspace/xcuserdata/huguangyu.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ErHu1993/ERPageController/HEAD/ERPageController.xcodeproj/project.xcworkspace/xcuserdata/huguangyu.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/ERPageController/PageOneViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // PageOneViewController.h
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface PageOneViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ERPageController/PageTwoViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // PageTwoViewController.h
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface PageTwoViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ERPageController/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // ERPageController
4 | //
5 | // Created by 胡广宇 on 2017/7/7.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/ERPageController/PageFourViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // PageFourViewController.h
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface PageFourViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ERPageController/PageThreeViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // PageThreeViewController.h
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface PageThreeViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/ERPageController/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // ERPageController
4 | //
5 | // Created by 胡广宇 on 2017/7/7.
6 | // Copyright © 2017年 胡广宇. 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 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/EditMenuControllers/SectionHeader.h:
--------------------------------------------------------------------------------
1 | //
2 | // SectionHeader.h
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/7/6.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SectionHeader : UICollectionReusableView
12 |
13 | @property (nonatomic, strong) UILabel *titleLabel;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/ERPageController/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // ERPageController
4 | //
5 | // Created by 胡广宇 on 2017/7/7.
6 | // Copyright © 2017年 胡广宇. 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 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/EditMenuControllers/EditMenuCollectionViewCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // EditMenuCollectionViewCell.h
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/7/4.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface EditMenuCollectionViewCell : UICollectionViewCell
12 |
13 | @property (weak, nonatomic) IBOutlet UIButton *channelButton;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/PageViewControllers/ERSegmentCollectionViewCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // ERSegmentCollectionViewCell.h
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ERSegmentCollectionViewCell : UICollectionViewCell
12 |
13 | @property (weak, nonatomic) IBOutlet UILabel *titleLabel;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/PageViewControllers/ERSegmentCollectionViewCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // ERSegmentCollectionViewCell.m
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import "ERSegmentCollectionViewCell.h"
10 |
11 | @implementation ERSegmentCollectionViewCell
12 |
13 | - (void)awakeFromNib {
14 | [super awakeFromNib];
15 |
16 | }
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/ERPageController/Assets.xcassets/editButtonImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "editButtonImage@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/ERPageController/ERPageController/EditMenuControllers/EditMenuCollectionViewCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // EditMenuCollectionViewCell.m
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/7/4.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import "EditMenuCollectionViewCell.h"
10 |
11 | @interface EditMenuCollectionViewCell ()
12 |
13 | @property (weak, nonatomic) IBOutlet UIButton *deleteButton;
14 |
15 | @end
16 |
17 | @implementation EditMenuCollectionViewCell
18 |
19 | - (void)awakeFromNib {
20 | [super awakeFromNib];
21 | }
22 |
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/ERPageController.xcodeproj/xcuserdata/huguangyu.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/ERPageControllerTests/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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ERPageControllerUITests/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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/EditMenuControllers/SectionHeader.m:
--------------------------------------------------------------------------------
1 | //
2 | // SectionHeader.m
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/7/6.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import "SectionHeader.h"
10 |
11 | @implementation SectionHeader
12 |
13 | - (UILabel *)titleLabel{
14 | if (!_titleLabel) {
15 | _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
16 | _titleLabel.font = [UIFont systemFontOfSize:12];
17 | _titleLabel.textColor = [UIColor blackColor];
18 | [self addSubview:_titleLabel];
19 | }
20 | return _titleLabel;
21 | }
22 |
23 | - (void)layoutSubviews{
24 | [self.titleLabel setFrame:CGRectMake(10, (CGRectGetHeight(self.frame) - 15), CGRectGetWidth(self.frame), 15)];
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/ERPageController.xcodeproj/xcuserdata/huguangyu.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ERPageController.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | D8F7C80B1F0F5E5B000DB0E7
16 |
17 | primary
18 |
19 |
20 | D8F7C8241F0F5E5B000DB0E7
21 |
22 | primary
23 |
24 |
25 | D8F7C82F1F0F5E5B000DB0E7
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/ERPageController/PageFourViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // PageFourViewController.m
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import "PageFourViewController.h"
10 |
11 | @interface PageFourViewController ()
12 |
13 | @end
14 |
15 | @implementation PageFourViewController
16 |
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | self.view.backgroundColor = [UIColor blueColor];
20 | }
21 |
22 | - (void)didReceiveMemoryWarning {
23 | [super didReceiveMemoryWarning];
24 | // Dispose of any resources that can be recreated.
25 | }
26 |
27 | /*
28 | #pragma mark - Navigation
29 |
30 | // In a storyboard-based application, you will often want to do a little preparation before navigation
31 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
32 | // Get the new view controller using [segue destinationViewController].
33 | // Pass the selected object to the new view controller.
34 | }
35 | */
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/ERPageController/PageOneViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // PageOneViewController.m
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import "PageOneViewController.h"
10 |
11 | @interface PageOneViewController ()
12 |
13 | @end
14 |
15 | @implementation PageOneViewController
16 |
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | self.view.backgroundColor = [UIColor whiteColor];
20 | }
21 |
22 | - (void)didReceiveMemoryWarning {
23 | [super didReceiveMemoryWarning];
24 | // Dispose of any resources that can be recreated.
25 | }
26 |
27 | /*
28 | #pragma mark - Navigation
29 |
30 | // In a storyboard-based application, you will often want to do a little preparation before navigation
31 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
32 | // Get the new view controller using [segue destinationViewController].
33 | // Pass the selected object to the new view controller.
34 | }
35 | */
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/ERPageController/PageTwoViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // PageTwoViewController.m
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import "PageTwoViewController.h"
10 |
11 | @interface PageTwoViewController ()
12 |
13 | @end
14 |
15 | @implementation PageTwoViewController
16 |
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | self.view.backgroundColor = [UIColor yellowColor];
20 | }
21 |
22 | - (void)didReceiveMemoryWarning {
23 | [super didReceiveMemoryWarning];
24 | // Dispose of any resources that can be recreated.
25 | }
26 |
27 | /*
28 | #pragma mark - Navigation
29 |
30 | // In a storyboard-based application, you will often want to do a little preparation before navigation
31 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
32 | // Get the new view controller using [segue destinationViewController].
33 | // Pass the selected object to the new view controller.
34 | }
35 | */
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/ERPageController/PageThreeViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // PageThreeViewController.m
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import "PageThreeViewController.h"
10 |
11 | @interface PageThreeViewController ()
12 |
13 | @end
14 |
15 | @implementation PageThreeViewController
16 |
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | self.view.backgroundColor = [UIColor blackColor];
20 | }
21 |
22 | - (void)didReceiveMemoryWarning {
23 | [super didReceiveMemoryWarning];
24 | // Dispose of any resources that can be recreated.
25 | }
26 |
27 | /*
28 | #pragma mark - Navigation
29 |
30 | // In a storyboard-based application, you will often want to do a little preparation before navigation
31 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
32 | // Get the new view controller using [segue destinationViewController].
33 | // Pass the selected object to the new view controller.
34 | }
35 | */
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/ERPageControllerTests/ERPageControllerTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // ERPageControllerTests.m
3 | // ERPageControllerTests
4 | //
5 | // Created by 胡广宇 on 2017/7/7.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ERPageControllerTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation ERPageControllerTests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 | // Put setup code here. This method is called before the invocation of each test method in the class.
20 | }
21 |
22 | - (void)tearDown {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | [super tearDown];
25 | }
26 |
27 | - (void)testExample {
28 | // This is an example of a functional test case.
29 | // Use XCTAssert and related functions to verify your tests produce the correct results.
30 | }
31 |
32 | - (void)testPerformanceExample {
33 | // This is an example of a performance test case.
34 | [self measureBlock:^{
35 | // Put the code you want to measure the time of here.
36 | }];
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/ERPageControllerUITests/ERPageControllerUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // ERPageControllerUITests.m
3 | // ERPageControllerUITests
4 | //
5 | // Created by 胡广宇 on 2017/7/7.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ERPageControllerUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation ERPageControllerUITests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 |
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 |
22 | // In UI tests it is usually best to stop immediately when a failure occurs.
23 | self.continueAfterFailure = NO;
24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
25 | [[[XCUIApplication alloc] init] launch];
26 |
27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
28 | }
29 |
30 | - (void)tearDown {
31 | // Put teardown code here. This method is called after the invocation of each test method in the class.
32 | [super tearDown];
33 | }
34 |
35 | - (void)testExample {
36 | // Use recording to get started writing UI tests.
37 | // Use XCTAssert and related functions to verify your tests produce the correct results.
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/ERPageController/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 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/EditMenuControllers/ERSegmentMenuController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ERSegmentMenuController.h
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/29.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class ERSegmentMenuController;
12 |
13 | @protocol ERSegmentMenuControllerDataSource
14 |
15 | @required;
16 |
17 | /**
18 | 已经选择的频道列表信息
19 |
20 | @param segmentMenuController self
21 | @return 必须为字典型数组(必须包含一个KEY为@"name"的字符串)
22 | */
23 | - (NSMutableArray *)selectedChannelLisInSegmentMenuController:(ERSegmentMenuController *)segmentMenuController;
24 |
25 | @optional;
26 |
27 | /**
28 | 未选择的频道列表信息
29 |
30 | @param segmentMenuController self
31 | @return 可以为nil ,若不为nil则必须为字典型数组(必须包含一个KEY为@"name"的字符串)
32 | */
33 | - (NSMutableArray *)unSelectChannelListInSegmentMenuController:(ERSegmentMenuController *)segmentMenuController;
34 |
35 |
36 | /**
37 | 每组标题
38 |
39 | @param segmentMenuController segmentMenuController
40 | @param sectionHeaderLabel 组头Label
41 | @param section section
42 | @return title
43 | */
44 | - (NSString *)segmentMenuController:(ERSegmentMenuController *)segmentMenuController sectionHeaderLabel:(UILabel *)sectionHeaderLabel titleForHeaderInSection:(NSInteger)section;
45 |
46 | @end
47 |
48 | @protocol ERSegmentMenuControllerDelegate
49 |
50 | @optional;
51 |
52 | - (void)displayChannelListDidChange;
53 |
54 | @end
55 |
56 | @interface ERSegmentMenuController : UIViewController
57 |
58 | @property (nonatomic, weak) id dataSource;
59 |
60 | @property (nonatomic, weak) id delegate;
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/ERPageController/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 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ERPageController/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 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/PageViewControllers/ERPageViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ERPageViewController.h
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class ERPageViewController;
12 |
13 | @protocol ERPageViewControllerDataSource
14 |
15 | @required
16 |
17 | /**
18 | 返回子控制器总数,类似TableViewDataSource
19 |
20 | @param pageViewController self
21 | @return 子控制器总数
22 | */
23 | - (NSInteger)numberOfControllersInPageViewController:(ERPageViewController *)pageViewController;
24 |
25 |
26 | /**
27 | 返回对应index的ViewController
28 |
29 | @param pageViewController self
30 | @param index 当前index
31 | @return 需要展示的ViewController
32 | */
33 | - (UIViewController *)pageViewController:(ERPageViewController *)pageViewController childControllerAtIndex:(NSInteger)index;
34 |
35 | /**
36 | 子控制器title
37 |
38 | @param pageViewController self
39 | @param index 当前index
40 | @return title
41 | */
42 | - (NSString *)pageViewController:(ERPageViewController *)pageViewController titleForChildControllerAtIndex:(NSInteger)index;
43 |
44 |
45 | @end
46 |
47 |
48 | @interface ERPageViewController : UIViewController
49 |
50 | /** 导航选择器高度 */
51 | @property (nonatomic, assign) NSInteger segmentHeight;
52 |
53 | @property (nonatomic, assign) NSInteger countOfControllers;
54 |
55 | @property (nonatomic, assign) NSInteger currentIndex;
56 |
57 | @property (nonatomic, strong) UIScrollView *contentScrollerView;
58 |
59 | @property (nonatomic, weak) id dataSource;
60 |
61 | /**
62 | 刷新子视图
63 | */
64 | - (void)reloadPageData;
65 |
66 |
67 | /**
68 | 移动到某一页面
69 |
70 | @param index index
71 | */
72 | - (void)movePageControllerToIndex:(NSInteger)index;
73 | @end
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/ERPageController/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/ERPageController/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // ERPageController
4 | //
5 | // Created by 胡广宇 on 2017/7/7.
6 | // Copyright © 2017年 胡广宇. 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 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/PageViewControllers/ERSegmentController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ERSegmentController.h
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import "ERPageViewController.h"
10 | #import "ERSegmentMenuController.h"
11 |
12 | @class ERSegmentController;
13 |
14 | @protocol ERSegmentControllerDelegte
15 |
16 | @optional
17 |
18 | /**
19 | 导航按钮点击事件回调
20 |
21 | @param segmentController self
22 | @param indexPath indexPath
23 | */
24 | - (void)segmentController:(ERSegmentController *)segmentController didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
25 |
26 | /**
27 | 导航菜单编辑按钮点击回调
28 |
29 | @param segmentController self
30 | @param editMenuButton editMenuButton
31 | */
32 | - (void)segmentController:(ERSegmentController *)segmentController didSelectEditMenuButton:(UIButton *)editMenuButton;
33 | /**
34 | 导航按钮双击事件回调
35 |
36 | @param segmentController self
37 | @param indexPath indexPath
38 | */
39 | - (void)segmentController:(ERSegmentController *)segmentController itemDoubleClickAtIndexPath:(NSIndexPath *)indexPath;
40 |
41 | /**
42 | 页面切换滚动完成回调
43 |
44 | @param pageController superClass
45 | @param fromIndex fromIndex
46 | @param toIndex toIndex
47 | */
48 | - (void)pageControllerDidScroll:(ERPageViewController *)pageController fromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex;
49 |
50 | @end
51 |
52 | @interface ERSegmentController : ERPageViewController
53 |
54 | @property (nonatomic, weak) iddelegate;
55 | /** 是否展示编辑菜单按钮 */
56 | @property (nonatomic, weak) id menuDataSource;
57 | /** 编辑菜单图片(这里在editMenuButton上又覆盖一层imageView是为了让阴影和旋转分开,用不同的视图表示) */
58 | @property (nonatomic, strong) UIImageView *editMenuIconIgV;
59 | /** 底部横线高度 */
60 | @property (nonatomic, assign) CGFloat progressHeight;
61 | /** 底部横线宽度 */
62 | @property (nonatomic, assign) CGFloat progressWidth;
63 | /** 未选中状态下的字号 */
64 | @property (nonatomic, strong) UIFont *normalTextFont;
65 | /** 选中状态下的字号 */
66 | @property (nonatomic, strong) UIFont *selectedTextFont;
67 | /** 未选中状态下的字体颜色 */
68 | @property (nonatomic, strong) UIColor *normalTextColor;
69 | /** 选中状态下的字体颜色 */
70 | @property (nonatomic, strong) UIColor *selectedTextColor;
71 | /** item直接的行间距 */
72 | @property (nonatomic, assign) NSInteger itemMinimumSpace;
73 |
74 | @end
75 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/EditMenuControllers/LXReorderableCollectionViewFlowLayout.h:
--------------------------------------------------------------------------------
1 | //
2 | // LXReorderableCollectionViewFlowLayout.h
3 | //
4 | // Created by Stan Chang Khin Boon on 1/10/12.
5 | // Copyright (c) 2012 d--buzz. All rights reserved.
6 | //
7 |
8 | #import
9 |
10 | @interface LXReorderableCollectionViewFlowLayout : UICollectionViewFlowLayout
11 |
12 | @property (assign, nonatomic) CGFloat scrollingSpeed;
13 | @property (assign, nonatomic) UIEdgeInsets scrollingTriggerEdgeInsets;
14 | @property (strong, nonatomic, readonly) UILongPressGestureRecognizer *longPressGestureRecognizer;
15 | @property (strong, nonatomic, readonly) UIPanGestureRecognizer *panGestureRecognizer;
16 |
17 | - (void)setUpGestureRecognizersOnCollectionView __attribute__((deprecated("Calls to setUpGestureRecognizersOnCollectionView method are not longer needed as setup are done automatically through KVO.")));
18 |
19 | @end
20 |
21 | @protocol LXReorderableCollectionViewDataSource
22 |
23 | @optional
24 |
25 | - (void)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath willMoveToIndexPath:(NSIndexPath *)toIndexPath;
26 | - (void)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath didMoveToIndexPath:(NSIndexPath *)toIndexPath;
27 |
28 | - (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath;
29 | - (BOOL)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath canMoveToIndexPath:(NSIndexPath *)toIndexPath;
30 |
31 | @end
32 |
33 | @protocol LXReorderableCollectionViewDelegateFlowLayout
34 | @optional
35 |
36 | - (void)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout willBeginDraggingItemAtIndexPath:(NSIndexPath *)indexPath;
37 | - (void)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout didBeginDraggingItemAtIndexPath:(NSIndexPath *)indexPath;
38 | - (void)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout willEndDraggingItemAtIndexPath:(NSIndexPath *)indexPath;
39 | - (void)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout didEndDraggingItemAtIndexPath:(NSIndexPath *)indexPath;
40 |
41 | @end
--------------------------------------------------------------------------------
/ERPageController/ERPageController/PageViewControllers/ERSegmentCollectionViewCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/PageViewControllers/ERPageViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ERPageViewController.m
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import "ERPageViewController.h"
10 |
11 | @interface ERPageViewController ()
12 |
13 | @property (nonatomic, assign) NSMutableArray *visiblecontrollers;
14 |
15 | @end
16 |
17 | @implementation ERPageViewController
18 |
19 | - (void)viewDidLoad {
20 |
21 | [super viewDidLoad];
22 |
23 | self.automaticallyAdjustsScrollViewInsets = false;
24 | self.view.backgroundColor = [UIColor whiteColor];
25 |
26 | self.segmentHeight = 30;
27 | }
28 |
29 | /**
30 | 添加子视图控制器
31 | */
32 | - (void)initializeSubViews{
33 |
34 | [self.visiblecontrollers removeAllObjects];
35 | self.countOfControllers = [self.dataSource numberOfControllersInPageViewController:self];
36 | for (int i = 0; i < self.countOfControllers; i++) {
37 | [self addViewController:[self.dataSource pageViewController:self childControllerAtIndex:i] atIndex:i];
38 | }
39 | self.contentScrollerView.contentSize = CGSizeMake(self.countOfControllers * CGRectGetWidth(self.contentScrollerView.frame), 0);
40 | self.contentScrollerView.contentOffset = CGPointMake(self.currentIndex * CGRectGetWidth(self.contentScrollerView.frame), 0);
41 | }
42 |
43 | /**
44 | 刷新子视图
45 | */
46 | - (void)reloadPageData{
47 | [self initializeSubViews];
48 | }
49 |
50 | /**
51 | 移动到某一页面
52 |
53 | @param index index
54 | */
55 | - (void)movePageControllerToIndex:(NSInteger)index{
56 | if (index < 0 && index > self.countOfControllers) return;
57 | [self.contentScrollerView setContentOffset:CGPointMake(index * CGRectGetWidth(self.contentScrollerView .frame),0)];
58 | }
59 |
60 | #pragma mark - 控制器的增删操作
61 |
62 | - (void)addViewController:(UIViewController *)viewController atIndex:(NSInteger)index
63 | {
64 | if (!viewController.parentViewController) {
65 | [self addChildViewController:viewController];
66 | viewController.view.frame = [self getControllerFrameWithIndex:index];
67 | [self.contentScrollerView addSubview:viewController.view];
68 | [self.visiblecontrollers addObject:viewController];
69 | }else {
70 | viewController.view.frame = [self getControllerFrameWithIndex:index];
71 | }
72 | }
73 |
74 | - (void)removeViewController:(UIViewController *)viewController atIndex:(NSInteger)index
75 | {
76 | if (viewController.parentViewController) {
77 | [viewController.view removeFromSuperview];
78 | [viewController removeFromParentViewController];
79 | [self.visiblecontrollers removeObjectAtIndex:index];
80 | }
81 | }
82 |
83 | - (CGRect)getControllerFrameWithIndex:(NSInteger)index{
84 | return CGRectMake(index * CGRectGetWidth(self.contentScrollerView.frame), 0, CGRectGetWidth(self.contentScrollerView.frame), CGRectGetHeight(self.contentScrollerView.frame));
85 | }
86 |
87 | - (void)viewWillLayoutSubviews{
88 | if (!CGRectEqualToRect(self.contentScrollerView.bounds, self.view.bounds)) {
89 | self.contentScrollerView.frame = CGRectMake(0, self.segmentHeight, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame) - self.segmentHeight);
90 | [self initializeSubViews];
91 | }
92 | }
93 |
94 |
95 | #pragma mark - getter/setter
96 |
97 | - (UIScrollView *)contentScrollerView{
98 | if (!_contentScrollerView) {
99 | _contentScrollerView = [[UIScrollView alloc] initWithFrame:CGRectZero];
100 | _contentScrollerView.showsHorizontalScrollIndicator = NO;
101 | _contentScrollerView.showsVerticalScrollIndicator = NO;
102 | _contentScrollerView.pagingEnabled = YES;
103 | [self.view addSubview:_contentScrollerView];
104 | }
105 | return _contentScrollerView;
106 | }
107 |
108 | - (void)didReceiveMemoryWarning {
109 | [super didReceiveMemoryWarning];
110 |
111 | }
112 |
113 | @end
114 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/EditMenuControllers/EditMenuCollectionViewCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/ERPageController.xcodeproj/xcuserdata/huguangyu.xcuserdatad/xcschemes/ERPageController.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
63 |
64 |
74 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
95 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # ERPageController
3 |
4 | ## 带编辑菜单的分页选择器
5 |
6 | ### 功能说明:
7 | ##### 页面为不同的ViewController,可以左右滑动.
8 | ##### 顶部导航条可点击切换(双击刷新事件回调),可以左右滑动查看.
9 | ##### 按需显示的编辑菜单,可以长按拖动顺序/添加/删除
10 |
11 |
12 | 
13 |
14 | ### 使用方法:
15 |
16 | ### 特别声明: 数据模型我使用的是``` (NSMutableArray *) ``` 通过 "name" 获取页面标题 (可根据自己需求更改)
17 |
18 | ### 初始化控件
19 |
20 | ```
21 | ERSegmentController *pageManager = [[ERSegmentController alloc] init];
22 | pageManager.view.frame = CGRectMake(0, 64, ScreenWidth, ScreenHeight - 64 - 49);
23 | pageManager.segmentHeight = 25;//导航条高度
24 | pageManager.progressWidth = 15;//导航条底横线度宽度
25 | pageManager.progressHeight = 1;//导航条底横线高
26 | pageManager.itemMinimumSpace = 10;//导航条item直接的间距
27 | pageManager.normalTextFont = [UIFont systemFontOfSize:12];//未选中字体大小
28 | pageManager.selectedTextFont = [UIFont systemFontOfSize:16];//已选中字体大小
29 | pageManager.normalTextColor = [UIColor blackColor];//未选中字体颜色
30 | pageManager.selectedTextColor = [UIColor redColor];//已选中字体颜色
31 | pageManager.dataSource = self;//页面管理数据源
32 | pageManager.menuDataSource = self;//菜单管理数据源, 如果不设置改代理则没有菜单按钮
33 | pageManager.editMenuIconIgV.image = [UIImage imageNamed:@"editButtonImage"];//编辑菜单icon (按需设置)
34 | pageManager.delegate = self;//相关事件返回代理
35 | [self.view addSubview:pageManager.view];
36 | [self addChildViewController:pageManager];
37 | ```
38 | ### 通过 dataSource 获取所有页面的数据源
39 |
40 | ```
41 | @protocol ERPageViewControllerDataSource
42 |
43 | @required
44 |
45 | /**
46 | 返回子控制器总数,类似TableViewDataSource
47 |
48 | @param pageViewController self
49 | @return 子控制器总数
50 | */
51 | - (NSInteger)numberOfControllersInPageViewController:(ERPageViewController *)pageViewController;
52 |
53 |
54 | /**
55 | 返回对应index的ViewController
56 |
57 | @param pageViewController self
58 | @param index 当前index
59 | @return 需要展示的ViewController
60 | */
61 | - (UIViewController *)pageViewController:(ERPageViewController *)pageViewController childControllerAtIndex:(NSInteger)index;
62 |
63 | /**
64 | 子控制器title
65 |
66 | @param pageViewController self
67 | @param index 当前index
68 | @return title
69 | */
70 | - (NSString *)pageViewController:(ERPageViewController *)pageViewController titleForChildControllerAtIndex:(NSInteger)index;
71 |
72 |
73 |
74 | @end
75 |
76 | ```
77 |
78 | ### 通过 menuDataSource 获取编辑菜单的数据源,如不需要则不用设置该代理
79 |
80 | ```
81 | @protocol ERSegmentMenuControllerDataSource
82 |
83 | @required;
84 |
85 | /**
86 | 已经选择的频道列表信息
87 |
88 | @param segmentMenuController self
89 | @return 必须为字典型数组(必须包含一个KEY为@"name"的字符串)
90 | */
91 | - (NSMutableArray *)selectedChannelLisInSegmentMenuController:(ERSegmentMenuController *)segmentMenuController;
92 |
93 | @optional;
94 |
95 | /**
96 | 未选择的频道列表信息
97 |
98 | @param segmentMenuController self
99 | @return 可以为nil ,若不为nil则必须为字典型数组(必须包含一个KEY为@"name"的字符串)
100 | */
101 | - (NSMutableArray *)unSelectChannelListInSegmentMenuController:(ERSegmentMenuController *)segmentMenuController;
102 |
103 |
104 | /**
105 | 每组标题
106 |
107 | @param segmentMenuController segmentMenuController
108 | @param sectionHeaderLabel 组头Label
109 | @param section section
110 | @return title
111 | */
112 | - (NSString *)segmentMenuController:(ERSegmentMenuController *)segmentMenuController sectionHeaderLabel:(UILabel *)sectionHeaderLabel titleForHeaderInSection:(NSInteger)section;
113 |
114 | @end
115 |
116 | ```
117 |
118 | ### delegate 可以获取点击事件(双击导航条item)已经滚动事件的回调,用于自定义处理
119 |
120 | ```
121 | @protocol ERSegmentControllerDelegte
122 |
123 | @optional
124 |
125 | /**
126 | 导航按钮点击事件回调
127 |
128 | @param segmentController self
129 | @param indexPath indexPath
130 | */
131 | - (void)segmentController:(ERSegmentController *)segmentController didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
132 |
133 | /**
134 | 导航菜单编辑按钮点击回调
135 |
136 | @param segmentController self
137 | @param editMenuButton editMenuButton
138 | */
139 | - (void)segmentController:(ERSegmentController *)segmentController didSelectEditMenuButton:(UIButton *)editMenuButton;
140 | /**
141 | 导航按钮双击事件回调
142 |
143 | @param segmentController self
144 | @param indexPath indexPath
145 | */
146 | - (void)segmentController:(ERSegmentController *)segmentController itemDoubleClickAtIndexPath:(NSIndexPath *)indexPath;
147 |
148 | /**
149 | 页面切换滚动完成回调
150 |
151 | @param pageController superClass
152 | @param fromIndex fromIndex
153 | @param toIndex toIndex
154 | */
155 | - (void)pageControllerDidScroll:(ERPageViewController *)pageController fromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex;
156 |
157 | @end
158 |
159 | ```
160 |
161 |
162 |
163 | ### 参考类库/文章 (已表感谢 ! 学习并膜拜大神们 ~)
164 |
165 | [DDNews](https://github.com/iDvel/DDNews)
166 | [ZYColumnViewController](https://github.com/r9ronaldozhang/ZYColumnViewController)
167 | [LXReorderableCollectionViewFlowLayout](https://github.com/lxcid/LXReorderableCollectionViewFlowLayout)
168 | [TYPagerController](https://github.com/12207480/TYPagerController)
169 |
170 |
--------------------------------------------------------------------------------
/ERPageController/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // ERPageController
4 | //
5 | // Created by 胡广宇 on 2017/7/7.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "ERSegmentController.h"
11 |
12 | #define isIPhoneX (([UIScreen mainScreen].bounds.size.width == 375.f || [UIScreen mainScreen].bounds.size.width == 812.f) && ([UIScreen mainScreen].bounds.size.height == 375.f || [UIScreen mainScreen].bounds.size.height == 812.f) ? YES : NO)
13 | #define TabbarSafeBottomMargin (isIPhoneX ? 34.f : 0.f)
14 | #define NavigationSafeTopMargin (isIPhoneX ? 24.f : 0.f)
15 |
16 | @interface ViewController ()
17 |
18 | @property (nonatomic, strong) NSMutableArray *displayArray;
19 |
20 | @property (nonatomic, strong) NSMutableArray *unDisplayArray;
21 |
22 | @end
23 |
24 | @implementation ViewController
25 |
26 | - (void)viewDidLoad {
27 | [super viewDidLoad];
28 |
29 | [self prepareData];
30 |
31 | [self addPageController];
32 | }
33 |
34 | - (void)prepareData{
35 |
36 | NSArray *displayTitlesArry = @[@"Two",@"Two",@"Two",@"Two",@"Four",@"Four",@"Four",@"Four",@"Three",@"Three",@"Three"];
37 |
38 | self.displayArray = [NSMutableArray arrayWithCapacity:displayTitlesArry.count];
39 |
40 | for (int i = 0; i < displayTitlesArry.count; i++) {
41 | NSMutableDictionary *dic = [NSMutableDictionary dictionary];
42 | [dic setValue:displayTitlesArry[i] forKey:@"name"];
43 | [dic setValue:@(i) forKey:@"tag"];
44 | [dic setValue:[[NSClassFromString([NSString stringWithFormat:@"Page%@ViewController",displayTitlesArry[i]]) alloc] init] forKey:@"viewController"];
45 | [self.displayArray addObject:dic];
46 | }
47 |
48 | NSArray *undisplayTitlesArry = @[@"One",@"One",@"One",@"One"];
49 |
50 | self.unDisplayArray = [NSMutableArray arrayWithCapacity:undisplayTitlesArry.count];
51 |
52 | for (int i = 0; i < undisplayTitlesArry.count; i++) {
53 | NSMutableDictionary *dic = [NSMutableDictionary dictionary];
54 | [dic setValue:undisplayTitlesArry[i] forKey:@"name"];
55 | [dic setValue:@(i + displayTitlesArry.count) forKey:@"tag"];
56 | [dic setValue:[[NSClassFromString([NSString stringWithFormat:@"Page%@ViewController",undisplayTitlesArry[i]]) alloc] init] forKey:@"viewController"];
57 | [self.unDisplayArray addObject:dic];
58 | }
59 | }
60 |
61 | - (void)addPageController{
62 |
63 | ERSegmentController *pageVC = [[ERSegmentController alloc] init];
64 | pageVC.view.frame = CGRectMake(CGRectGetMinX(self.view.frame), NavigationSafeTopMargin + CGRectGetMinY(self.view.frame) + 20, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame) - 20);
65 | pageVC.segmentHeight = 25;
66 | pageVC.progressWidth = 15;
67 | pageVC.progressHeight = 1;
68 | pageVC.itemMinimumSpace = 10;
69 | pageVC.editMenuIconIgV.image = [UIImage imageNamed:@"editButtonImage"];
70 | pageVC.normalTextFont = [UIFont systemFontOfSize:12];
71 | pageVC.selectedTextFont = [UIFont systemFontOfSize:16];
72 | pageVC.normalTextColor = [UIColor blackColor];
73 | pageVC.selectedTextColor = [UIColor redColor];
74 | pageVC.delegate = self;
75 | pageVC.dataSource = self;
76 | pageVC.menuDataSource = self;
77 | [self.view addSubview:pageVC.view];
78 | [self addChildViewController:pageVC];
79 |
80 | }
81 |
82 | #pragma mark - ERSegmentMenuControllerDataSource
83 |
84 | - (NSMutableArray *)selectedChannelLisInSegmentMenuController:(ERSegmentMenuController *)segmentMenuController{
85 |
86 | return self.displayArray;
87 | }
88 |
89 | - (NSMutableArray *)unSelectChannelListInSegmentMenuController:(ERSegmentMenuController *)segmentMenuController{
90 | return self.unDisplayArray;
91 | }
92 |
93 | - (NSString *)segmentMenuController:(ERSegmentMenuController *)segmentMenuController sectionHeaderLabel:(UILabel *)sectionHeaderLabel titleForHeaderInSection:(NSInteger)section{
94 | if (!section) {
95 | sectionHeaderLabel.textColor = [UIColor redColor];
96 | return @"长按排序";
97 | }else{
98 | sectionHeaderLabel.textColor = [UIColor blackColor];
99 | return @"点击添加标签";
100 | }
101 | }
102 |
103 | #pragma mark - ERPageViewControllerDataSource
104 |
105 | - (NSInteger)numberOfControllersInPageViewController:(ERPageViewController *)pageViewController{
106 | return self.displayArray.count;
107 | }
108 |
109 | - (UIViewController *)pageViewController:(ERPageViewController *)pageViewController childControllerAtIndex:(NSInteger)index{
110 | return [self.displayArray[index] valueForKey:@"viewController"];
111 | }
112 |
113 | - (NSString *)pageViewController:(ERPageViewController *)pageViewController titleForChildControllerAtIndex:(NSInteger)index{
114 | return [NSString stringWithFormat:@"%@", [self.displayArray[index] valueForKey:@"name"]];
115 | }
116 |
117 | #pragma mark - ERSegmentControllerDelegte
118 |
119 | - (void)segmentController:(ERSegmentController *)segmentController didSelectEditMenuButton:(UIButton *)editMenuButton{
120 |
121 | CGFloat angle = editMenuButton.selected ? M_PI * 0.25 : - M_PI * 0.25;
122 | //旋转动画
123 | [UIView animateWithDuration:0.25 animations:^{
124 | segmentController.editMenuIconIgV.transform = CGAffineTransformRotate(segmentController.editMenuIconIgV.transform, angle);
125 | }];
126 | }
127 |
128 | - (void)segmentController:(ERSegmentController *)segmentController didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
129 | UIViewController *currentVC = [self.displayArray[indexPath.item] valueForKey:@"viewController"];
130 | NSLog(@"currentVC: %@ , index : %ld",currentVC,indexPath.item);
131 | }
132 |
133 | - (void)segmentController:(ERSegmentController *)segmentController itemDoubleClickAtIndexPath:(NSIndexPath *)indexPath{
134 | UIViewController *currentVC = [self.displayArray[indexPath.item] valueForKey:@"viewController"];
135 | NSLog(@"双击了,可刷新 currentVC: %@ , index : %ld",currentVC,indexPath.item);
136 | }
137 |
138 | - (void)pageControllerDidScroll:(ERPageViewController *)pageController fromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex{
139 | UIViewController *currentVC = [self.displayArray[toIndex] valueForKey:@"viewController"];
140 | NSLog(@"滚动切换 完成 currentVC: %@ , fromIndex : %ld toindex : %ld",currentVC,fromIndex,toIndex);
141 | }
142 |
143 |
144 | - (void)didReceiveMemoryWarning {
145 | [super didReceiveMemoryWarning];
146 | }
147 |
148 |
149 | @end
150 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/EditMenuControllers/ERSegmentMenuController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ERSegmentMenuController.m
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/29.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import "ERSegmentMenuController.h"
10 | #import "LXReorderableCollectionViewFlowLayout.h"
11 | #import "EditMenuCollectionViewCell.h"
12 | #import "SectionHeader.h"
13 |
14 |
15 | static NSString * const CollectionViewCellIdentifier = @"EditMenuCollectionViewCell";
16 |
17 | @interface ERSegmentMenuController ()<
18 | UICollectionViewDelegate,
19 | UICollectionViewDataSource,
20 | UICollectionViewDelegateFlowLayout
21 | >
22 |
23 | /** 选中的标签列表 */
24 | @property (nonatomic, strong) NSMutableArray *selectedChannelList;
25 | /** 未选中的标签列表 */
26 | @property (nonatomic, strong) NSMutableArray *unSelectChannelList;
27 | /** 布局视图 */
28 | @property (nonatomic, strong) UICollectionView *collectionView;
29 | @end
30 |
31 | @implementation ERSegmentMenuController
32 |
33 | - (void)viewDidLoad {
34 | [super viewDidLoad];
35 | }
36 |
37 | - (void)viewWillAppear:(BOOL)animated{
38 | [super viewWillAppear:animated];
39 | [self refreshContentData];
40 | }
41 |
42 | - (void)refreshContentData{
43 | self.selectedChannelList = [self.dataSource selectedChannelLisInSegmentMenuController:self];
44 | if ([self.dataSource respondsToSelector:@selector(unSelectChannelListInSegmentMenuController:)]) {
45 | self.unSelectChannelList = [self.dataSource unSelectChannelListInSegmentMenuController:self];
46 | }
47 | [self.collectionView reloadData];
48 | }
49 |
50 | #pragma mark - UICollectionViewDataSource
51 |
52 | - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
53 |
54 | return (self.selectedChannelList.count && self.unSelectChannelList.count) ? 2 : (self.selectedChannelList.count || self.unSelectChannelList.count);
55 | }
56 |
57 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
58 | {
59 | if (section == 0){
60 | return self.selectedChannelList.count;
61 | }else{
62 | return self.unSelectChannelList.count;
63 | }
64 | }
65 |
66 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
67 | {
68 | EditMenuCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CollectionViewCellIdentifier forIndexPath:indexPath];
69 |
70 | if (indexPath.section == 0 ) {
71 | //选中的列表
72 | [cell.channelButton setTitle:[NSString stringWithFormat:@"%@ %@",[self.selectedChannelList[indexPath.row] objectForKey:@"name"],[self.selectedChannelList[indexPath.row] objectForKey:@"tag"]] forState:UIControlStateNormal];
73 | }else{
74 | //未选中的列表
75 | [cell.channelButton setTitle:[NSString stringWithFormat:@"%@ %@",[self.unSelectChannelList[indexPath.row] objectForKey:@"name"],[self.unSelectChannelList[indexPath.row] objectForKey:@"tag"]] forState:UIControlStateNormal];
76 | }
77 |
78 | return cell;
79 | }
80 |
81 | - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{
82 |
83 | SectionHeader *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"SectionHeader" forIndexPath:indexPath];
84 |
85 | if ([self.dataSource respondsToSelector:@selector(segmentMenuController:sectionHeaderLabel:titleForHeaderInSection:)]) {
86 | header.titleLabel.text = [self.dataSource segmentMenuController:self sectionHeaderLabel:header.titleLabel titleForHeaderInSection:indexPath.section];
87 | return header;
88 | }else{
89 | if (!indexPath.section) {
90 | header.titleLabel.text = @"长按排序";
91 | }else{
92 | header.titleLabel.text = @"点击添加标签";
93 | }
94 | }
95 | return header;
96 | }
97 |
98 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
99 | if (section) {
100 | //未选中组
101 | return CGSizeMake(CGRectGetWidth(self.view.frame), 15);
102 | }
103 | //选中组
104 | return CGSizeMake(CGRectGetWidth(self.view.frame), 15 + 20);
105 | }
106 |
107 |
108 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
109 |
110 | if (indexPath.section) {
111 |
112 | NSDictionary *dic = self.unSelectChannelList[indexPath.row];
113 |
114 | [self.unSelectChannelList removeObjectAtIndex:indexPath.row];
115 |
116 | if (!self.unSelectChannelList.count) {
117 | [self.collectionView deleteSections:[NSIndexSet indexSetWithIndex:1]];
118 | }else{
119 | [self.collectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:indexPath.row inSection:1]]];
120 | }
121 |
122 | [self.selectedChannelList addObject:dic];
123 |
124 | [self.collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.selectedChannelList.count - 1 inSection:0]]];
125 |
126 | }else{
127 |
128 | if (self.selectedChannelList.count > 1) {
129 |
130 | NSDictionary *dic = self.selectedChannelList[indexPath.row];
131 |
132 | [self.selectedChannelList removeObjectAtIndex:indexPath.row];
133 |
134 | [self.collectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:indexPath.row inSection:0]]];
135 |
136 | [self.unSelectChannelList addObject:dic];
137 |
138 | if (self.unSelectChannelList.count == 1) {
139 | [self.collectionView insertSections:[NSIndexSet indexSetWithIndex:1]];
140 | }else{
141 | [self.collectionView insertItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.unSelectChannelList.count - 1 inSection:1]]];
142 | }
143 | }
144 | }
145 |
146 | [self.delegate displayChannelListDidChange];
147 | }
148 |
149 | #pragma mark LXReorderableCollectionViewDataSource
150 |
151 | /**
152 | 已经移动到toIndexPath
153 |
154 | @param collectionView collectionView
155 | @param fromIndexPath fromIndexPath
156 | @param toIndexPath toIndexPath
157 | */
158 | - (void)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath didMoveToIndexPath:(NSIndexPath *)toIndexPath{
159 | NSDictionary *dic = self.selectedChannelList[fromIndexPath.item];
160 | [self.selectedChannelList removeObjectAtIndex:fromIndexPath.row];
161 | [self.selectedChannelList insertObject:dic atIndex:toIndexPath.row];
162 | [self.delegate displayChannelListDidChange];
163 | }
164 |
165 | /**
166 | 是否可以移动
167 |
168 | @param collectionView collectionView
169 | @param indexPath indexPath
170 | @return bool
171 | */
172 | - (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath{
173 | if (indexPath.section || self.selectedChannelList.count == 1) return false;
174 | return YES;
175 | }
176 |
177 | /**
178 | 是否可以移动到某toIndexPath
179 |
180 | @param collectionView collectionView
181 | @param fromIndexPath fromIndexPath
182 | @param toIndexPath toIndexPath
183 | @return bool
184 | */
185 | - (BOOL)collectionView:(UICollectionView *)collectionView itemAtIndexPath:(NSIndexPath *)fromIndexPath canMoveToIndexPath:(NSIndexPath *)toIndexPath{
186 | if (toIndexPath.section) return false;
187 | return YES;
188 | }
189 |
190 | #pragma mark - getter/setter
191 |
192 | - (UICollectionView *)collectionView{
193 | if (!_collectionView) {
194 |
195 | LXReorderableCollectionViewFlowLayout *flowLayout = [[LXReorderableCollectionViewFlowLayout alloc] init];
196 | // 设置cell的大小和细节,每排4个
197 | CGFloat margin = 20.0;
198 | CGFloat width = (CGRectGetWidth(self.view.frame) - margin * 5) / 4.f;
199 | CGFloat height = width * 3.f / 7.f;
200 | flowLayout.sectionInset = UIEdgeInsetsMake(margin, margin, margin, margin);
201 | flowLayout.itemSize = CGSizeMake(width, height);
202 | flowLayout.minimumInteritemSpacing = margin;
203 | flowLayout.minimumLineSpacing = 20;
204 |
205 | _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
206 | _collectionView.backgroundColor = [UIColor whiteColor];
207 | _collectionView.dataSource = self;
208 | _collectionView.delegate = self;
209 | [_collectionView registerNib:[UINib nibWithNibName:@"EditMenuCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:CollectionViewCellIdentifier];
210 | [_collectionView registerClass:[SectionHeader class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"SectionHeader"];
211 | [self.view addSubview:_collectionView];
212 | }
213 | return _collectionView;
214 | }
215 |
216 | #pragma mark - viewWillLayoutSubviews
217 |
218 | - (void)viewWillLayoutSubviews{
219 | self.collectionView.frame = self.view.bounds;
220 | }
221 |
222 | - (void)didReceiveMemoryWarning {
223 | [super didReceiveMemoryWarning];
224 |
225 | }
226 | @end
227 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/PageViewControllers/ERSegmentController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ERSegmentController.m
3 | // ErHuDemo
4 | //
5 | // Created by 胡广宇 on 2017/6/27.
6 | // Copyright © 2017年 胡广宇. All rights reserved.
7 | //
8 |
9 | #import "ERSegmentController.h"
10 | #import "ERSegmentCollectionViewCell.h"
11 |
12 | static NSString *segmentCellIdentifier = @"ERSegmentCollectionViewCell";
13 |
14 | @interface ERSegmentController ()
15 |
16 | /** "导航"条 */
17 | @property (nonatomic, strong) UICollectionView *segCollectionView;
18 | /** 底部红线 */
19 | @property (nonatomic, strong) UIView *underLineView;
20 | /** 记录点击时间,用于判断双击事件 */
21 | @property (nonatomic, strong) NSDate *lastTime;
22 | /** 开始滚动时坐标 */
23 | @property (nonatomic, assign) CGFloat beginOffsetX;
24 | /** 选中状态下字体放大倍数 */
25 | @property (nonatomic, assign) CGFloat selectFontScale;
26 | /** 是否是点击item触发的滚动 */
27 | @property (nonatomic, assign) BOOL isTapItemToScroll;
28 | /** 编辑按钮 */
29 | @property (nonatomic, strong) UIButton *editMenuButton;
30 | /** 菜单控制器 */
31 | @property (nonatomic, strong) ERSegmentMenuController *menuController;
32 | /** 是否展示编辑菜单按钮 */
33 | @property (nonatomic, assign) BOOL showEditMenuButton;
34 | @end
35 |
36 | @implementation ERSegmentController
37 |
38 | - (instancetype)init {
39 | if (self = [super init]) {
40 | [self configirePropertys];
41 | }
42 | return self;
43 | }
44 |
45 |
46 | - (void)viewDidLoad {
47 | [super viewDidLoad];
48 | }
49 |
50 | #pragma mark - 初始化属性配置
51 | - (void)configirePropertys{
52 |
53 | self.showEditMenuButton = false;
54 |
55 | self.progressWidth = 20;
56 | self.progressHeight = 2;
57 | self.itemMinimumSpace = 5;
58 |
59 | self.normalTextFont = [UIFont systemFontOfSize:15];
60 | self.selectedTextFont = [UIFont systemFontOfSize:18];
61 |
62 | self.contentScrollerView.delegate = self;
63 |
64 | self.normalTextColor = [UIColor blackColor];
65 | self.selectedTextColor = [UIColor redColor];
66 | }
67 |
68 |
69 | /**
70 | 刷新数据
71 | */
72 | - (void)reloadData{
73 | [self.segCollectionView reloadData];
74 | [self reloadPageData];
75 | [self changeSegmentImmediately];
76 | }
77 |
78 | #pragma mark - 编辑菜单点击事件
79 |
80 | - (void)editMenuButtonClick:(UIButton *)btn{
81 |
82 | btn.selected = !btn.selected;
83 |
84 | if ([self.delegate respondsToSelector:@selector(segmentController:didSelectEditMenuButton:)]) {
85 | // 存在回调则自定义点击事件, 否则弹出菜单 这里按需求自行修改
86 | [self.delegate segmentController:self didSelectEditMenuButton:btn];
87 | }
88 | if (btn.selected) {
89 | [self showMenuViewController];
90 | }else{
91 | [self hideMenuViewController];
92 | }
93 | }
94 |
95 | - (void)showMenuViewController{
96 |
97 | self.segCollectionView.userInteractionEnabled = false;
98 |
99 | [UIView animateWithDuration:0.25 animations:^{
100 | self.menuController.view.frame = CGRectMake(CGRectGetMinX(self.view.frame), CGRectGetMaxY(self.segCollectionView.frame), self.view.frame.size.width, [UIScreen mainScreen].bounds.size.height - CGRectGetMaxY(self.segCollectionView.frame));
101 | [self.menuController.view layoutIfNeeded];
102 |
103 | } completion:^(BOOL finished) {
104 | self.tabBarController.tabBar.hidden = YES;
105 | }];
106 | }
107 |
108 | - (void)hideMenuViewController{
109 |
110 | self.segCollectionView.userInteractionEnabled = true;;
111 |
112 | [UIView animateWithDuration:0.25 animations:^{
113 | self.menuController.view.frame = CGRectMake(CGRectGetMinX(self.view.frame), CGRectGetMaxY(self.segCollectionView.frame), self.view.frame.size.width, 0);
114 | [self.menuController.view layoutIfNeeded];
115 | } completion:^(BOOL finished) {
116 | self.tabBarController.tabBar.hidden = false;
117 | }];
118 | }
119 |
120 | #pragma mark - UICollectionView 相关
121 |
122 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
123 | return [self.dataSource numberOfControllersInPageViewController:self];
124 | }
125 |
126 | - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
127 |
128 | ERSegmentCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:segmentCellIdentifier forIndexPath:indexPath];
129 |
130 | NSString *title = [self.dataSource pageViewController:self titleForChildControllerAtIndex:indexPath.item];
131 |
132 | cell.titleLabel.text = title;
133 |
134 | cell.titleLabel.font = self.normalTextFont;
135 |
136 | [self changeCellTextColorImmediatelyFromCell:(indexPath.item == self.currentIndex ? nil : cell) toCell:(indexPath.item == self.currentIndex ? cell : nil)];
137 |
138 | return cell;
139 | }
140 |
141 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
142 |
143 | NSString *title = [self.dataSource pageViewController:self titleForChildControllerAtIndex:indexPath.item];
144 |
145 | CGFloat width = [self boundingSizeWithString:title font:self.selectedTextFont constrainedToSize:CGSizeMake(MAXFLOAT, self.segmentHeight)].width;
146 |
147 | return CGSizeMake(width, self.segmentHeight);
148 | }
149 |
150 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
151 | NSDate *nowTime = [NSDate date];
152 | if (self.currentIndex != indexPath.item) {
153 | self.isTapItemToScroll = true;
154 | [self movePageControllerToIndex:indexPath.item];
155 | [self changeSegmentImmediately];
156 | if ([self.delegate respondsToSelector:@selector(segmentController:didSelectItemAtIndexPath:)]) {
157 | [self.delegate segmentController:self didSelectItemAtIndexPath:indexPath];
158 | }
159 | }else{
160 | if ([nowTime timeIntervalSinceDate:self.lastTime] < 0.3) {
161 | //判定为双击事件
162 | if ([self.delegate respondsToSelector:@selector(segmentController:itemDoubleClickAtIndexPath:)]) {
163 | [self.delegate segmentController:self itemDoubleClickAtIndexPath:indexPath];
164 | }
165 | }
166 | }
167 | self.lastTime = nowTime;
168 | }
169 |
170 | - (ERSegmentCollectionViewCell *)cellForIndex:(NSInteger)index
171 | {
172 | if (index >= self.countOfControllers) {
173 | return nil;
174 | }
175 | return (ERSegmentCollectionViewCell *)[self.segCollectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]];
176 | }
177 |
178 | - (CGRect)cellFrameWithIndex:(NSInteger)index
179 | {
180 | if (index >= self.countOfControllers) {
181 | return CGRectZero;
182 | }
183 | UICollectionViewLayoutAttributes * cellAttrs = [self.segCollectionView layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]];
184 | return cellAttrs.frame;
185 | }
186 |
187 | #pragma mark - UIScrollViewDelegate
188 |
189 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView{
190 | if (scrollView == self.contentScrollerView) {
191 | if (!self.isTapItemToScroll) {
192 | [self shangeSegmentProgress];
193 | }
194 | [self changeCurrentPageIndex];
195 | }
196 | }
197 |
198 | - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
199 | if (scrollView == self.contentScrollerView) {
200 | self.beginOffsetX = scrollView.contentOffset.x;
201 | }
202 | }
203 |
204 | #pragma mark - ERSegmentMenuControllerDelegate
205 |
206 | - (void)displayChannelListDidChange{
207 | [self reloadData];
208 | }
209 |
210 | #pragma mark - Item 渐变滚动动画
211 |
212 | /**
213 | 带渐变效果的改变
214 | */
215 | - (void)shangeSegmentProgress{
216 |
217 | CGFloat offsetX = self.contentScrollerView.contentOffset.x;
218 | CGFloat width = CGRectGetWidth(self.contentScrollerView.frame);
219 | CGFloat floorIndex = floor(offsetX / width);
220 | CGFloat progress = offsetX / width - floorIndex;
221 |
222 | if (floorIndex < 0 || floorIndex >= self.countOfControllers) {
223 | return;
224 | }
225 |
226 | NSInteger fromIndex = 0, toIndex = 0;
227 |
228 | if (offsetX >= self.beginOffsetX) {
229 | //左滑
230 | if (floorIndex >= self.countOfControllers - 1) {
231 | return;
232 | }
233 | fromIndex = floorIndex;
234 | toIndex = MIN(self.countOfControllers - 1, fromIndex + 1);
235 | }else {
236 | //右滑
237 | if (floorIndex < 0 ) {
238 | return;
239 | }
240 | toIndex = floorIndex;
241 | fromIndex = MIN(self.countOfControllers - 1, toIndex + 1);
242 | progress = 1.0 - progress;
243 | }
244 |
245 | [self transitionFromIndex:fromIndex toIndex:toIndex progress:progress isTapToScroller:self.isTapItemToScroll];
246 | }
247 |
248 |
249 | /**
250 | 无渐变效果的改变
251 | */
252 | - (void)changeSegmentImmediately{
253 |
254 | CGRect toCellFrame = [self cellFrameWithIndex:self.currentIndex];
255 | CGFloat progressEdging = (toCellFrame.size.width - self.progressWidth) / 2;
256 | CGFloat progressX = toCellFrame.origin.x + progressEdging;
257 | CGFloat progressY = (toCellFrame.size.height - self.progressHeight);
258 | CGFloat width = toCellFrame.size.width - 2 * progressEdging;
259 |
260 | [UIView animateWithDuration:0.25 animations:^{
261 | self.underLineView.frame = CGRectMake(progressX, progressY, width, self.progressHeight);
262 | } completion:^(BOOL finished) {
263 | self.isTapItemToScroll = false;
264 | }];
265 | }
266 |
267 | /**
268 | 判断当前页面的index
269 | */
270 | - (void)changeCurrentPageIndex{
271 |
272 | CGFloat offsetX = self.contentScrollerView.contentOffset.x;
273 | CGFloat width = CGRectGetWidth(self.contentScrollerView.frame);
274 |
275 | NSInteger index = 0;
276 |
277 | if (offsetX >= self.beginOffsetX) {
278 | index = offsetX / width;
279 | }else {
280 | index = ceil(offsetX / width);
281 | }
282 |
283 | if (index < 0) {
284 | index = 0;
285 | }else if (index >= self.countOfControllers) {
286 | index = self.countOfControllers - 1;
287 | }
288 |
289 | if (index != self.currentIndex) {
290 | NSInteger fromIndex = self.currentIndex;
291 | self.currentIndex = index;
292 | if (self.currentIndex < self.countOfControllers) {
293 | [self.segCollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:self.currentIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
294 | }
295 | if (self.isTapItemToScroll) {
296 | [self transitionFromIndex:fromIndex toIndex:self.currentIndex progress:1 isTapToScroller:self.isTapItemToScroll];
297 | }
298 |
299 | if ([self.delegate respondsToSelector:@selector(pageControllerDidScroll:fromIndex:toIndex:)]) {
300 | [self.delegate pageControllerDidScroll:self fromIndex:fromIndex toIndex:self.currentIndex];
301 | }
302 | }
303 | }
304 |
305 |
306 | /**
307 | 逐渐改变cell选中和未选中的状态
308 |
309 | @param fromIndex fromIndex
310 | @param toIndex toIndex
311 | @param progress progress
312 | @param isTapToScroller 是否是点击item触发的
313 | */
314 | - (void)transitionFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress isTapToScroller:(BOOL)isTapToScroller{
315 |
316 | ERSegmentCollectionViewCell *fromCell = [self cellForIndex:fromIndex];
317 | ERSegmentCollectionViewCell *toCell = [self cellForIndex:toIndex];
318 |
319 | if (isTapToScroller) {
320 | [self changeCellTextColorImmediatelyFromCell:fromCell toCell:toCell];
321 | }else{
322 | [self transitionCellTextColorFromCell:fromCell toCell:toCell progress:progress];
323 | [self transitionUnderLineFrameWithfromIndex:fromIndex toIndex:toIndex progress:progress];
324 | }
325 | }
326 |
327 | /**
328 | 立即改变cell选中和未选中的状态,无渐变效果
329 |
330 | @param fromCell fromCell
331 | @param toCell toCell
332 | */
333 | - (void)changeCellTextColorImmediatelyFromCell:(ERSegmentCollectionViewCell *)fromCell toCell:(ERSegmentCollectionViewCell *)toCell{
334 |
335 | if (fromCell) {
336 | fromCell.titleLabel.textColor = self.normalTextColor;
337 | fromCell.transform = CGAffineTransformMakeScale(self.selectFontScale, self.selectFontScale);
338 | }
339 |
340 | if (toCell) {
341 | toCell.titleLabel.textColor = self.selectedTextColor;
342 | toCell.transform = CGAffineTransformIdentity;
343 | }
344 | }
345 |
346 |
347 | /**
348 | 根据progress来控制Cell标题颜色的转变和Cell放大效果
349 |
350 | @param fromCell fromCell
351 | @param toCell toCell
352 | @param progress progress
353 | */
354 | - (void)transitionCellTextColorFromCell:(ERSegmentCollectionViewCell *)fromCell toCell:(ERSegmentCollectionViewCell *)toCell progress:(CGFloat)progress{
355 |
356 | CGFloat currentTransform = (1.0 - self.selectFontScale) * progress;
357 | fromCell.transform = CGAffineTransformMakeScale(1.0 - currentTransform, 1.0 - currentTransform);
358 | toCell.transform = CGAffineTransformMakeScale(self.selectFontScale + currentTransform, self.selectFontScale + currentTransform);
359 |
360 | CGFloat narR,narG,narB,narA;
361 | [self.normalTextColor getRed:&narR green:&narG blue:&narB alpha:&narA];
362 | CGFloat selR,selG,selB,selA;
363 | [self.selectedTextColor getRed:&selR green:&selG blue:&selB alpha:&selA];
364 | CGFloat detalR = narR - selR ,detalG = narG - selG,detalB = narB - selB,detalA = narA - selA;
365 |
366 | fromCell.titleLabel.textColor = [UIColor colorWithRed:selR + detalR * progress green:selG + detalG * progress blue:selB + detalB * progress alpha:selA + detalA * progress];
367 | toCell.titleLabel.textColor = [UIColor colorWithRed:narR - detalR * progress green:narG - detalG * progress blue:narB - detalB * progress alpha:narA - detalA * progress];
368 | }
369 |
370 |
371 | /**
372 | 根据progress来控制底部横线便宜
373 |
374 | @param fromIndex fromIndex
375 | @param toIndex toIndex
376 | @param progress progress
377 | */
378 | - (void)transitionUnderLineFrameWithfromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex progress:(CGFloat)progress{
379 | if (self.countOfControllers == 0) {
380 | return;
381 | }
382 |
383 | CGRect fromCellFrame = [self cellFrameWithIndex:fromIndex];
384 | CGRect toCellFrame = [self cellFrameWithIndex:toIndex];
385 |
386 | CGFloat progressFromEdging = ABS((fromCellFrame.size.width - self.progressWidth)) / 2;
387 | CGFloat progressToEdging = ABS((toCellFrame.size.width - self.progressWidth)) / 2;
388 |
389 | CGFloat progressY = (toCellFrame.size.height - self.progressHeight);
390 |
391 | CGFloat progressX, width;
392 |
393 | if (fromCellFrame.origin.x < toCellFrame.origin.x) {
394 | if (progress <= 0.5) {
395 | progressX = fromCellFrame.origin.x + progressFromEdging + (fromCellFrame.size.width - 2 * progressFromEdging) * progress;
396 | width = (toCellFrame.size.width - progressToEdging + progressFromEdging) * 2 * progress - (toCellFrame.size.width - 2 *progressToEdging) * progress + fromCellFrame.size.width - 2 * progressFromEdging - (fromCellFrame.size.width - 2 * progressFromEdging) * progress;
397 | }else {
398 | progressX = fromCellFrame.origin.x + progressFromEdging + (fromCellFrame.size.width - 2 * progressFromEdging) * 0.5 + (fromCellFrame.size.width - progressFromEdging - (fromCellFrame.size.width - 2 * progressFromEdging) * 0.5 + progressToEdging + self.itemMinimumSpace)*(progress - 0.5) * 2;
399 | width = CGRectGetMaxX(toCellFrame) - progressToEdging - progressX - (toCellFrame.size.width - 2 * progressToEdging) * ( 1 - progress);
400 | }
401 | }else {
402 | if (progress <= 0.5) {
403 | progressX = fromCellFrame.origin.x + progressFromEdging - (toCellFrame.size.width - (toCellFrame.size.width - 2 * progressToEdging) / 2 - progressToEdging + progressFromEdging) * 2 * progress;
404 | width = CGRectGetMaxX(fromCellFrame) - (fromCellFrame.size.width - 2 * progressFromEdging) * progress - progressFromEdging - progressX;
405 | }else {
406 | progressX = toCellFrame.origin.x + progressToEdging+(toCellFrame.size.width - 2 * progressToEdging) * (1 - progress);
407 | width = (fromCellFrame.size.width - progressFromEdging + progressToEdging - (fromCellFrame.size.width - 2 * progressFromEdging) / 2 ) * (1 - progress) * 2 + toCellFrame.size.width - 2 * progressToEdging - (toCellFrame.size.width - 2 * progressToEdging) * (1 - progress);
408 | }
409 | }
410 |
411 | self.underLineView.frame = CGRectMake(progressX,progressY, width, self.progressHeight);
412 | }
413 |
414 | #pragma mark - Tool 支持工具
415 |
416 | /**
417 | 获取内容大小(Item大小适配)
418 |
419 | @param string 内容
420 | @param font 字号
421 | @param size 最大size
422 | @return contentSize
423 | */
424 | - (CGSize)boundingSizeWithString:(NSString *)string font:(UIFont *)font constrainedToSize:(CGSize)size
425 | {
426 | CGSize textSize = CGSizeZero;
427 |
428 | #if (__IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0)
429 | if (![string respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
430 | textSize = [string sizeWithFont:font constrainedToSize:size lineBreakMode:NSLineBreakByWordWrapping];
431 | }
432 | else
433 | #endif
434 | {
435 | CGRect frame = [string boundingRectWithSize:size options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{ NSFontAttributeName:font} context:nil];
436 | textSize = CGSizeMake(frame.size.width, frame.size.height + 1);
437 | }
438 |
439 | return textSize;
440 | }
441 |
442 | #pragma mark - LayoutSubviews
443 |
444 | - (void)viewWillLayoutSubviews{
445 |
446 | [super viewWillLayoutSubviews];
447 |
448 | if (CGRectEqualToRect(self.segCollectionView.frame, CGRectZero)) {
449 |
450 | self.editMenuButton.frame = CGRectMake(self.showEditMenuButton ? CGRectGetMaxX(self.view.frame) - self.segmentHeight : CGRectGetMaxX(self.view.frame), 0, self.showEditMenuButton ? self.segmentHeight : 0, self.segmentHeight);
451 |
452 | self.segCollectionView.frame = CGRectMake(0, 0,CGRectGetMinX(self.editMenuButton.frame), self.segmentHeight);
453 |
454 | [self scrollViewDidScroll:self.contentScrollerView];
455 |
456 | if (self.showEditMenuButton) {
457 | self.editMenuIconIgV.frame = CGRectMake(self.segmentHeight / 4, self.segmentHeight / 4, self.segmentHeight / 2, self.segmentHeight/ 2);
458 | }
459 | }
460 | }
461 |
462 | #pragma mark - getter/setter
463 |
464 | - (void)setMenuDataSource:(id)menuDataSource{
465 | if (self.menuController.dataSource != menuDataSource) {
466 | self.menuController.dataSource = menuDataSource;
467 | if (self.menuController.dataSource) {
468 | self.showEditMenuButton = true;
469 | }
470 | }
471 | }
472 |
473 | - (ERSegmentMenuController *)menuController{
474 | if (!_menuController) {
475 | _menuController = [[ERSegmentMenuController alloc] init];
476 | _menuController.view.frame = CGRectMake(CGRectGetMinX(self.view.frame), self.segmentHeight, CGRectGetWidth(self.view.frame), 0);
477 | _menuController.dataSource = self.menuDataSource;
478 | _menuController.delegate = self;
479 | [_menuController.view layoutIfNeeded];
480 | [self addChildViewController:_menuController];
481 | [self.view addSubview:_menuController.view];
482 | }
483 | return _menuController;
484 | }
485 |
486 | - (void)setNormalTextFont:(UIFont *)normalTextFont{
487 | if (_normalTextFont.pointSize != normalTextFont.pointSize) {
488 | _normalTextFont = normalTextFont;
489 | self.selectFontScale = _normalTextFont.pointSize / self.selectedTextFont.pointSize;
490 | }
491 | }
492 |
493 | - (void)setSelectedTextFont:(UIFont *)selectedTextFont{
494 | if (_selectedTextFont.pointSize != selectedTextFont.pointSize) {
495 | _selectedTextFont = selectedTextFont;
496 | self.selectFontScale = self.normalTextFont.pointSize / _selectedTextFont.pointSize;
497 | }
498 | }
499 |
500 | - (UIButton *)editMenuButton{
501 | if (!_editMenuButton) {
502 | _editMenuButton = [UIButton buttonWithType:UIButtonTypeCustom];
503 | [_editMenuButton addTarget:self action:@selector(editMenuButtonClick:) forControlEvents:UIControlEventTouchUpInside];
504 | _editMenuButton.backgroundColor = [UIColor whiteColor];
505 | _editMenuButton.layer.shadowColor = [UIColor whiteColor].CGColor;
506 | _editMenuButton.layer.shadowRadius = self.segmentHeight / 10;
507 | _editMenuButton.layer.shadowOffset = CGSizeMake(- self.segmentHeight / 5, - 2);
508 | _editMenuButton.layer.shadowOpacity = 1;
509 | [_editMenuButton addSubview:self.editMenuIconIgV];
510 | [self.view addSubview:_editMenuButton];
511 | }
512 | return _editMenuButton;
513 | }
514 |
515 | - (UIImageView *)editMenuIconIgV{
516 | if (!_editMenuIconIgV) {
517 | _editMenuIconIgV = [[UIImageView alloc] initWithFrame:CGRectZero];
518 | _editMenuIconIgV.image = [UIImage imageNamed:@"editButtonImage"];
519 | }
520 | return _editMenuIconIgV;
521 | }
522 |
523 | - (UICollectionView *)segCollectionView{
524 | if (!_segCollectionView) {
525 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
526 | layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
527 | layout.sectionInset = UIEdgeInsetsMake(0, 5, 0, self.segmentHeight / 5);
528 | layout.minimumInteritemSpacing = self.itemMinimumSpace;
529 | _segCollectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
530 | _segCollectionView.showsHorizontalScrollIndicator = NO;
531 | _segCollectionView.showsVerticalScrollIndicator = NO;
532 | if ([_segCollectionView respondsToSelector:@selector(setPrefetchingEnabled:)]) _segCollectionView.prefetchingEnabled = NO;
533 | _segCollectionView.backgroundColor = [UIColor whiteColor];
534 | _segCollectionView.delegate = self;
535 | _segCollectionView.dataSource = self;
536 | [_segCollectionView registerNib:[UINib nibWithNibName:segmentCellIdentifier bundle:nil] forCellWithReuseIdentifier:segmentCellIdentifier];
537 | [self.view addSubview:_segCollectionView];
538 |
539 | self.underLineView = [[UIView alloc] initWithFrame:CGRectZero];
540 | self.underLineView.layer.zPosition = -1;
541 | self.underLineView.backgroundColor = self.selectedTextColor;
542 | [_segCollectionView insertSubview:self.underLineView atIndex:0];
543 | }
544 | return _segCollectionView;
545 | }
546 |
547 | - (void)didReceiveMemoryWarning {
548 | [super didReceiveMemoryWarning];
549 |
550 | }
551 |
552 | @end
553 |
--------------------------------------------------------------------------------
/ERPageController/ERPageController/EditMenuControllers/LXReorderableCollectionViewFlowLayout.m:
--------------------------------------------------------------------------------
1 | //
2 | // LXReorderableCollectionViewFlowLayout.m
3 | //
4 | // Created by Stan Chang Khin Boon on 1/10/12.
5 | // Copyright (c) 2012 d--buzz. All rights reserved.
6 | //
7 |
8 | #import "LXReorderableCollectionViewFlowLayout.h"
9 | #import
10 | #import
11 |
12 | #ifndef CGGEOMETRY_LXSUPPORT_H_
13 | CG_INLINE CGPoint
14 | LXS_CGPointAdd(CGPoint point1, CGPoint point2) {
15 | return CGPointMake(point1.x + point2.x, point1.y + point2.y);
16 | }
17 | #endif
18 |
19 | typedef NS_ENUM(NSInteger, LXScrollingDirection) {
20 | LXScrollingDirectionUnknown = 0,
21 | LXScrollingDirectionUp,
22 | LXScrollingDirectionDown,
23 | LXScrollingDirectionLeft,
24 | LXScrollingDirectionRight
25 | };
26 |
27 | static NSString * const kLXScrollingDirectionKey = @"LXScrollingDirection";
28 | static NSString * const kLXCollectionViewKeyPath = @"collectionView";
29 |
30 | @interface CADisplayLink (LX_userInfo)
31 | @property (nonatomic, copy) NSDictionary *LX_userInfo;
32 | @end
33 |
34 | @implementation CADisplayLink (LX_userInfo)
35 | - (void) setLX_userInfo:(NSDictionary *) LX_userInfo {
36 | objc_setAssociatedObject(self, "LX_userInfo", LX_userInfo, OBJC_ASSOCIATION_COPY);
37 | }
38 |
39 | - (NSDictionary *) LX_userInfo {
40 | return objc_getAssociatedObject(self, "LX_userInfo");
41 | }
42 | @end
43 |
44 | @interface UICollectionViewCell (LXReorderableCollectionViewFlowLayout)
45 |
46 | - (UIView *)LX_snapshotView;
47 |
48 | @end
49 |
50 | @implementation UICollectionViewCell (LXReorderableCollectionViewFlowLayout)
51 |
52 | - (UIView *)LX_snapshotView {
53 | if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)]) {
54 | return [self snapshotViewAfterScreenUpdates:YES];
55 | } else {
56 | UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0f);
57 | [self.layer renderInContext:UIGraphicsGetCurrentContext()];
58 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
59 | UIGraphicsEndImageContext();
60 | return [[UIImageView alloc] initWithImage:image];
61 | }
62 | }
63 |
64 | @end
65 |
66 | @interface LXReorderableCollectionViewFlowLayout ()
67 |
68 | @property (strong, nonatomic) NSIndexPath *selectedItemIndexPath;
69 | @property (strong, nonatomic) UIView *currentView;
70 | @property (assign, nonatomic) CGPoint currentViewCenter;
71 | @property (assign, nonatomic) CGPoint panTranslationInCollectionView;
72 | @property (strong, nonatomic) CADisplayLink *displayLink;
73 |
74 | @property (assign, nonatomic, readonly) id dataSource;
75 | @property (assign, nonatomic, readonly) id delegate;
76 |
77 | @end
78 |
79 | @implementation LXReorderableCollectionViewFlowLayout
80 |
81 | - (void)setDefaults {
82 | _scrollingSpeed = 300.0f;
83 | _scrollingTriggerEdgeInsets = UIEdgeInsetsMake(50.0f, 50.0f, 50.0f, 50.0f);
84 | }
85 |
86 | - (void)setupCollectionView {
87 | _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self
88 | action:@selector(handleLongPressGesture:)];
89 | _longPressGestureRecognizer.delegate = self;
90 |
91 | // Links the default long press gesture recognizer to the custom long press gesture recognizer we are creating now
92 | // by enforcing failure dependency so that they doesn't clash.
93 | for (UIGestureRecognizer *gestureRecognizer in self.collectionView.gestureRecognizers) {
94 | if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
95 | [gestureRecognizer requireGestureRecognizerToFail:_longPressGestureRecognizer];
96 | }
97 | }
98 |
99 | [self.collectionView addGestureRecognizer:_longPressGestureRecognizer];
100 |
101 | _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self
102 | action:@selector(handlePanGesture:)];
103 | _panGestureRecognizer.delegate = self;
104 | [self.collectionView addGestureRecognizer:_panGestureRecognizer];
105 |
106 | // Useful in multiple scenarios: one common scenario being when the Notification Center drawer is pulled down
107 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleApplicationWillResignActive:) name: UIApplicationWillResignActiveNotification object:nil];
108 | }
109 |
110 | - (void)tearDownCollectionView {
111 | // Tear down long press gesture
112 | if (_longPressGestureRecognizer) {
113 | UIView *view = _longPressGestureRecognizer.view;
114 | if (view) {
115 | [view removeGestureRecognizer:_longPressGestureRecognizer];
116 | }
117 | _longPressGestureRecognizer.delegate = nil;
118 | _longPressGestureRecognizer = nil;
119 | }
120 |
121 | // Tear down pan gesture
122 | if (_panGestureRecognizer) {
123 | UIView *view = _panGestureRecognizer.view;
124 | if (view) {
125 | [view removeGestureRecognizer:_panGestureRecognizer];
126 | }
127 | _panGestureRecognizer.delegate = nil;
128 | _panGestureRecognizer = nil;
129 | }
130 |
131 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
132 | }
133 |
134 | - (id)init {
135 | self = [super init];
136 | if (self) {
137 | [self setDefaults];
138 | [self addObserver:self forKeyPath:kLXCollectionViewKeyPath options:NSKeyValueObservingOptionNew context:nil];
139 | }
140 | return self;
141 | }
142 |
143 | - (id)initWithCoder:(NSCoder *)aDecoder {
144 | self = [super initWithCoder:aDecoder];
145 | if (self) {
146 | [self setDefaults];
147 | [self addObserver:self forKeyPath:kLXCollectionViewKeyPath options:NSKeyValueObservingOptionNew context:nil];
148 | }
149 | return self;
150 | }
151 |
152 | - (void)dealloc {
153 | [self invalidatesScrollTimer];
154 | [self tearDownCollectionView];
155 | [self removeObserver:self forKeyPath:kLXCollectionViewKeyPath];
156 | }
157 |
158 | - (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
159 | if ([layoutAttributes.indexPath isEqual:self.selectedItemIndexPath]) {
160 | layoutAttributes.hidden = YES;
161 | }
162 | }
163 |
164 | - (id)dataSource {
165 | return (id)self.collectionView.dataSource;
166 | }
167 |
168 | - (id)delegate {
169 | return (id)self.collectionView.delegate;
170 | }
171 |
172 | - (void)invalidateLayoutIfNecessary {
173 | NSIndexPath *newIndexPath = [self.collectionView indexPathForItemAtPoint:self.currentView.center];
174 | NSIndexPath *previousIndexPath = self.selectedItemIndexPath;
175 |
176 | if ((newIndexPath == nil) || [newIndexPath isEqual:previousIndexPath]) {
177 | return;
178 | }
179 |
180 | if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:canMoveToIndexPath:)] &&
181 | ![self.dataSource collectionView:self.collectionView itemAtIndexPath:previousIndexPath canMoveToIndexPath:newIndexPath]) {
182 | return;
183 | }
184 |
185 | self.selectedItemIndexPath = newIndexPath;
186 |
187 | if ([self.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:willMoveToIndexPath:)]) {
188 | [self.dataSource collectionView:self.collectionView itemAtIndexPath:previousIndexPath willMoveToIndexPath:newIndexPath];
189 | }
190 |
191 | __weak typeof(self) weakSelf = self;
192 | [self.collectionView performBatchUpdates:^{
193 | __strong typeof(self) strongSelf = weakSelf;
194 | if (strongSelf) {
195 | [strongSelf.collectionView deleteItemsAtIndexPaths:@[ previousIndexPath ]];
196 | [strongSelf.collectionView insertItemsAtIndexPaths:@[ newIndexPath ]];
197 | }
198 | } completion:^(BOOL finished) {
199 | __strong typeof(self) strongSelf = weakSelf;
200 | if ([strongSelf.dataSource respondsToSelector:@selector(collectionView:itemAtIndexPath:didMoveToIndexPath:)]) {
201 | [strongSelf.dataSource collectionView:strongSelf.collectionView itemAtIndexPath:previousIndexPath didMoveToIndexPath:newIndexPath];
202 | }
203 | }];
204 | }
205 |
206 | - (void)invalidatesScrollTimer {
207 | if (!self.displayLink.paused) {
208 | [self.displayLink invalidate];
209 | }
210 | self.displayLink = nil;
211 | }
212 |
213 | - (void)setupScrollTimerInDirection:(LXScrollingDirection)direction {
214 | if (!self.displayLink.paused) {
215 | LXScrollingDirection oldDirection = [self.displayLink.LX_userInfo[kLXScrollingDirectionKey] integerValue];
216 |
217 | if (direction == oldDirection) {
218 | return;
219 | }
220 | }
221 |
222 | [self invalidatesScrollTimer];
223 |
224 | self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleScroll:)];
225 | self.displayLink.LX_userInfo = @{ kLXScrollingDirectionKey : @(direction) };
226 |
227 | [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
228 | }
229 |
230 | #pragma mark - Target/Action methods
231 |
232 | // Tight loop, allocate memory sparely, even if they are stack allocation.
233 | - (void)handleScroll:(CADisplayLink *)displayLink {
234 | LXScrollingDirection direction = (LXScrollingDirection)[displayLink.LX_userInfo[kLXScrollingDirectionKey] integerValue];
235 | if (direction == LXScrollingDirectionUnknown) {
236 | return;
237 | }
238 |
239 | CGSize frameSize = self.collectionView.bounds.size;
240 | CGSize contentSize = self.collectionView.contentSize;
241 | CGPoint contentOffset = self.collectionView.contentOffset;
242 | UIEdgeInsets contentInset = self.collectionView.contentInset;
243 | // Important to have an integer `distance` as the `contentOffset` property automatically gets rounded
244 | // and it would diverge from the view's center resulting in a "cell is slipping away under finger"-bug.
245 | CGFloat distance = rint(self.scrollingSpeed * displayLink.duration);
246 | CGPoint translation = CGPointZero;
247 |
248 | switch(direction) {
249 | case LXScrollingDirectionUp: {
250 | distance = -distance;
251 | CGFloat minY = 0.0f - contentInset.top;
252 |
253 | if ((contentOffset.y + distance) <= minY) {
254 | distance = -contentOffset.y - contentInset.top;
255 | }
256 |
257 | translation = CGPointMake(0.0f, distance);
258 | } break;
259 | case LXScrollingDirectionDown: {
260 | CGFloat maxY = MAX(contentSize.height, frameSize.height) - frameSize.height + contentInset.bottom;
261 |
262 | if ((contentOffset.y + distance) >= maxY) {
263 | distance = maxY - contentOffset.y;
264 | }
265 |
266 | translation = CGPointMake(0.0f, distance);
267 | } break;
268 | case LXScrollingDirectionLeft: {
269 | distance = -distance;
270 | CGFloat minX = 0.0f - contentInset.left;
271 |
272 | if ((contentOffset.x + distance) <= minX) {
273 | distance = -contentOffset.x - contentInset.left;
274 | }
275 |
276 | translation = CGPointMake(distance, 0.0f);
277 | } break;
278 | case LXScrollingDirectionRight: {
279 | CGFloat maxX = MAX(contentSize.width, frameSize.width) - frameSize.width + contentInset.right;
280 |
281 | if ((contentOffset.x + distance) >= maxX) {
282 | distance = maxX - contentOffset.x;
283 | }
284 |
285 | translation = CGPointMake(distance, 0.0f);
286 | } break;
287 | default: {
288 | // Do nothing...
289 | } break;
290 | }
291 |
292 | self.currentViewCenter = LXS_CGPointAdd(self.currentViewCenter, translation);
293 | self.currentView.center = LXS_CGPointAdd(self.currentViewCenter, self.panTranslationInCollectionView);
294 | self.collectionView.contentOffset = LXS_CGPointAdd(contentOffset, translation);
295 | }
296 |
297 |
298 | - (void)handleLongPressGesture:(UILongPressGestureRecognizer *)gestureRecognizer {
299 | switch(gestureRecognizer.state) {
300 | case UIGestureRecognizerStateBegan: {
301 | NSIndexPath *currentIndexPath = [self.collectionView indexPathForItemAtPoint:[gestureRecognizer locationInView:self.collectionView]];
302 |
303 | if (currentIndexPath == nil) {
304 | return;
305 | }
306 |
307 | if ([self.dataSource respondsToSelector:@selector(collectionView:canMoveItemAtIndexPath:)] &&
308 | ![self.dataSource collectionView:self.collectionView canMoveItemAtIndexPath:currentIndexPath]) {
309 | return;
310 | }
311 |
312 | self.selectedItemIndexPath = currentIndexPath;
313 |
314 | if ([self.delegate respondsToSelector:@selector(collectionView:layout:willBeginDraggingItemAtIndexPath:)]) {
315 | [self.delegate collectionView:self.collectionView layout:self willBeginDraggingItemAtIndexPath:self.selectedItemIndexPath];
316 | }
317 |
318 | UICollectionViewCell *collectionViewCell = [self.collectionView cellForItemAtIndexPath:self.selectedItemIndexPath];
319 |
320 | self.currentView = [[UIView alloc] initWithFrame:collectionViewCell.frame];
321 |
322 | collectionViewCell.highlighted = YES;
323 | UIView *highlightedImageView = [collectionViewCell LX_snapshotView];
324 | highlightedImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
325 | highlightedImageView.alpha = 1.0f;
326 |
327 | collectionViewCell.highlighted = NO;
328 | UIView *imageView = [collectionViewCell LX_snapshotView];
329 | imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
330 | imageView.alpha = 0.0f;
331 |
332 | [self.currentView addSubview:imageView];
333 | [self.currentView addSubview:highlightedImageView];
334 | [self.collectionView addSubview:self.currentView];
335 |
336 | self.currentViewCenter = self.currentView.center;
337 |
338 | if ([self.delegate respondsToSelector:@selector(collectionView:layout:didBeginDraggingItemAtIndexPath:)]) {
339 | [self.delegate collectionView:self.collectionView layout:self didBeginDraggingItemAtIndexPath:self.selectedItemIndexPath];
340 | }
341 |
342 | __weak typeof(self) weakSelf = self;
343 | [UIView
344 | animateWithDuration:0.3
345 | delay:0.0
346 | options:UIViewAnimationOptionBeginFromCurrentState
347 | animations:^{
348 | __strong typeof(self) strongSelf = weakSelf;
349 | if (strongSelf) {
350 | strongSelf.currentView.transform = CGAffineTransformMakeScale(1.1f, 1.1f);
351 | highlightedImageView.alpha = 0.0f;
352 | imageView.alpha = 1.0f;
353 | }
354 | }
355 | completion:^(BOOL finished) {
356 | __strong typeof(self) strongSelf = weakSelf;
357 | if (strongSelf) {
358 | [highlightedImageView removeFromSuperview];
359 | }
360 | }];
361 |
362 | [self invalidateLayout];
363 | } break;
364 | case UIGestureRecognizerStateCancelled:
365 | case UIGestureRecognizerStateEnded: {
366 | NSIndexPath *currentIndexPath = self.selectedItemIndexPath;
367 |
368 | if (currentIndexPath) {
369 | if ([self.delegate respondsToSelector:@selector(collectionView:layout:willEndDraggingItemAtIndexPath:)]) {
370 | [self.delegate collectionView:self.collectionView layout:self willEndDraggingItemAtIndexPath:currentIndexPath];
371 | }
372 |
373 | self.selectedItemIndexPath = nil;
374 | self.currentViewCenter = CGPointZero;
375 |
376 | UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForItemAtIndexPath:currentIndexPath];
377 |
378 | self.longPressGestureRecognizer.enabled = NO;
379 |
380 | __weak typeof(self) weakSelf = self;
381 | [UIView
382 | animateWithDuration:0.3
383 | delay:0.0
384 | options:UIViewAnimationOptionBeginFromCurrentState
385 | animations:^{
386 | __strong typeof(self) strongSelf = weakSelf;
387 | if (strongSelf) {
388 | strongSelf.currentView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
389 | strongSelf.currentView.center = layoutAttributes.center;
390 | }
391 | }
392 | completion:^(BOOL finished) {
393 |
394 | self.longPressGestureRecognizer.enabled = YES;
395 |
396 | __strong typeof(self) strongSelf = weakSelf;
397 | if (strongSelf) {
398 | [strongSelf.currentView removeFromSuperview];
399 | strongSelf.currentView = nil;
400 | [strongSelf invalidateLayout];
401 |
402 | if ([strongSelf.delegate respondsToSelector:@selector(collectionView:layout:didEndDraggingItemAtIndexPath:)]) {
403 | [strongSelf.delegate collectionView:strongSelf.collectionView layout:strongSelf didEndDraggingItemAtIndexPath:currentIndexPath];
404 | }
405 | }
406 | }];
407 | }
408 | } break;
409 |
410 | default: break;
411 | }
412 | }
413 |
414 | - (void)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer {
415 | switch (gestureRecognizer.state) {
416 | case UIGestureRecognizerStateBegan:
417 | case UIGestureRecognizerStateChanged: {
418 | self.panTranslationInCollectionView = [gestureRecognizer translationInView:self.collectionView];
419 | CGPoint viewCenter = self.currentView.center = LXS_CGPointAdd(self.currentViewCenter, self.panTranslationInCollectionView);
420 |
421 | [self invalidateLayoutIfNecessary];
422 |
423 | switch (self.scrollDirection) {
424 | case UICollectionViewScrollDirectionVertical: {
425 | if (viewCenter.y < (CGRectGetMinY(self.collectionView.bounds) + self.scrollingTriggerEdgeInsets.top)) {
426 | [self setupScrollTimerInDirection:LXScrollingDirectionUp];
427 | } else {
428 | if (viewCenter.y > (CGRectGetMaxY(self.collectionView.bounds) - self.scrollingTriggerEdgeInsets.bottom)) {
429 | [self setupScrollTimerInDirection:LXScrollingDirectionDown];
430 | } else {
431 | [self invalidatesScrollTimer];
432 | }
433 | }
434 | } break;
435 | case UICollectionViewScrollDirectionHorizontal: {
436 | if (viewCenter.x < (CGRectGetMinX(self.collectionView.bounds) + self.scrollingTriggerEdgeInsets.left)) {
437 | [self setupScrollTimerInDirection:LXScrollingDirectionLeft];
438 | } else {
439 | if (viewCenter.x > (CGRectGetMaxX(self.collectionView.bounds) - self.scrollingTriggerEdgeInsets.right)) {
440 | [self setupScrollTimerInDirection:LXScrollingDirectionRight];
441 | } else {
442 | [self invalidatesScrollTimer];
443 | }
444 | }
445 | } break;
446 | }
447 | } break;
448 | case UIGestureRecognizerStateCancelled:
449 | case UIGestureRecognizerStateEnded: {
450 | [self invalidatesScrollTimer];
451 | } break;
452 | default: {
453 | // Do nothing...
454 | } break;
455 | }
456 | }
457 |
458 | #pragma mark - UICollectionViewLayout overridden methods
459 |
460 | - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
461 | NSArray *layoutAttributesForElementsInRect = [super layoutAttributesForElementsInRect:rect];
462 |
463 | for (UICollectionViewLayoutAttributes *layoutAttributes in layoutAttributesForElementsInRect) {
464 | switch (layoutAttributes.representedElementCategory) {
465 | case UICollectionElementCategoryCell: {
466 | [self applyLayoutAttributes:layoutAttributes];
467 | } break;
468 | default: {
469 | // Do nothing...
470 | } break;
471 | }
472 | }
473 |
474 | return layoutAttributesForElementsInRect;
475 | }
476 |
477 | - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
478 | UICollectionViewLayoutAttributes *layoutAttributes = [super layoutAttributesForItemAtIndexPath:indexPath];
479 |
480 | switch (layoutAttributes.representedElementCategory) {
481 | case UICollectionElementCategoryCell: {
482 | [self applyLayoutAttributes:layoutAttributes];
483 | } break;
484 | default: {
485 | // Do nothing...
486 | } break;
487 | }
488 |
489 | return layoutAttributes;
490 | }
491 |
492 | #pragma mark - UIGestureRecognizerDelegate methods
493 |
494 | - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
495 | if ([self.panGestureRecognizer isEqual:gestureRecognizer]) {
496 | return (self.selectedItemIndexPath != nil);
497 | }
498 | return YES;
499 | }
500 |
501 | - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
502 | if ([self.longPressGestureRecognizer isEqual:gestureRecognizer]) {
503 | return [self.panGestureRecognizer isEqual:otherGestureRecognizer];
504 | }
505 |
506 | if ([self.panGestureRecognizer isEqual:gestureRecognizer]) {
507 | return [self.longPressGestureRecognizer isEqual:otherGestureRecognizer];
508 | }
509 |
510 | return NO;
511 | }
512 |
513 | #pragma mark - Key-Value Observing methods
514 |
515 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
516 | if ([keyPath isEqualToString:kLXCollectionViewKeyPath]) {
517 | if (self.collectionView != nil) {
518 | [self setupCollectionView];
519 | } else {
520 | [self invalidatesScrollTimer];
521 | [self tearDownCollectionView];
522 | }
523 | }
524 | }
525 |
526 | #pragma mark - Notifications
527 |
528 | - (void)handleApplicationWillResignActive:(NSNotification *)notification {
529 | self.panGestureRecognizer.enabled = NO;
530 | self.panGestureRecognizer.enabled = YES;
531 | }
532 |
533 | #pragma mark - Depreciated methods
534 |
535 | #pragma mark Starting from 0.1.0
536 | - (void)setUpGestureRecognizersOnCollectionView {
537 | // Do nothing...
538 | }
539 |
540 | @end
541 |
--------------------------------------------------------------------------------
/ERPageController.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D85CD4861F13650700CE5640 /* EditMenuCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = D85CD4761F13650700CE5640 /* EditMenuCollectionViewCell.m */; };
11 | D85CD4871F13650700CE5640 /* EditMenuCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D85CD4771F13650700CE5640 /* EditMenuCollectionViewCell.xib */; };
12 | D85CD4881F13650700CE5640 /* ERSegmentMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = D85CD4791F13650700CE5640 /* ERSegmentMenuController.m */; };
13 | D85CD4891F13650700CE5640 /* LXReorderableCollectionViewFlowLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = D85CD47B1F13650700CE5640 /* LXReorderableCollectionViewFlowLayout.m */; };
14 | D85CD48A1F13650700CE5640 /* SectionHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = D85CD47D1F13650700CE5640 /* SectionHeader.m */; };
15 | D85CD48B1F13650700CE5640 /* ERPageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D85CD4801F13650700CE5640 /* ERPageViewController.m */; };
16 | D85CD48C1F13650700CE5640 /* ERSegmentCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = D85CD4821F13650700CE5640 /* ERSegmentCollectionViewCell.m */; };
17 | D85CD48D1F13650700CE5640 /* ERSegmentCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D85CD4831F13650700CE5640 /* ERSegmentCollectionViewCell.xib */; };
18 | D85CD48E1F13650700CE5640 /* ERSegmentController.m in Sources */ = {isa = PBXBuildFile; fileRef = D85CD4851F13650700CE5640 /* ERSegmentController.m */; };
19 | D8F7C8111F0F5E5B000DB0E7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D8F7C8101F0F5E5B000DB0E7 /* main.m */; };
20 | D8F7C8141F0F5E5B000DB0E7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D8F7C8131F0F5E5B000DB0E7 /* AppDelegate.m */; };
21 | D8F7C8171F0F5E5B000DB0E7 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D8F7C8161F0F5E5B000DB0E7 /* ViewController.m */; };
22 | D8F7C81A1F0F5E5B000DB0E7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D8F7C8181F0F5E5B000DB0E7 /* Main.storyboard */; };
23 | D8F7C81C1F0F5E5B000DB0E7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D8F7C81B1F0F5E5B000DB0E7 /* Assets.xcassets */; };
24 | D8F7C81F1F0F5E5B000DB0E7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D8F7C81D1F0F5E5B000DB0E7 /* LaunchScreen.storyboard */; };
25 | D8F7C82A1F0F5E5B000DB0E7 /* ERPageControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D8F7C8291F0F5E5B000DB0E7 /* ERPageControllerTests.m */; };
26 | D8F7C8351F0F5E5B000DB0E7 /* ERPageControllerUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = D8F7C8341F0F5E5B000DB0E7 /* ERPageControllerUITests.m */; };
27 | D8F7C8661F0F60B8000DB0E7 /* PageFourViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D8F7C85F1F0F60B8000DB0E7 /* PageFourViewController.m */; };
28 | D8F7C8671F0F60B8000DB0E7 /* PageOneViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D8F7C8611F0F60B8000DB0E7 /* PageOneViewController.m */; };
29 | D8F7C8681F0F60B8000DB0E7 /* PageThreeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D8F7C8631F0F60B8000DB0E7 /* PageThreeViewController.m */; };
30 | D8F7C8691F0F60B8000DB0E7 /* PageTwoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D8F7C8651F0F60B8000DB0E7 /* PageTwoViewController.m */; };
31 | /* End PBXBuildFile section */
32 |
33 | /* Begin PBXContainerItemProxy section */
34 | D8F7C8261F0F5E5B000DB0E7 /* PBXContainerItemProxy */ = {
35 | isa = PBXContainerItemProxy;
36 | containerPortal = D8F7C8041F0F5E5B000DB0E7 /* Project object */;
37 | proxyType = 1;
38 | remoteGlobalIDString = D8F7C80B1F0F5E5B000DB0E7;
39 | remoteInfo = ERPageController;
40 | };
41 | D8F7C8311F0F5E5B000DB0E7 /* PBXContainerItemProxy */ = {
42 | isa = PBXContainerItemProxy;
43 | containerPortal = D8F7C8041F0F5E5B000DB0E7 /* Project object */;
44 | proxyType = 1;
45 | remoteGlobalIDString = D8F7C80B1F0F5E5B000DB0E7;
46 | remoteInfo = ERPageController;
47 | };
48 | /* End PBXContainerItemProxy section */
49 |
50 | /* Begin PBXFileReference section */
51 | D85CD4751F13650700CE5640 /* EditMenuCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditMenuCollectionViewCell.h; sourceTree = ""; };
52 | D85CD4761F13650700CE5640 /* EditMenuCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EditMenuCollectionViewCell.m; sourceTree = ""; };
53 | D85CD4771F13650700CE5640 /* EditMenuCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EditMenuCollectionViewCell.xib; sourceTree = ""; };
54 | D85CD4781F13650700CE5640 /* ERSegmentMenuController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ERSegmentMenuController.h; sourceTree = ""; };
55 | D85CD4791F13650700CE5640 /* ERSegmentMenuController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ERSegmentMenuController.m; sourceTree = ""; };
56 | D85CD47A1F13650700CE5640 /* LXReorderableCollectionViewFlowLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LXReorderableCollectionViewFlowLayout.h; sourceTree = ""; };
57 | D85CD47B1F13650700CE5640 /* LXReorderableCollectionViewFlowLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LXReorderableCollectionViewFlowLayout.m; sourceTree = ""; };
58 | D85CD47C1F13650700CE5640 /* SectionHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SectionHeader.h; sourceTree = ""; };
59 | D85CD47D1F13650700CE5640 /* SectionHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SectionHeader.m; sourceTree = ""; };
60 | D85CD47F1F13650700CE5640 /* ERPageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ERPageViewController.h; sourceTree = ""; };
61 | D85CD4801F13650700CE5640 /* ERPageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ERPageViewController.m; sourceTree = ""; };
62 | D85CD4811F13650700CE5640 /* ERSegmentCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ERSegmentCollectionViewCell.h; sourceTree = ""; };
63 | D85CD4821F13650700CE5640 /* ERSegmentCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ERSegmentCollectionViewCell.m; sourceTree = ""; };
64 | D85CD4831F13650700CE5640 /* ERSegmentCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ERSegmentCollectionViewCell.xib; sourceTree = ""; };
65 | D85CD4841F13650700CE5640 /* ERSegmentController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ERSegmentController.h; sourceTree = ""; };
66 | D85CD4851F13650700CE5640 /* ERSegmentController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ERSegmentController.m; sourceTree = ""; };
67 | D8F7C80C1F0F5E5B000DB0E7 /* ERPageController.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ERPageController.app; sourceTree = BUILT_PRODUCTS_DIR; };
68 | D8F7C8101F0F5E5B000DB0E7 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
69 | D8F7C8121F0F5E5B000DB0E7 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
70 | D8F7C8131F0F5E5B000DB0E7 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
71 | D8F7C8151F0F5E5B000DB0E7 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
72 | D8F7C8161F0F5E5B000DB0E7 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
73 | D8F7C8191F0F5E5B000DB0E7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
74 | D8F7C81B1F0F5E5B000DB0E7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
75 | D8F7C81E1F0F5E5B000DB0E7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
76 | D8F7C8201F0F5E5B000DB0E7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
77 | D8F7C8251F0F5E5B000DB0E7 /* ERPageControllerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ERPageControllerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
78 | D8F7C8291F0F5E5B000DB0E7 /* ERPageControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ERPageControllerTests.m; sourceTree = ""; };
79 | D8F7C82B1F0F5E5B000DB0E7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
80 | D8F7C8301F0F5E5B000DB0E7 /* ERPageControllerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ERPageControllerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
81 | D8F7C8341F0F5E5B000DB0E7 /* ERPageControllerUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ERPageControllerUITests.m; sourceTree = ""; };
82 | D8F7C8361F0F5E5B000DB0E7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
83 | D8F7C85E1F0F60B8000DB0E7 /* PageFourViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageFourViewController.h; sourceTree = ""; };
84 | D8F7C85F1F0F60B8000DB0E7 /* PageFourViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PageFourViewController.m; sourceTree = ""; };
85 | D8F7C8601F0F60B8000DB0E7 /* PageOneViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageOneViewController.h; sourceTree = ""; };
86 | D8F7C8611F0F60B8000DB0E7 /* PageOneViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PageOneViewController.m; sourceTree = ""; };
87 | D8F7C8621F0F60B8000DB0E7 /* PageThreeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageThreeViewController.h; sourceTree = ""; };
88 | D8F7C8631F0F60B8000DB0E7 /* PageThreeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PageThreeViewController.m; sourceTree = ""; };
89 | D8F7C8641F0F60B8000DB0E7 /* PageTwoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageTwoViewController.h; sourceTree = ""; };
90 | D8F7C8651F0F60B8000DB0E7 /* PageTwoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PageTwoViewController.m; sourceTree = ""; };
91 | /* End PBXFileReference section */
92 |
93 | /* Begin PBXFrameworksBuildPhase section */
94 | D8F7C8091F0F5E5B000DB0E7 /* Frameworks */ = {
95 | isa = PBXFrameworksBuildPhase;
96 | buildActionMask = 2147483647;
97 | files = (
98 | );
99 | runOnlyForDeploymentPostprocessing = 0;
100 | };
101 | D8F7C8221F0F5E5B000DB0E7 /* Frameworks */ = {
102 | isa = PBXFrameworksBuildPhase;
103 | buildActionMask = 2147483647;
104 | files = (
105 | );
106 | runOnlyForDeploymentPostprocessing = 0;
107 | };
108 | D8F7C82D1F0F5E5B000DB0E7 /* Frameworks */ = {
109 | isa = PBXFrameworksBuildPhase;
110 | buildActionMask = 2147483647;
111 | files = (
112 | );
113 | runOnlyForDeploymentPostprocessing = 0;
114 | };
115 | /* End PBXFrameworksBuildPhase section */
116 |
117 | /* Begin PBXGroup section */
118 | D85CD4731F13650700CE5640 /* ERPageController */ = {
119 | isa = PBXGroup;
120 | children = (
121 | D85CD4741F13650700CE5640 /* EditMenuControllers */,
122 | D85CD47E1F13650700CE5640 /* PageViewControllers */,
123 | );
124 | path = ERPageController;
125 | sourceTree = "";
126 | };
127 | D85CD4741F13650700CE5640 /* EditMenuControllers */ = {
128 | isa = PBXGroup;
129 | children = (
130 | D85CD4751F13650700CE5640 /* EditMenuCollectionViewCell.h */,
131 | D85CD4761F13650700CE5640 /* EditMenuCollectionViewCell.m */,
132 | D85CD4771F13650700CE5640 /* EditMenuCollectionViewCell.xib */,
133 | D85CD4781F13650700CE5640 /* ERSegmentMenuController.h */,
134 | D85CD4791F13650700CE5640 /* ERSegmentMenuController.m */,
135 | D85CD47A1F13650700CE5640 /* LXReorderableCollectionViewFlowLayout.h */,
136 | D85CD47B1F13650700CE5640 /* LXReorderableCollectionViewFlowLayout.m */,
137 | D85CD47C1F13650700CE5640 /* SectionHeader.h */,
138 | D85CD47D1F13650700CE5640 /* SectionHeader.m */,
139 | );
140 | path = EditMenuControllers;
141 | sourceTree = "";
142 | };
143 | D85CD47E1F13650700CE5640 /* PageViewControllers */ = {
144 | isa = PBXGroup;
145 | children = (
146 | D85CD47F1F13650700CE5640 /* ERPageViewController.h */,
147 | D85CD4801F13650700CE5640 /* ERPageViewController.m */,
148 | D85CD4811F13650700CE5640 /* ERSegmentCollectionViewCell.h */,
149 | D85CD4821F13650700CE5640 /* ERSegmentCollectionViewCell.m */,
150 | D85CD4831F13650700CE5640 /* ERSegmentCollectionViewCell.xib */,
151 | D85CD4841F13650700CE5640 /* ERSegmentController.h */,
152 | D85CD4851F13650700CE5640 /* ERSegmentController.m */,
153 | );
154 | path = PageViewControllers;
155 | sourceTree = "";
156 | };
157 | D8F7C8031F0F5E5B000DB0E7 = {
158 | isa = PBXGroup;
159 | children = (
160 | D8F7C80E1F0F5E5B000DB0E7 /* ERPageController */,
161 | D8F7C8281F0F5E5B000DB0E7 /* ERPageControllerTests */,
162 | D8F7C8331F0F5E5B000DB0E7 /* ERPageControllerUITests */,
163 | D8F7C80D1F0F5E5B000DB0E7 /* Products */,
164 | );
165 | sourceTree = "";
166 | };
167 | D8F7C80D1F0F5E5B000DB0E7 /* Products */ = {
168 | isa = PBXGroup;
169 | children = (
170 | D8F7C80C1F0F5E5B000DB0E7 /* ERPageController.app */,
171 | D8F7C8251F0F5E5B000DB0E7 /* ERPageControllerTests.xctest */,
172 | D8F7C8301F0F5E5B000DB0E7 /* ERPageControllerUITests.xctest */,
173 | );
174 | name = Products;
175 | sourceTree = "";
176 | };
177 | D8F7C80E1F0F5E5B000DB0E7 /* ERPageController */ = {
178 | isa = PBXGroup;
179 | children = (
180 | D85CD4731F13650700CE5640 /* ERPageController */,
181 | D8F7C8121F0F5E5B000DB0E7 /* AppDelegate.h */,
182 | D8F7C8131F0F5E5B000DB0E7 /* AppDelegate.m */,
183 | D8F7C8151F0F5E5B000DB0E7 /* ViewController.h */,
184 | D8F7C8161F0F5E5B000DB0E7 /* ViewController.m */,
185 | D8F7C85E1F0F60B8000DB0E7 /* PageFourViewController.h */,
186 | D8F7C85F1F0F60B8000DB0E7 /* PageFourViewController.m */,
187 | D8F7C8601F0F60B8000DB0E7 /* PageOneViewController.h */,
188 | D8F7C8611F0F60B8000DB0E7 /* PageOneViewController.m */,
189 | D8F7C8621F0F60B8000DB0E7 /* PageThreeViewController.h */,
190 | D8F7C8631F0F60B8000DB0E7 /* PageThreeViewController.m */,
191 | D8F7C8641F0F60B8000DB0E7 /* PageTwoViewController.h */,
192 | D8F7C8651F0F60B8000DB0E7 /* PageTwoViewController.m */,
193 | D8F7C8181F0F5E5B000DB0E7 /* Main.storyboard */,
194 | D8F7C81B1F0F5E5B000DB0E7 /* Assets.xcassets */,
195 | D8F7C81D1F0F5E5B000DB0E7 /* LaunchScreen.storyboard */,
196 | D8F7C8201F0F5E5B000DB0E7 /* Info.plist */,
197 | D8F7C80F1F0F5E5B000DB0E7 /* Supporting Files */,
198 | );
199 | path = ERPageController;
200 | sourceTree = "";
201 | };
202 | D8F7C80F1F0F5E5B000DB0E7 /* Supporting Files */ = {
203 | isa = PBXGroup;
204 | children = (
205 | D8F7C8101F0F5E5B000DB0E7 /* main.m */,
206 | );
207 | name = "Supporting Files";
208 | sourceTree = "";
209 | };
210 | D8F7C8281F0F5E5B000DB0E7 /* ERPageControllerTests */ = {
211 | isa = PBXGroup;
212 | children = (
213 | D8F7C8291F0F5E5B000DB0E7 /* ERPageControllerTests.m */,
214 | D8F7C82B1F0F5E5B000DB0E7 /* Info.plist */,
215 | );
216 | path = ERPageControllerTests;
217 | sourceTree = "";
218 | };
219 | D8F7C8331F0F5E5B000DB0E7 /* ERPageControllerUITests */ = {
220 | isa = PBXGroup;
221 | children = (
222 | D8F7C8341F0F5E5B000DB0E7 /* ERPageControllerUITests.m */,
223 | D8F7C8361F0F5E5B000DB0E7 /* Info.plist */,
224 | );
225 | path = ERPageControllerUITests;
226 | sourceTree = "";
227 | };
228 | /* End PBXGroup section */
229 |
230 | /* Begin PBXNativeTarget section */
231 | D8F7C80B1F0F5E5B000DB0E7 /* ERPageController */ = {
232 | isa = PBXNativeTarget;
233 | buildConfigurationList = D8F7C8391F0F5E5B000DB0E7 /* Build configuration list for PBXNativeTarget "ERPageController" */;
234 | buildPhases = (
235 | D8F7C8081F0F5E5B000DB0E7 /* Sources */,
236 | D8F7C8091F0F5E5B000DB0E7 /* Frameworks */,
237 | D8F7C80A1F0F5E5B000DB0E7 /* Resources */,
238 | );
239 | buildRules = (
240 | );
241 | dependencies = (
242 | );
243 | name = ERPageController;
244 | productName = ERPageController;
245 | productReference = D8F7C80C1F0F5E5B000DB0E7 /* ERPageController.app */;
246 | productType = "com.apple.product-type.application";
247 | };
248 | D8F7C8241F0F5E5B000DB0E7 /* ERPageControllerTests */ = {
249 | isa = PBXNativeTarget;
250 | buildConfigurationList = D8F7C83C1F0F5E5B000DB0E7 /* Build configuration list for PBXNativeTarget "ERPageControllerTests" */;
251 | buildPhases = (
252 | D8F7C8211F0F5E5B000DB0E7 /* Sources */,
253 | D8F7C8221F0F5E5B000DB0E7 /* Frameworks */,
254 | D8F7C8231F0F5E5B000DB0E7 /* Resources */,
255 | );
256 | buildRules = (
257 | );
258 | dependencies = (
259 | D8F7C8271F0F5E5B000DB0E7 /* PBXTargetDependency */,
260 | );
261 | name = ERPageControllerTests;
262 | productName = ERPageControllerTests;
263 | productReference = D8F7C8251F0F5E5B000DB0E7 /* ERPageControllerTests.xctest */;
264 | productType = "com.apple.product-type.bundle.unit-test";
265 | };
266 | D8F7C82F1F0F5E5B000DB0E7 /* ERPageControllerUITests */ = {
267 | isa = PBXNativeTarget;
268 | buildConfigurationList = D8F7C83F1F0F5E5B000DB0E7 /* Build configuration list for PBXNativeTarget "ERPageControllerUITests" */;
269 | buildPhases = (
270 | D8F7C82C1F0F5E5B000DB0E7 /* Sources */,
271 | D8F7C82D1F0F5E5B000DB0E7 /* Frameworks */,
272 | D8F7C82E1F0F5E5B000DB0E7 /* Resources */,
273 | );
274 | buildRules = (
275 | );
276 | dependencies = (
277 | D8F7C8321F0F5E5B000DB0E7 /* PBXTargetDependency */,
278 | );
279 | name = ERPageControllerUITests;
280 | productName = ERPageControllerUITests;
281 | productReference = D8F7C8301F0F5E5B000DB0E7 /* ERPageControllerUITests.xctest */;
282 | productType = "com.apple.product-type.bundle.ui-testing";
283 | };
284 | /* End PBXNativeTarget section */
285 |
286 | /* Begin PBXProject section */
287 | D8F7C8041F0F5E5B000DB0E7 /* Project object */ = {
288 | isa = PBXProject;
289 | attributes = {
290 | LastUpgradeCheck = 0830;
291 | ORGANIZATIONNAME = "胡广宇";
292 | TargetAttributes = {
293 | D8F7C80B1F0F5E5B000DB0E7 = {
294 | CreatedOnToolsVersion = 8.3.3;
295 | DevelopmentTeam = 7W6345K7JN;
296 | ProvisioningStyle = Automatic;
297 | };
298 | D8F7C8241F0F5E5B000DB0E7 = {
299 | CreatedOnToolsVersion = 8.3.3;
300 | DevelopmentTeam = 7W6345K7JN;
301 | ProvisioningStyle = Automatic;
302 | TestTargetID = D8F7C80B1F0F5E5B000DB0E7;
303 | };
304 | D8F7C82F1F0F5E5B000DB0E7 = {
305 | CreatedOnToolsVersion = 8.3.3;
306 | DevelopmentTeam = 7W6345K7JN;
307 | ProvisioningStyle = Automatic;
308 | TestTargetID = D8F7C80B1F0F5E5B000DB0E7;
309 | };
310 | };
311 | };
312 | buildConfigurationList = D8F7C8071F0F5E5B000DB0E7 /* Build configuration list for PBXProject "ERPageController" */;
313 | compatibilityVersion = "Xcode 3.2";
314 | developmentRegion = English;
315 | hasScannedForEncodings = 0;
316 | knownRegions = (
317 | en,
318 | Base,
319 | );
320 | mainGroup = D8F7C8031F0F5E5B000DB0E7;
321 | productRefGroup = D8F7C80D1F0F5E5B000DB0E7 /* Products */;
322 | projectDirPath = "";
323 | projectRoot = "";
324 | targets = (
325 | D8F7C80B1F0F5E5B000DB0E7 /* ERPageController */,
326 | D8F7C8241F0F5E5B000DB0E7 /* ERPageControllerTests */,
327 | D8F7C82F1F0F5E5B000DB0E7 /* ERPageControllerUITests */,
328 | );
329 | };
330 | /* End PBXProject section */
331 |
332 | /* Begin PBXResourcesBuildPhase section */
333 | D8F7C80A1F0F5E5B000DB0E7 /* Resources */ = {
334 | isa = PBXResourcesBuildPhase;
335 | buildActionMask = 2147483647;
336 | files = (
337 | D8F7C81F1F0F5E5B000DB0E7 /* LaunchScreen.storyboard in Resources */,
338 | D85CD48D1F13650700CE5640 /* ERSegmentCollectionViewCell.xib in Resources */,
339 | D85CD4871F13650700CE5640 /* EditMenuCollectionViewCell.xib in Resources */,
340 | D8F7C81C1F0F5E5B000DB0E7 /* Assets.xcassets in Resources */,
341 | D8F7C81A1F0F5E5B000DB0E7 /* Main.storyboard in Resources */,
342 | );
343 | runOnlyForDeploymentPostprocessing = 0;
344 | };
345 | D8F7C8231F0F5E5B000DB0E7 /* Resources */ = {
346 | isa = PBXResourcesBuildPhase;
347 | buildActionMask = 2147483647;
348 | files = (
349 | );
350 | runOnlyForDeploymentPostprocessing = 0;
351 | };
352 | D8F7C82E1F0F5E5B000DB0E7 /* Resources */ = {
353 | isa = PBXResourcesBuildPhase;
354 | buildActionMask = 2147483647;
355 | files = (
356 | );
357 | runOnlyForDeploymentPostprocessing = 0;
358 | };
359 | /* End PBXResourcesBuildPhase section */
360 |
361 | /* Begin PBXSourcesBuildPhase section */
362 | D8F7C8081F0F5E5B000DB0E7 /* Sources */ = {
363 | isa = PBXSourcesBuildPhase;
364 | buildActionMask = 2147483647;
365 | files = (
366 | D85CD4891F13650700CE5640 /* LXReorderableCollectionViewFlowLayout.m in Sources */,
367 | D8F7C8661F0F60B8000DB0E7 /* PageFourViewController.m in Sources */,
368 | D85CD4861F13650700CE5640 /* EditMenuCollectionViewCell.m in Sources */,
369 | D85CD48A1F13650700CE5640 /* SectionHeader.m in Sources */,
370 | D85CD48C1F13650700CE5640 /* ERSegmentCollectionViewCell.m in Sources */,
371 | D8F7C8171F0F5E5B000DB0E7 /* ViewController.m in Sources */,
372 | D8F7C8671F0F60B8000DB0E7 /* PageOneViewController.m in Sources */,
373 | D8F7C8691F0F60B8000DB0E7 /* PageTwoViewController.m in Sources */,
374 | D8F7C8681F0F60B8000DB0E7 /* PageThreeViewController.m in Sources */,
375 | D85CD48B1F13650700CE5640 /* ERPageViewController.m in Sources */,
376 | D85CD4881F13650700CE5640 /* ERSegmentMenuController.m in Sources */,
377 | D8F7C8141F0F5E5B000DB0E7 /* AppDelegate.m in Sources */,
378 | D85CD48E1F13650700CE5640 /* ERSegmentController.m in Sources */,
379 | D8F7C8111F0F5E5B000DB0E7 /* main.m in Sources */,
380 | );
381 | runOnlyForDeploymentPostprocessing = 0;
382 | };
383 | D8F7C8211F0F5E5B000DB0E7 /* Sources */ = {
384 | isa = PBXSourcesBuildPhase;
385 | buildActionMask = 2147483647;
386 | files = (
387 | D8F7C82A1F0F5E5B000DB0E7 /* ERPageControllerTests.m in Sources */,
388 | );
389 | runOnlyForDeploymentPostprocessing = 0;
390 | };
391 | D8F7C82C1F0F5E5B000DB0E7 /* Sources */ = {
392 | isa = PBXSourcesBuildPhase;
393 | buildActionMask = 2147483647;
394 | files = (
395 | D8F7C8351F0F5E5B000DB0E7 /* ERPageControllerUITests.m in Sources */,
396 | );
397 | runOnlyForDeploymentPostprocessing = 0;
398 | };
399 | /* End PBXSourcesBuildPhase section */
400 |
401 | /* Begin PBXTargetDependency section */
402 | D8F7C8271F0F5E5B000DB0E7 /* PBXTargetDependency */ = {
403 | isa = PBXTargetDependency;
404 | target = D8F7C80B1F0F5E5B000DB0E7 /* ERPageController */;
405 | targetProxy = D8F7C8261F0F5E5B000DB0E7 /* PBXContainerItemProxy */;
406 | };
407 | D8F7C8321F0F5E5B000DB0E7 /* PBXTargetDependency */ = {
408 | isa = PBXTargetDependency;
409 | target = D8F7C80B1F0F5E5B000DB0E7 /* ERPageController */;
410 | targetProxy = D8F7C8311F0F5E5B000DB0E7 /* PBXContainerItemProxy */;
411 | };
412 | /* End PBXTargetDependency section */
413 |
414 | /* Begin PBXVariantGroup section */
415 | D8F7C8181F0F5E5B000DB0E7 /* Main.storyboard */ = {
416 | isa = PBXVariantGroup;
417 | children = (
418 | D8F7C8191F0F5E5B000DB0E7 /* Base */,
419 | );
420 | name = Main.storyboard;
421 | sourceTree = "";
422 | };
423 | D8F7C81D1F0F5E5B000DB0E7 /* LaunchScreen.storyboard */ = {
424 | isa = PBXVariantGroup;
425 | children = (
426 | D8F7C81E1F0F5E5B000DB0E7 /* Base */,
427 | );
428 | name = LaunchScreen.storyboard;
429 | sourceTree = "";
430 | };
431 | /* End PBXVariantGroup section */
432 |
433 | /* Begin XCBuildConfiguration section */
434 | D8F7C8371F0F5E5B000DB0E7 /* Debug */ = {
435 | isa = XCBuildConfiguration;
436 | buildSettings = {
437 | ALWAYS_SEARCH_USER_PATHS = NO;
438 | CLANG_ANALYZER_NONNULL = YES;
439 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
440 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
441 | CLANG_CXX_LIBRARY = "libc++";
442 | CLANG_ENABLE_MODULES = YES;
443 | CLANG_ENABLE_OBJC_ARC = YES;
444 | CLANG_WARN_BOOL_CONVERSION = YES;
445 | CLANG_WARN_CONSTANT_CONVERSION = YES;
446 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
447 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
448 | CLANG_WARN_EMPTY_BODY = YES;
449 | CLANG_WARN_ENUM_CONVERSION = YES;
450 | CLANG_WARN_INFINITE_RECURSION = YES;
451 | CLANG_WARN_INT_CONVERSION = YES;
452 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
453 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
454 | CLANG_WARN_UNREACHABLE_CODE = YES;
455 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
456 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
457 | COPY_PHASE_STRIP = NO;
458 | DEBUG_INFORMATION_FORMAT = dwarf;
459 | ENABLE_STRICT_OBJC_MSGSEND = YES;
460 | ENABLE_TESTABILITY = YES;
461 | GCC_C_LANGUAGE_STANDARD = gnu99;
462 | GCC_DYNAMIC_NO_PIC = NO;
463 | GCC_NO_COMMON_BLOCKS = YES;
464 | GCC_OPTIMIZATION_LEVEL = 0;
465 | GCC_PREPROCESSOR_DEFINITIONS = (
466 | "DEBUG=1",
467 | "$(inherited)",
468 | );
469 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
470 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
471 | GCC_WARN_UNDECLARED_SELECTOR = YES;
472 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
473 | GCC_WARN_UNUSED_FUNCTION = YES;
474 | GCC_WARN_UNUSED_VARIABLE = YES;
475 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
476 | MTL_ENABLE_DEBUG_INFO = YES;
477 | ONLY_ACTIVE_ARCH = YES;
478 | SDKROOT = iphoneos;
479 | TARGETED_DEVICE_FAMILY = "1,2";
480 | };
481 | name = Debug;
482 | };
483 | D8F7C8381F0F5E5B000DB0E7 /* Release */ = {
484 | isa = XCBuildConfiguration;
485 | buildSettings = {
486 | ALWAYS_SEARCH_USER_PATHS = NO;
487 | CLANG_ANALYZER_NONNULL = YES;
488 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
489 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
490 | CLANG_CXX_LIBRARY = "libc++";
491 | CLANG_ENABLE_MODULES = YES;
492 | CLANG_ENABLE_OBJC_ARC = YES;
493 | CLANG_WARN_BOOL_CONVERSION = YES;
494 | CLANG_WARN_CONSTANT_CONVERSION = YES;
495 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
496 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
497 | CLANG_WARN_EMPTY_BODY = YES;
498 | CLANG_WARN_ENUM_CONVERSION = YES;
499 | CLANG_WARN_INFINITE_RECURSION = YES;
500 | CLANG_WARN_INT_CONVERSION = YES;
501 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
502 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
503 | CLANG_WARN_UNREACHABLE_CODE = YES;
504 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
505 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
506 | COPY_PHASE_STRIP = NO;
507 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
508 | ENABLE_NS_ASSERTIONS = NO;
509 | ENABLE_STRICT_OBJC_MSGSEND = YES;
510 | GCC_C_LANGUAGE_STANDARD = gnu99;
511 | GCC_NO_COMMON_BLOCKS = YES;
512 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
513 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
514 | GCC_WARN_UNDECLARED_SELECTOR = YES;
515 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
516 | GCC_WARN_UNUSED_FUNCTION = YES;
517 | GCC_WARN_UNUSED_VARIABLE = YES;
518 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
519 | MTL_ENABLE_DEBUG_INFO = NO;
520 | SDKROOT = iphoneos;
521 | TARGETED_DEVICE_FAMILY = "1,2";
522 | VALIDATE_PRODUCT = YES;
523 | };
524 | name = Release;
525 | };
526 | D8F7C83A1F0F5E5B000DB0E7 /* Debug */ = {
527 | isa = XCBuildConfiguration;
528 | buildSettings = {
529 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
530 | DEVELOPMENT_TEAM = 7W6345K7JN;
531 | INFOPLIST_FILE = ERPageController/Info.plist;
532 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
533 | PRODUCT_BUNDLE_IDENTIFIER = com.erhu.ERPageController;
534 | PRODUCT_NAME = "$(TARGET_NAME)";
535 | };
536 | name = Debug;
537 | };
538 | D8F7C83B1F0F5E5B000DB0E7 /* Release */ = {
539 | isa = XCBuildConfiguration;
540 | buildSettings = {
541 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
542 | DEVELOPMENT_TEAM = 7W6345K7JN;
543 | INFOPLIST_FILE = ERPageController/Info.plist;
544 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
545 | PRODUCT_BUNDLE_IDENTIFIER = com.erhu.ERPageController;
546 | PRODUCT_NAME = "$(TARGET_NAME)";
547 | };
548 | name = Release;
549 | };
550 | D8F7C83D1F0F5E5B000DB0E7 /* Debug */ = {
551 | isa = XCBuildConfiguration;
552 | buildSettings = {
553 | BUNDLE_LOADER = "$(TEST_HOST)";
554 | DEVELOPMENT_TEAM = 7W6345K7JN;
555 | INFOPLIST_FILE = ERPageControllerTests/Info.plist;
556 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
557 | PRODUCT_BUNDLE_IDENTIFIER = com.erhu.ERPageControllerTests;
558 | PRODUCT_NAME = "$(TARGET_NAME)";
559 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ERPageController.app/ERPageController";
560 | };
561 | name = Debug;
562 | };
563 | D8F7C83E1F0F5E5B000DB0E7 /* Release */ = {
564 | isa = XCBuildConfiguration;
565 | buildSettings = {
566 | BUNDLE_LOADER = "$(TEST_HOST)";
567 | DEVELOPMENT_TEAM = 7W6345K7JN;
568 | INFOPLIST_FILE = ERPageControllerTests/Info.plist;
569 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
570 | PRODUCT_BUNDLE_IDENTIFIER = com.erhu.ERPageControllerTests;
571 | PRODUCT_NAME = "$(TARGET_NAME)";
572 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ERPageController.app/ERPageController";
573 | };
574 | name = Release;
575 | };
576 | D8F7C8401F0F5E5B000DB0E7 /* Debug */ = {
577 | isa = XCBuildConfiguration;
578 | buildSettings = {
579 | DEVELOPMENT_TEAM = 7W6345K7JN;
580 | INFOPLIST_FILE = ERPageControllerUITests/Info.plist;
581 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
582 | PRODUCT_BUNDLE_IDENTIFIER = com.erhu.ERPageControllerUITests;
583 | PRODUCT_NAME = "$(TARGET_NAME)";
584 | TEST_TARGET_NAME = ERPageController;
585 | };
586 | name = Debug;
587 | };
588 | D8F7C8411F0F5E5B000DB0E7 /* Release */ = {
589 | isa = XCBuildConfiguration;
590 | buildSettings = {
591 | DEVELOPMENT_TEAM = 7W6345K7JN;
592 | INFOPLIST_FILE = ERPageControllerUITests/Info.plist;
593 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
594 | PRODUCT_BUNDLE_IDENTIFIER = com.erhu.ERPageControllerUITests;
595 | PRODUCT_NAME = "$(TARGET_NAME)";
596 | TEST_TARGET_NAME = ERPageController;
597 | };
598 | name = Release;
599 | };
600 | /* End XCBuildConfiguration section */
601 |
602 | /* Begin XCConfigurationList section */
603 | D8F7C8071F0F5E5B000DB0E7 /* Build configuration list for PBXProject "ERPageController" */ = {
604 | isa = XCConfigurationList;
605 | buildConfigurations = (
606 | D8F7C8371F0F5E5B000DB0E7 /* Debug */,
607 | D8F7C8381F0F5E5B000DB0E7 /* Release */,
608 | );
609 | defaultConfigurationIsVisible = 0;
610 | defaultConfigurationName = Release;
611 | };
612 | D8F7C8391F0F5E5B000DB0E7 /* Build configuration list for PBXNativeTarget "ERPageController" */ = {
613 | isa = XCConfigurationList;
614 | buildConfigurations = (
615 | D8F7C83A1F0F5E5B000DB0E7 /* Debug */,
616 | D8F7C83B1F0F5E5B000DB0E7 /* Release */,
617 | );
618 | defaultConfigurationIsVisible = 0;
619 | defaultConfigurationName = Release;
620 | };
621 | D8F7C83C1F0F5E5B000DB0E7 /* Build configuration list for PBXNativeTarget "ERPageControllerTests" */ = {
622 | isa = XCConfigurationList;
623 | buildConfigurations = (
624 | D8F7C83D1F0F5E5B000DB0E7 /* Debug */,
625 | D8F7C83E1F0F5E5B000DB0E7 /* Release */,
626 | );
627 | defaultConfigurationIsVisible = 0;
628 | defaultConfigurationName = Release;
629 | };
630 | D8F7C83F1F0F5E5B000DB0E7 /* Build configuration list for PBXNativeTarget "ERPageControllerUITests" */ = {
631 | isa = XCConfigurationList;
632 | buildConfigurations = (
633 | D8F7C8401F0F5E5B000DB0E7 /* Debug */,
634 | D8F7C8411F0F5E5B000DB0E7 /* Release */,
635 | );
636 | defaultConfigurationIsVisible = 0;
637 | defaultConfigurationName = Release;
638 | };
639 | /* End XCConfigurationList section */
640 | };
641 | rootObject = D8F7C8041F0F5E5B000DB0E7 /* Project object */;
642 | }
643 |
--------------------------------------------------------------------------------