修改UI
This commit is contained in:
24
Pods/JXCategoryView/Sources/Common/JXCategoryCollectionView.h
generated
Normal file
24
Pods/JXCategoryView/Sources/Common/JXCategoryCollectionView.h
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// JXCategoryCollectionView.h
|
||||
// UI系列测试
|
||||
//
|
||||
// Created by jiaxin on 2018/3/21.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "JXCategoryIndicatorProtocol.h"
|
||||
@class JXCategoryCollectionView;
|
||||
|
||||
@protocol JXCategoryCollectionViewGestureDelegate <NSObject>
|
||||
@optional
|
||||
- (BOOL)categoryCollectionView:(JXCategoryCollectionView *)collectionView gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
|
||||
- (BOOL)categoryCollectionView:(JXCategoryCollectionView *)collectionView gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
|
||||
@end
|
||||
|
||||
@interface JXCategoryCollectionView : UICollectionView
|
||||
|
||||
@property (nonatomic, strong) NSArray <UIView<JXCategoryIndicatorProtocol> *> *indicators;
|
||||
@property (nonatomic, weak) id<JXCategoryCollectionViewGestureDelegate> gestureDelegate;
|
||||
|
||||
@end
|
||||
52
Pods/JXCategoryView/Sources/Common/JXCategoryCollectionView.m
generated
Normal file
52
Pods/JXCategoryView/Sources/Common/JXCategoryCollectionView.m
generated
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// JXCategoryCollectionView.m
|
||||
// UI系列测试
|
||||
//
|
||||
// Created by jiaxin on 2018/3/21.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryCollectionView.h"
|
||||
|
||||
@interface JXCategoryCollectionView ()<UIGestureRecognizerDelegate>
|
||||
@end
|
||||
|
||||
@implementation JXCategoryCollectionView
|
||||
|
||||
- (void)setIndicators:(NSArray<UIView<JXCategoryIndicatorProtocol> *> *)indicators {
|
||||
for (UIView *indicator in _indicators) {
|
||||
//先移除之前的indicator
|
||||
[indicator removeFromSuperview];
|
||||
}
|
||||
|
||||
_indicators = indicators;
|
||||
|
||||
for (UIView *indicator in indicators) {
|
||||
[self addSubview:indicator];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
|
||||
for (UIView<JXCategoryIndicatorProtocol> *view in self.indicators) {
|
||||
[self sendSubviewToBack:view];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
|
||||
if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(categoryCollectionView:gestureRecognizerShouldBegin:)]) {
|
||||
return [self.gestureDelegate categoryCollectionView:self gestureRecognizerShouldBegin:gestureRecognizer];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
|
||||
if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(categoryCollectionView:gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)]) {
|
||||
return [self.gestureDelegate categoryCollectionView:self gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
18
Pods/JXCategoryView/Sources/Common/JXCategoryFactory.h
generated
Normal file
18
Pods/JXCategoryView/Sources/Common/JXCategoryFactory.h
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// JXCategoryFactory.h
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/8/17.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface JXCategoryFactory : NSObject
|
||||
|
||||
+ (CGFloat)interpolationFrom:(CGFloat)from to:(CGFloat)to percent:(CGFloat)percent;
|
||||
|
||||
+ (UIColor *)interpolationColorFrom:(UIColor *)fromColor to:(UIColor *)toColor percent:(CGFloat)percent;
|
||||
|
||||
@end
|
||||
29
Pods/JXCategoryView/Sources/Common/JXCategoryFactory.m
generated
Normal file
29
Pods/JXCategoryView/Sources/Common/JXCategoryFactory.m
generated
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// JXCategoryFactory.m
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/8/17.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryFactory.h"
|
||||
#import "UIColor+JXAdd.h"
|
||||
|
||||
@implementation JXCategoryFactory
|
||||
|
||||
+ (CGFloat)interpolationFrom:(CGFloat)from to:(CGFloat)to percent:(CGFloat)percent
|
||||
{
|
||||
percent = MAX(0, MIN(1, percent));
|
||||
return from + (to - from)*percent;
|
||||
}
|
||||
|
||||
+ (UIColor *)interpolationColorFrom:(UIColor *)fromColor to:(UIColor *)toColor percent:(CGFloat)percent
|
||||
{
|
||||
CGFloat red = [self interpolationFrom:fromColor.jx_red to:toColor.jx_red percent:percent];
|
||||
CGFloat green = [self interpolationFrom:fromColor.jx_green to:toColor.jx_green percent:percent];
|
||||
CGFloat blue = [self interpolationFrom:fromColor.jx_blue to:toColor.jx_blue percent:percent];
|
||||
CGFloat alpha = [self interpolationFrom:fromColor.jx_alpha to:toColor.jx_alpha percent:percent];
|
||||
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
|
||||
}
|
||||
|
||||
@end
|
||||
31
Pods/JXCategoryView/Sources/Common/JXCategoryIndicatorParamsModel.h
generated
Normal file
31
Pods/JXCategoryView/Sources/Common/JXCategoryIndicatorParamsModel.h
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// JXCategoryIndicatorParamsModel.h
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/12/13.
|
||||
// Copyright © 2018 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "JXCategoryViewDefines.h"
|
||||
|
||||
/**
|
||||
指示器不同情况处理时传递的数据模型,不同情况会对不同的属性赋值,根据不同情况的 api 说明确认。
|
||||
|
||||
FAQ: 为什么会通过 model 传递数据?
|
||||
因为指示器处理逻辑以后会扩展不同的使用场景,会新增参数,如果不通过 model 传递,就会在 api 新增参数,一旦修改 api 改的地方就特别多了,而且会影响到之前自定义实现的开发者。
|
||||
*/
|
||||
@interface JXCategoryIndicatorParamsModel : NSObject
|
||||
|
||||
@property (nonatomic, assign) NSInteger selectedIndex; // 当前选中的 index
|
||||
@property (nonatomic, assign) CGRect selectedCellFrame; // 当前选中的 cellFrame
|
||||
@property (nonatomic, assign) NSInteger leftIndex; // 正在过渡中的两个 cell,相对位置在左边的 cell 的 index
|
||||
@property (nonatomic, assign) CGRect leftCellFrame; // 正在过渡中的两个 cell,相对位置在左边的 cell 的 frame
|
||||
@property (nonatomic, assign) NSInteger rightIndex; // 正在过渡中的两个 cell,相对位置在右边的 cell 的 index
|
||||
@property (nonatomic, assign) CGRect rightCellFrame; // 正在过渡中的两个 cell,相对位置在右边的 cell 的 frame
|
||||
@property (nonatomic, assign) CGFloat percent; // 正在过渡中的两个 cell,从左到右的百分比
|
||||
@property (nonatomic, assign) NSInteger lastSelectedIndex; // 之前选中的 index
|
||||
@property (nonatomic, assign) JXCategoryCellSelectedType selectedType; //cell 被选中类型
|
||||
|
||||
@end
|
||||
13
Pods/JXCategoryView/Sources/Common/JXCategoryIndicatorParamsModel.m
generated
Normal file
13
Pods/JXCategoryView/Sources/Common/JXCategoryIndicatorParamsModel.m
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// JXCategoryIndicatorParamsModel.m
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/12/13.
|
||||
// Copyright © 2018 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryIndicatorParamsModel.h"
|
||||
|
||||
@implementation JXCategoryIndicatorParamsModel
|
||||
|
||||
@end
|
||||
49
Pods/JXCategoryView/Sources/Common/JXCategoryIndicatorProtocol.h
generated
Normal file
49
Pods/JXCategoryView/Sources/Common/JXCategoryIndicatorProtocol.h
generated
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// JXCategoryIndicatorProtocol.h
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/8/17.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "JXCategoryViewDefines.h"
|
||||
#import "JXCategoryIndicatorParamsModel.h"
|
||||
|
||||
@protocol JXCategoryIndicatorProtocol <NSObject>
|
||||
|
||||
/**
|
||||
categoryView 重置状态时调用
|
||||
|
||||
param selectedIndex 当前选中的 index
|
||||
param selectedCellFrame 当前选中的 cellFrame
|
||||
@param model 数据模型
|
||||
*/
|
||||
- (void)jx_refreshState:(JXCategoryIndicatorParamsModel *)model;
|
||||
|
||||
/**
|
||||
contentScrollView在进行手势滑动时,处理指示器跟随手势变化UI逻辑;
|
||||
|
||||
param selectedIndex 当前选中的index
|
||||
param leftIndex 正在过渡中的两个cell,相对位置在左边的cell的index
|
||||
param leftCellFrame 正在过渡中的两个cell,相对位置在左边的cell的frame
|
||||
param rightIndex 正在过渡中的两个cell,相对位置在右边的cell的index
|
||||
param rightCellFrame 正在过渡中的两个cell,相对位置在右边的cell的frame
|
||||
param percent 过渡百分比
|
||||
@param model 数据模型
|
||||
*/
|
||||
- (void)jx_contentScrollViewDidScroll:(JXCategoryIndicatorParamsModel *)model;
|
||||
|
||||
/**
|
||||
选中了某一个cell
|
||||
|
||||
param lastSelectedIndex 之前选中的index
|
||||
param selectedIndex 选中的index
|
||||
param selectedCellFrame 选中的cellFrame
|
||||
param selectedType cell被选中类型
|
||||
@param model 数据模型
|
||||
*/
|
||||
- (void)jx_selectedCell:(JXCategoryIndicatorParamsModel *)model;
|
||||
|
||||
@end
|
||||
16
Pods/JXCategoryView/Sources/Common/JXCategoryListContainerRTLCell.h
generated
Normal file
16
Pods/JXCategoryView/Sources/Common/JXCategoryListContainerRTLCell.h
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// JXCategoryListContainerRTLCell.h
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2020/7/3.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface JXCategoryListContainerRTLCell : UICollectionViewCell
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
23
Pods/JXCategoryView/Sources/Common/JXCategoryListContainerRTLCell.m
generated
Normal file
23
Pods/JXCategoryView/Sources/Common/JXCategoryListContainerRTLCell.m
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// JXCategoryListContainerRTLCell.m
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2020/7/3.
|
||||
//
|
||||
|
||||
#import "JXCategoryListContainerRTLCell.h"
|
||||
#import "RTLManager.h"
|
||||
|
||||
@implementation JXCategoryListContainerRTLCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[RTLManager horizontalFlipViewIfNeeded:self];
|
||||
[RTLManager horizontalFlipViewIfNeeded:self.contentView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
122
Pods/JXCategoryView/Sources/Common/JXCategoryListContainerView.h
generated
Normal file
122
Pods/JXCategoryView/Sources/Common/JXCategoryListContainerView.h
generated
Normal file
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// JXCategoryListScrollView.h
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/9/12.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "JXCategoryViewDefines.h"
|
||||
#import "JXCategoryBaseView.h"
|
||||
@class JXCategoryListContainerView;
|
||||
|
||||
/**
|
||||
列表容器视图的类型
|
||||
|
||||
- ScrollView: UIScrollView。优势:没有其他副作用。劣势:视图内存占用相对大一点。
|
||||
- CollectionView: 使用UICollectionView。优势:因为列表被添加到cell上,视图的内存占用更少,适合内存要求特别高的场景。劣势:因为cell重用机制的问题,导致列表下拉刷新视图,会因为被removeFromSuperview而被隐藏。需要参考`LoadDataListCollectionListViewController`类做特殊处理。
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, JXCategoryListContainerType) {
|
||||
JXCategoryListContainerType_ScrollView,
|
||||
JXCategoryListContainerType_CollectionView,
|
||||
};
|
||||
|
||||
@protocol JXCategoryListContentViewDelegate <NSObject>
|
||||
|
||||
/**
|
||||
如果列表是VC,就返回VC.view
|
||||
如果列表是View,就返回View自己
|
||||
|
||||
@return 返回列表视图
|
||||
*/
|
||||
- (UIView *)listView;
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
可选实现,列表将要显示的时候调用
|
||||
*/
|
||||
- (void)listWillAppear;
|
||||
|
||||
/**
|
||||
可选实现,列表显示的时候调用
|
||||
*/
|
||||
- (void)listDidAppear;
|
||||
|
||||
/**
|
||||
可选实现,列表将要消失的时候调用
|
||||
*/
|
||||
- (void)listWillDisappear;
|
||||
|
||||
/**
|
||||
可选实现,列表消失的时候调用
|
||||
*/
|
||||
- (void)listDidDisappear;
|
||||
|
||||
@end
|
||||
|
||||
@protocol JXCategoryListContainerViewDelegate <NSObject>
|
||||
/**
|
||||
返回list的数量
|
||||
|
||||
@param listContainerView 列表的容器视图
|
||||
@return list的数量
|
||||
*/
|
||||
- (NSInteger)numberOfListsInlistContainerView:(JXCategoryListContainerView *)listContainerView;
|
||||
|
||||
/**
|
||||
根据index返回一个对应列表实例,需要是遵从`JXCategoryListContentViewDelegate`协议的对象。
|
||||
你可以代理方法调用的时候初始化对应列表,达到懒加载的效果。这也是默认推荐的初始化列表方法。你也可以提前创建好列表,等该代理方法回调的时候再返回也可以,达到预加载的效果。
|
||||
如果列表是用自定义UIView封装的,就让自定义UIView遵从`JXCategoryListContentViewDelegate`协议,该方法返回自定义UIView即可。
|
||||
如果列表是用自定义UIViewController封装的,就让自定义UIViewController遵从`JXCategoryListContentViewDelegate`协议,该方法返回自定义UIViewController即可。
|
||||
|
||||
@param listContainerView 列表的容器视图
|
||||
@param index 目标下标
|
||||
@return 遵从JXCategoryListContentViewDelegate协议的list实例
|
||||
*/
|
||||
- (id<JXCategoryListContentViewDelegate>)listContainerView:(JXCategoryListContainerView *)listContainerView initListForIndex:(NSInteger)index;
|
||||
|
||||
@optional
|
||||
/**
|
||||
返回自定义UIScrollView或UICollectionView的Class
|
||||
某些特殊情况需要自己处理UIScrollView内部逻辑。比如项目用了FDFullscreenPopGesture,需要处理手势相关代理。
|
||||
|
||||
@param listContainerView JXCategoryListContainerView
|
||||
@return 自定义UIScrollView实例
|
||||
*/
|
||||
- (Class)scrollViewClassInlistContainerView:(JXCategoryListContainerView *)listContainerView;
|
||||
|
||||
/**
|
||||
控制能否初始化对应index的列表。有些业务需求,需要在某些情况才允许初始化某些列表,通过通过该代理实现控制。
|
||||
*/
|
||||
- (BOOL)listContainerView:(JXCategoryListContainerView *)listContainerView canInitListAtIndex:(NSInteger)index;
|
||||
|
||||
- (void)listContainerViewDidScroll:(UIScrollView *)scrollView;
|
||||
- (void)listContainerViewWillBeginDragging:(UIScrollView *)scrollView;
|
||||
- (void)listContainerViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
|
||||
- (void)listContainerViewWillBeginDecelerating:(UIScrollView *)scrollView;
|
||||
- (void)listContainerViewDidEndDecelerating:(UIScrollView *)scrollView;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface JXCategoryListContainerView : UIView <JXCategoryViewListContainer>
|
||||
|
||||
@property (nonatomic, assign, readonly) JXCategoryListContainerType containerType;
|
||||
@property (nonatomic, strong, readonly) UIScrollView *scrollView;
|
||||
@property (nonatomic, strong, readonly) NSDictionary <NSNumber *, id<JXCategoryListContentViewDelegate>> *validListDict; //已经加载过的列表字典。key是index,value是对应的列表
|
||||
@property (nonatomic, strong) UIColor *listCellBackgroundColor; //默认:[UIColor whiteColor]
|
||||
/**
|
||||
滚动切换的时候,滚动距离超过一页的多少百分比,就触发列表的初始化。默认0.01(即列表显示了一点就触发加载)。范围0~1,开区间不包括0和1
|
||||
*/
|
||||
@property (nonatomic, assign) CGFloat initListPercent;
|
||||
@property (nonatomic, assign) BOOL bounces; //默认NO
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE;
|
||||
- (instancetype)initWithType:(JXCategoryListContainerType)type delegate:(id<JXCategoryListContainerViewDelegate>)delegate NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
547
Pods/JXCategoryView/Sources/Common/JXCategoryListContainerView.m
generated
Normal file
547
Pods/JXCategoryView/Sources/Common/JXCategoryListContainerView.m
generated
Normal file
@@ -0,0 +1,547 @@
|
||||
//
|
||||
// JXCategoryListContainerView.m
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/9/12.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryListContainerView.h"
|
||||
#import <objc/runtime.h>
|
||||
#import "RTLManager.h"
|
||||
|
||||
@interface JXCategoryListContainerViewController : UIViewController
|
||||
@property (copy) void(^viewWillAppearBlock)(void);
|
||||
@property (copy) void(^viewDidAppearBlock)(void);
|
||||
@property (copy) void(^viewWillDisappearBlock)(void);
|
||||
@property (copy) void(^viewDidDisappearBlock)(void);
|
||||
@end
|
||||
|
||||
@implementation JXCategoryListContainerViewController
|
||||
- (void)dealloc
|
||||
{
|
||||
self.viewWillAppearBlock = nil;
|
||||
self.viewDidAppearBlock = nil;
|
||||
self.viewWillDisappearBlock = nil;
|
||||
self.viewDidDisappearBlock = nil;
|
||||
}
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
self.viewWillAppearBlock();
|
||||
}
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
self.viewDidAppearBlock();
|
||||
}
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
self.viewWillDisappearBlock();
|
||||
}
|
||||
- (void)viewDidDisappear:(BOOL)animated {
|
||||
[super viewDidDisappear:animated];
|
||||
self.viewDidDisappearBlock();
|
||||
}
|
||||
- (BOOL)shouldAutomaticallyForwardAppearanceMethods { return NO; }
|
||||
@end
|
||||
|
||||
@interface JXCategoryListContainerView () <UIScrollViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource>
|
||||
@property (nonatomic, weak) id<JXCategoryListContainerViewDelegate> delegate;
|
||||
@property (nonatomic, strong) UIScrollView *scrollView;
|
||||
@property (nonatomic, assign) NSInteger currentIndex;
|
||||
@property (nonatomic, strong) NSMutableDictionary <NSNumber *, id<JXCategoryListContentViewDelegate>> *validListDict;
|
||||
@property (nonatomic, assign) NSInteger willAppearIndex;
|
||||
@property (nonatomic, assign) NSInteger willDisappearIndex;
|
||||
@property (nonatomic, strong) UICollectionView *collectionView;
|
||||
@property (nonatomic, strong) JXCategoryListContainerViewController *containerVC;
|
||||
@end
|
||||
|
||||
@implementation JXCategoryListContainerView
|
||||
|
||||
- (instancetype)initWithType:(JXCategoryListContainerType)type delegate:(id<JXCategoryListContainerViewDelegate>)delegate{
|
||||
self = [super initWithFrame:CGRectZero];
|
||||
if (self) {
|
||||
_containerType = type;
|
||||
_delegate = delegate;
|
||||
_validListDict = [NSMutableDictionary dictionary];
|
||||
_willAppearIndex = -1;
|
||||
_willDisappearIndex = -1;
|
||||
_initListPercent = 0.01;
|
||||
[self initializeViews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initializeViews {
|
||||
_listCellBackgroundColor = [UIColor whiteColor];
|
||||
_containerVC = [[JXCategoryListContainerViewController alloc] init];
|
||||
self.containerVC.view.backgroundColor = [UIColor clearColor];
|
||||
[self addSubview:self.containerVC.view];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
self.containerVC.viewWillAppearBlock = ^{
|
||||
[weakSelf listWillAppear:weakSelf.currentIndex];
|
||||
};
|
||||
self.containerVC.viewDidAppearBlock = ^{
|
||||
[weakSelf listDidAppear:weakSelf.currentIndex];
|
||||
};
|
||||
self.containerVC.viewWillDisappearBlock = ^{
|
||||
[weakSelf listWillDisappear:weakSelf.currentIndex];
|
||||
};
|
||||
self.containerVC.viewDidDisappearBlock = ^{
|
||||
[weakSelf listDidDisappear:weakSelf.currentIndex];
|
||||
};
|
||||
if (self.containerType == JXCategoryListContainerType_ScrollView) {
|
||||
if (self.delegate &&
|
||||
[self.delegate respondsToSelector:@selector(scrollViewClassInlistContainerView:)] &&
|
||||
[[self.delegate scrollViewClassInlistContainerView:self] isKindOfClass:object_getClass([UIScrollView class])]) {
|
||||
_scrollView = (UIScrollView *)[[[self.delegate scrollViewClassInlistContainerView:self] alloc] init];
|
||||
}else {
|
||||
_scrollView = [[UIScrollView alloc] init];
|
||||
}
|
||||
self.scrollView.delegate = self;
|
||||
self.scrollView.pagingEnabled = YES;
|
||||
self.scrollView.showsHorizontalScrollIndicator = NO;
|
||||
self.scrollView.showsVerticalScrollIndicator = NO;
|
||||
self.scrollView.scrollsToTop = NO;
|
||||
self.scrollView.bounces = NO;
|
||||
if (@available(iOS 11.0, *)) {
|
||||
if ([self.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
|
||||
self.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
}
|
||||
}
|
||||
[RTLManager horizontalFlipViewIfNeeded:self.scrollView];
|
||||
[self.containerVC.view addSubview:self.scrollView];
|
||||
}else {
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
layout.minimumLineSpacing = 0;
|
||||
layout.minimumInteritemSpacing = 0;
|
||||
if (self.delegate &&
|
||||
[self.delegate respondsToSelector:@selector(scrollViewClassInlistContainerView:)] &&
|
||||
[[self.delegate scrollViewClassInlistContainerView:self] isKindOfClass:object_getClass([UICollectionView class])]) {
|
||||
_collectionView = (UICollectionView *)[[[self.delegate scrollViewClassInlistContainerView:self] alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
}else {
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
}
|
||||
self.collectionView.pagingEnabled = YES;
|
||||
self.collectionView.showsHorizontalScrollIndicator = NO;
|
||||
self.collectionView.showsVerticalScrollIndicator = NO;
|
||||
self.collectionView.scrollsToTop = NO;
|
||||
self.collectionView.bounces = NO;
|
||||
self.collectionView.dataSource = self;
|
||||
self.collectionView.delegate = self;
|
||||
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
|
||||
if (@available(iOS 10.0, *)) {
|
||||
self.collectionView.prefetchingEnabled = NO;
|
||||
}
|
||||
if (@available(iOS 11.0, *)) {
|
||||
if ([self.collectionView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) {
|
||||
self.collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
}
|
||||
}
|
||||
if ([RTLManager supportRTL]) {
|
||||
self.collectionView.semanticContentAttribute = UISemanticContentAttributeForceLeftToRight;
|
||||
[RTLManager horizontalFlipView:self.collectionView];
|
||||
}
|
||||
[self.containerVC.view addSubview:self.collectionView];
|
||||
//让外部统一访问scrollView
|
||||
_scrollView = _collectionView;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)willMoveToSuperview:(UIView *)newSuperview {
|
||||
[super willMoveToSuperview:newSuperview];
|
||||
|
||||
UIResponder *next = newSuperview;
|
||||
while (next != nil) {
|
||||
if ([next isKindOfClass:[UIViewController class]]) {
|
||||
[((UIViewController *)next) addChildViewController:self.containerVC];
|
||||
break;
|
||||
}
|
||||
next = next.nextResponder;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
|
||||
self.containerVC.view.frame = self.bounds;
|
||||
if (self.containerType == JXCategoryListContainerType_ScrollView) {
|
||||
if (CGRectEqualToRect(self.scrollView.frame, CGRectZero) || !CGSizeEqualToSize(self.scrollView.bounds.size, self.bounds.size)) {
|
||||
self.scrollView.frame = self.bounds;
|
||||
self.scrollView.contentSize = CGSizeMake(self.scrollView.bounds.size.width*[self.delegate numberOfListsInlistContainerView:self], self.scrollView.bounds.size.height);
|
||||
[_validListDict enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull index, id<JXCategoryListContentViewDelegate> _Nonnull list, BOOL * _Nonnull stop) {
|
||||
[list listView].frame = CGRectMake(index.intValue*self.scrollView.bounds.size.width, 0, self.scrollView.bounds.size.width, self.scrollView.bounds.size.height);
|
||||
}];
|
||||
CGPoint scrollViewContentOffset = self.scrollView.contentOffset;
|
||||
scrollViewContentOffset.x = self.currentIndex*self.scrollView.bounds.size.width;
|
||||
self.scrollView.contentOffset = scrollViewContentOffset;
|
||||
}else {
|
||||
self.scrollView.frame = self.bounds;
|
||||
self.scrollView.contentSize = CGSizeMake(self.scrollView.bounds.size.width*[self.delegate numberOfListsInlistContainerView:self], self.scrollView.bounds.size.height);
|
||||
}
|
||||
}else {
|
||||
if (CGRectEqualToRect(self.collectionView.frame, CGRectZero) || !CGSizeEqualToSize(self.collectionView.bounds.size, self.bounds.size)) {
|
||||
[self.collectionView.collectionViewLayout invalidateLayout];
|
||||
self.collectionView.frame = self.bounds;
|
||||
[self.collectionView reloadData];
|
||||
CGPoint collectionViewContentOffset = self.collectionView.contentOffset;
|
||||
collectionViewContentOffset.x =
|
||||
self.collectionView.bounds.size.width*self.currentIndex;
|
||||
[self.collectionView setContentOffset:collectionViewContentOffset animated:NO];
|
||||
}else {
|
||||
self.collectionView.frame = self.bounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)setinitListPercent:(CGFloat)initListPercent {
|
||||
_initListPercent = initListPercent;
|
||||
if (initListPercent <= 0 || initListPercent >= 1) {
|
||||
NSAssert(NO, @"initListPercent值范围为开区间(0,1),即不包括0和1");
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setBounces:(BOOL)bounces {
|
||||
_bounces = bounces;
|
||||
self.scrollView.bounces = bounces;
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionViewDelegate, UICollectionViewDataSource
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return [self.delegate numberOfListsInlistContainerView:self];
|
||||
}
|
||||
|
||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
|
||||
cell.contentView.backgroundColor = self.listCellBackgroundColor;
|
||||
|
||||
UIView* listView = nil;
|
||||
id<JXCategoryListContentViewDelegate> list = _validListDict[@(indexPath.item)];
|
||||
if (list != nil) {
|
||||
//fixme:如果list是UIViewController,如果这里的frame修改是`[list listView].frame = cell.bounds;`。那么就必须给list vc添加如下代码:
|
||||
//- (void)loadView {
|
||||
// self.view = [[UIView alloc] init];
|
||||
//}
|
||||
//所以,总感觉是把UIViewController当做普通view使用,导致了系统内部的bug。所以,缓兵之计就是用下面的方法,暂时解决问题。
|
||||
listView = [list listView];
|
||||
if ([list isKindOfClass:[UIViewController class]]) {
|
||||
listView.frame = cell.contentView.bounds;
|
||||
} else {
|
||||
listView.frame = cell.bounds;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL isAdded = NO;
|
||||
for (UIView *subview in cell.contentView.subviews) {
|
||||
if( listView != subview ) {
|
||||
[subview removeFromSuperview];
|
||||
} else {
|
||||
isAdded = YES;
|
||||
}
|
||||
}
|
||||
|
||||
if( !isAdded && listView ) {
|
||||
[cell.contentView addSubview:listView];
|
||||
}
|
||||
|
||||
// 针对 RTL 布局
|
||||
if ([UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.semanticContentAttribute]
|
||||
== UIUserInterfaceLayoutDirectionRightToLeft) {
|
||||
cell.contentView.transform = CGAffineTransformMakeScale(-1, 1);
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return self.bounds.size;
|
||||
}
|
||||
|
||||
#pragma mark - UIScrollViewDelegate
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(listContainerViewDidScroll:)]) {
|
||||
[self.delegate listContainerViewDidScroll:scrollView];
|
||||
}
|
||||
|
||||
if (!scrollView.isDragging && !scrollView.isTracking && !scrollView.isDecelerating) {
|
||||
return;
|
||||
}
|
||||
CGFloat ratio = scrollView.contentOffset.x/scrollView.bounds.size.width;
|
||||
NSInteger maxCount = round(scrollView.contentSize.width/scrollView.bounds.size.width);
|
||||
NSInteger leftIndex = floorf(ratio);
|
||||
leftIndex = MAX(0, MIN(maxCount - 1, leftIndex));
|
||||
NSInteger rightIndex = leftIndex + 1;
|
||||
if (ratio < 0 || rightIndex >= maxCount) {
|
||||
[self listDidAppearOrDisappear:scrollView];
|
||||
return;
|
||||
}
|
||||
CGFloat remainderRatio = ratio - leftIndex;
|
||||
if (rightIndex == self.currentIndex) {
|
||||
//当前选中的在右边,用户正在从右边往左边滑动
|
||||
if (self.validListDict[@(leftIndex)] == nil && remainderRatio < (1 - self.initListPercent)) {
|
||||
[self initListIfNeededAtIndex:leftIndex];
|
||||
}else if (self.validListDict[@(leftIndex)] != nil) {
|
||||
if (self.willAppearIndex == -1) {
|
||||
self.willAppearIndex = leftIndex;
|
||||
[self listWillAppear:self.willAppearIndex];
|
||||
}
|
||||
}
|
||||
if (self.willDisappearIndex == -1) {
|
||||
self.willDisappearIndex = rightIndex;
|
||||
[self listWillDisappear:self.willDisappearIndex];
|
||||
}
|
||||
}else {
|
||||
//当前选中的在左边,用户正在从左边往右边滑动
|
||||
if (self.validListDict[@(rightIndex)] == nil && remainderRatio > self.initListPercent) {
|
||||
[self initListIfNeededAtIndex:rightIndex];
|
||||
}else if (self.validListDict[@(rightIndex)] != nil) {
|
||||
if (self.willAppearIndex == -1) {
|
||||
self.willAppearIndex = rightIndex;
|
||||
[self listWillAppear:self.willAppearIndex];
|
||||
}
|
||||
}
|
||||
if (self.willDisappearIndex == -1) {
|
||||
self.willDisappearIndex = leftIndex;
|
||||
[self listWillDisappear:self.willDisappearIndex];
|
||||
}
|
||||
}
|
||||
[self listDidAppearOrDisappear:scrollView];
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
|
||||
//滑动到一半又取消滑动处理
|
||||
if (self.willDisappearIndex != -1) {
|
||||
[self listWillAppear:self.willDisappearIndex];
|
||||
[self listWillDisappear:self.willAppearIndex];
|
||||
[self listDidAppear:self.willDisappearIndex];
|
||||
[self listDidDisappear:self.willAppearIndex];
|
||||
self.willDisappearIndex = -1;
|
||||
self.willAppearIndex = -1;
|
||||
}
|
||||
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(listContainerViewDidEndDecelerating:)]) {
|
||||
[self.delegate listContainerViewDidEndDecelerating:scrollView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(listContainerViewWillBeginDragging:)]) {
|
||||
[self.delegate listContainerViewWillBeginDragging:scrollView];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(listContainerViewDidEndDragging:willDecelerate:)]) {
|
||||
[self.delegate listContainerViewDidEndDragging:scrollView willDecelerate:decelerate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
|
||||
{
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(listContainerViewWillBeginDecelerating:)]) {
|
||||
[self.delegate listContainerViewWillBeginDecelerating:scrollView];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - JXCategoryViewListContainer
|
||||
|
||||
- (UIScrollView *)contentScrollView {
|
||||
return self.scrollView;
|
||||
}
|
||||
|
||||
- (void)setDefaultSelectedIndex:(NSInteger)index {
|
||||
self.currentIndex = index;
|
||||
}
|
||||
|
||||
- (void)didClickSelectedItemAtIndex:(NSInteger)index {
|
||||
if (![self checkIndexValid:index]) {
|
||||
return;
|
||||
}
|
||||
self.willAppearIndex = -1;
|
||||
self.willDisappearIndex = -1;
|
||||
if (self.currentIndex != index) {
|
||||
[self listWillDisappear:self.currentIndex];
|
||||
[self listDidDisappear:self.currentIndex];
|
||||
[self listWillAppear:index];
|
||||
[self listDidAppear:index];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reloadData {
|
||||
for (id<JXCategoryListContentViewDelegate> list in _validListDict.allValues) {
|
||||
[[list listView] removeFromSuperview];
|
||||
if ([list isKindOfClass:[UIViewController class]]) {
|
||||
[(UIViewController *)list removeFromParentViewController];
|
||||
}
|
||||
}
|
||||
[_validListDict removeAllObjects];
|
||||
|
||||
if (self.containerType == JXCategoryListContainerType_ScrollView) {
|
||||
self.scrollView.contentSize = CGSizeMake(self.scrollView.bounds.size.width*[self.delegate numberOfListsInlistContainerView:self], self.scrollView.bounds.size.height);
|
||||
}else {
|
||||
[self.collectionView reloadData];
|
||||
}
|
||||
[self listWillAppear:self.currentIndex];
|
||||
[self listDidAppear:self.currentIndex];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (void)initListIfNeededAtIndex:(NSInteger)index {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(listContainerView:canInitListAtIndex:)]) {
|
||||
BOOL canInitList = [self.delegate listContainerView:self canInitListAtIndex:index];
|
||||
if (!canInitList) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
id<JXCategoryListContentViewDelegate> list = _validListDict[@(index)];
|
||||
if (list != nil) {
|
||||
//列表已经创建好了
|
||||
return;
|
||||
}
|
||||
list = [self.delegate listContainerView:self initListForIndex:index];
|
||||
if ([list isKindOfClass:[UIViewController class]]) {
|
||||
[self.containerVC addChildViewController:(UIViewController *)list];
|
||||
}
|
||||
_validListDict[@(index)] = list;
|
||||
|
||||
if (self.containerType == JXCategoryListContainerType_ScrollView) {
|
||||
[list listView].frame = CGRectMake(index*self.scrollView.bounds.size.width, 0, self.scrollView.bounds.size.width, self.scrollView.bounds.size.height);
|
||||
[self.scrollView addSubview:[list listView]];
|
||||
[RTLManager horizontalFlipViewIfNeeded:[list listView]];
|
||||
}else {
|
||||
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]];
|
||||
for (UIView *subview in cell.contentView.subviews) {
|
||||
[subview removeFromSuperview];
|
||||
}
|
||||
[list listView].frame = cell.contentView.bounds;
|
||||
[cell.contentView addSubview:[list listView]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)listWillAppear:(NSInteger)index {
|
||||
if (![self checkIndexValid:index]) {
|
||||
return;
|
||||
}
|
||||
id<JXCategoryListContentViewDelegate> list = _validListDict[@(index)];
|
||||
if (list == nil) {
|
||||
//当前列表未被创建(页面初始化或通过点击触发的listWillAppear)
|
||||
BOOL canInitList = YES;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(listContainerView:canInitListAtIndex:)]) {
|
||||
canInitList = [self.delegate listContainerView:self canInitListAtIndex:index];
|
||||
}
|
||||
if (!canInitList) {
|
||||
return;
|
||||
}
|
||||
list = [self.delegate listContainerView:self initListForIndex:index];
|
||||
if ([list isKindOfClass:[UIViewController class]]) {
|
||||
[self.containerVC addChildViewController:(UIViewController *)list];
|
||||
}
|
||||
_validListDict[@(index)] = list;
|
||||
if (self.containerType == JXCategoryListContainerType_ScrollView) {
|
||||
if ([list listView].superview == nil) {
|
||||
[list listView].frame = CGRectMake(index*self.scrollView.bounds.size.width, 0, self.scrollView.bounds.size.width, self.scrollView.bounds.size.height);
|
||||
[self.scrollView addSubview:[list listView]];
|
||||
[RTLManager horizontalFlipViewIfNeeded:[list listView]];
|
||||
}
|
||||
}else {
|
||||
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]];
|
||||
for (UIView *subview in cell.contentView.subviews) {
|
||||
[subview removeFromSuperview];
|
||||
}
|
||||
[list listView].frame = cell.contentView.bounds;
|
||||
[cell.contentView addSubview:[list listView]];
|
||||
}
|
||||
}
|
||||
|
||||
if (list && [list respondsToSelector:@selector(listWillAppear)]) {
|
||||
[list listWillAppear];
|
||||
}
|
||||
if ([list isKindOfClass:[UIViewController class]]) {
|
||||
UIViewController *listVC = (UIViewController *)list;
|
||||
[listVC beginAppearanceTransition:YES animated:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)listDidAppear:(NSInteger)index {
|
||||
if (![self checkIndexValid:index]) {
|
||||
return;
|
||||
}
|
||||
self.currentIndex = index;
|
||||
id<JXCategoryListContentViewDelegate> list = _validListDict[@(index)];
|
||||
if (list && [list respondsToSelector:@selector(listDidAppear)]) {
|
||||
[list listDidAppear];
|
||||
}
|
||||
if ([list isKindOfClass:[UIViewController class]]) {
|
||||
UIViewController *listVC = (UIViewController *)list;
|
||||
[listVC endAppearanceTransition];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)listWillDisappear:(NSInteger)index {
|
||||
if (![self checkIndexValid:index]) {
|
||||
return;
|
||||
}
|
||||
id<JXCategoryListContentViewDelegate> list = _validListDict[@(index)];
|
||||
if (list && [list respondsToSelector:@selector(listWillDisappear)]) {
|
||||
[list listWillDisappear];
|
||||
}
|
||||
if ([list isKindOfClass:[UIViewController class]]) {
|
||||
UIViewController *listVC = (UIViewController *)list;
|
||||
[listVC beginAppearanceTransition:NO animated:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)listDidDisappear:(NSInteger)index {
|
||||
if (![self checkIndexValid:index]) {
|
||||
return;
|
||||
}
|
||||
id<JXCategoryListContentViewDelegate> list = _validListDict[@(index)];
|
||||
if (list && [list respondsToSelector:@selector(listDidDisappear)]) {
|
||||
[list listDidDisappear];
|
||||
}
|
||||
if ([list isKindOfClass:[UIViewController class]]) {
|
||||
UIViewController *listVC = (UIViewController *)list;
|
||||
[listVC endAppearanceTransition];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)checkIndexValid:(NSInteger)index {
|
||||
NSUInteger count = [self.delegate numberOfListsInlistContainerView:self];
|
||||
if (count <= 0 || index >= count) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)listDidAppearOrDisappear:(UIScrollView *)scrollView {
|
||||
CGFloat currentIndexPercent = scrollView.contentOffset.x/scrollView.bounds.size.width;
|
||||
if (self.willAppearIndex != -1 || self.willDisappearIndex != -1) {
|
||||
NSInteger disappearIndex = self.willDisappearIndex;
|
||||
NSInteger appearIndex = self.willAppearIndex;
|
||||
if (self.willAppearIndex > self.willDisappearIndex) {
|
||||
//将要出现的列表在右边
|
||||
if (currentIndexPercent >= self.willAppearIndex) {
|
||||
self.willDisappearIndex = -1;
|
||||
self.willAppearIndex = -1;
|
||||
[self listDidDisappear:disappearIndex];
|
||||
[self listDidAppear:appearIndex];
|
||||
}
|
||||
}else {
|
||||
//将要出现的列表在左边
|
||||
if (currentIndexPercent <= self.willAppearIndex) {
|
||||
self.willDisappearIndex = -1;
|
||||
self.willAppearIndex = -1;
|
||||
[self listDidDisappear:disappearIndex];
|
||||
[self listDidAppear:appearIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
24
Pods/JXCategoryView/Sources/Common/JXCategoryViewAnimator.h
generated
Normal file
24
Pods/JXCategoryView/Sources/Common/JXCategoryViewAnimator.h
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// JXCategoryViewAnimator.h
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2019/1/24.
|
||||
// Copyright © 2019 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface JXCategoryViewAnimator : NSObject
|
||||
|
||||
@property (nonatomic, assign) NSTimeInterval duration;
|
||||
@property (nonatomic, copy) void(^progressCallback)(CGFloat percent);
|
||||
@property (nonatomic, copy) void(^completeCallback)(void);
|
||||
@property (readonly, getter=isExecuting) BOOL executing;
|
||||
|
||||
- (void)start;
|
||||
- (void)stop;
|
||||
- (void)invalid;
|
||||
|
||||
@end
|
||||
|
||||
75
Pods/JXCategoryView/Sources/Common/JXCategoryViewAnimator.m
generated
Normal file
75
Pods/JXCategoryView/Sources/Common/JXCategoryViewAnimator.m
generated
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// JXCategoryViewAnimator.m
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2019/1/24.
|
||||
// Copyright © 2019 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryViewAnimator.h"
|
||||
|
||||
@interface JXCategoryViewAnimator ()
|
||||
@property (nonatomic, strong) CADisplayLink *displayLink;
|
||||
@property (nonatomic, assign) CFTimeInterval firstTimestamp;
|
||||
@property (readwrite, getter=isExecuting) BOOL executing;
|
||||
@end
|
||||
|
||||
@implementation JXCategoryViewAnimator
|
||||
|
||||
#pragma mark - Initialize
|
||||
|
||||
- (void)dealloc {
|
||||
self.progressCallback = nil;
|
||||
self.completeCallback = nil;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_executing = NO;
|
||||
_duration = 0.25;
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(processDisplayLink:)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
- (void)start {
|
||||
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
||||
self.executing = YES;
|
||||
}
|
||||
|
||||
- (void)stop {
|
||||
!self.progressCallback ?: self.progressCallback(1);
|
||||
[self.displayLink invalidate];
|
||||
!self.completeCallback ?: self.completeCallback();
|
||||
self.executing = NO;
|
||||
}
|
||||
|
||||
- (void)invalid {
|
||||
[self.displayLink invalidate];
|
||||
!self.completeCallback ?: self.completeCallback();
|
||||
self.executing = NO;
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)processDisplayLink:(CADisplayLink *)sender {
|
||||
if (self.firstTimestamp == 0) {
|
||||
self.firstTimestamp = sender.timestamp;
|
||||
return;
|
||||
}
|
||||
CGFloat percent = (sender.timestamp - self.firstTimestamp)/self.duration;
|
||||
if (percent >= 1) {
|
||||
!self.progressCallback ?: self.progressCallback(percent);
|
||||
[self.displayLink invalidate];
|
||||
!self.completeCallback ?: self.completeCallback();
|
||||
self.executing = NO;
|
||||
}else {
|
||||
!self.progressCallback ?: self.progressCallback(percent);
|
||||
self.executing = YES;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
43
Pods/JXCategoryView/Sources/Common/JXCategoryViewDefines.h
generated
Normal file
43
Pods/JXCategoryView/Sources/Common/JXCategoryViewDefines.h
generated
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// JXCategoryViewDefines.h
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/8/17.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
static const CGFloat JXCategoryViewAutomaticDimension = -1;
|
||||
|
||||
typedef void(^JXCategoryCellSelectedAnimationBlock)(CGFloat percent);
|
||||
|
||||
// 指示器的位置
|
||||
typedef NS_ENUM(NSUInteger, JXCategoryComponentPosition) {
|
||||
JXCategoryComponentPosition_Bottom,
|
||||
JXCategoryComponentPosition_Top
|
||||
};
|
||||
|
||||
// cell 被选中的类型
|
||||
typedef NS_ENUM(NSUInteger, JXCategoryCellSelectedType) {
|
||||
JXCategoryCellSelectedTypeUnknown, // 未知,不是选中(cellForRow方法里面、两个cell过渡时)
|
||||
JXCategoryCellSelectedTypeClick, // 点击选中
|
||||
JXCategoryCellSelectedTypeCode, // 调用方法 selectItemAtIndex: 选中
|
||||
JXCategoryCellSelectedTypeScroll // 通过滚动到某个 cell 选中
|
||||
};
|
||||
|
||||
// cell 标题锚点位置
|
||||
typedef NS_ENUM(NSUInteger, JXCategoryTitleLabelAnchorPointStyle) {
|
||||
JXCategoryTitleLabelAnchorPointStyleCenter,
|
||||
JXCategoryTitleLabelAnchorPointStyleTop,
|
||||
JXCategoryTitleLabelAnchorPointStyleBottom
|
||||
};
|
||||
|
||||
// 指示器滚动样式
|
||||
typedef NS_ENUM(NSUInteger, JXCategoryIndicatorScrollStyle) {
|
||||
JXCategoryIndicatorScrollStyleSimple, // 简单滚动,即从当前位置过渡到目标位置
|
||||
JXCategoryIndicatorScrollStyleSameAsUserScroll // 和用户左右滚动列表时的效果一样
|
||||
};
|
||||
|
||||
#define JXCategoryViewDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
|
||||
18
Pods/JXCategoryView/Sources/Common/UIColor+JXAdd.h
generated
Normal file
18
Pods/JXCategoryView/Sources/Common/UIColor+JXAdd.h
generated
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// UIColor+JXAdd.h
|
||||
// UI系列测试
|
||||
//
|
||||
// Created by jiaxin on 2018/3/21.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIColor (JXAdd)
|
||||
|
||||
@property (nonatomic, assign, readonly) CGFloat jx_red;
|
||||
@property (nonatomic, assign, readonly) CGFloat jx_green;
|
||||
@property (nonatomic, assign, readonly) CGFloat jx_blue;
|
||||
@property (nonatomic, assign, readonly) CGFloat jx_alpha;
|
||||
|
||||
@end
|
||||
35
Pods/JXCategoryView/Sources/Common/UIColor+JXAdd.m
generated
Normal file
35
Pods/JXCategoryView/Sources/Common/UIColor+JXAdd.m
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// UIColor+JXAdd.m
|
||||
// UI系列测试
|
||||
//
|
||||
// Created by jiaxin on 2018/3/21.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIColor+JXAdd.h"
|
||||
|
||||
@implementation UIColor (JXAdd)
|
||||
|
||||
- (CGFloat)jx_red {
|
||||
CGFloat r = 0, g, b, a;
|
||||
[self getRed:&r green:&g blue:&b alpha:&a];
|
||||
return r;
|
||||
}
|
||||
|
||||
- (CGFloat)jx_green {
|
||||
CGFloat r, g = 0, b, a;
|
||||
[self getRed:&r green:&g blue:&b alpha:&a];
|
||||
return g;
|
||||
}
|
||||
|
||||
- (CGFloat)jx_blue {
|
||||
CGFloat r, g, b = 0, a;
|
||||
[self getRed:&r green:&g blue:&b alpha:&a];
|
||||
return b;
|
||||
}
|
||||
|
||||
- (CGFloat)jx_alpha {
|
||||
return CGColorGetAlpha(self.CGColor);
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user