Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
GMBase
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
gengmeiios
GMBase
Commits
a4f39813
Commit
a4f39813
authored
May 06, 2020
by
luyueming
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
jxPagerView放到GMBase中
parent
401aef70
Hide whitespace changes
Inline
Side-by-side
Showing
89 changed files
with
5655 additions
and
0 deletions
+5655
-0
JXCategoryBaseCell.h
...sses/JXPagerView/JXCategoryView/Base/JXCategoryBaseCell.h
+20
-0
JXCategoryBaseCell.m
...sses/JXPagerView/JXCategoryView/Base/JXCategoryBaseCell.m
+35
-0
JXCategoryBaseCellModel.h
...JXPagerView/JXCategoryView/Base/JXCategoryBaseCellModel.h
+26
-0
JXCategoryBaseCellModel.m
...JXPagerView/JXCategoryView/Base/JXCategoryBaseCellModel.m
+20
-0
JXCategoryBaseView.h
...sses/JXPagerView/JXCategoryView/Base/JXCategoryBaseView.h
+190
-0
JXCategoryBaseView.m
...sses/JXPagerView/JXCategoryView/Base/JXCategoryBaseView.m
+471
-0
JXCategoryCollectionView.h
...agerView/JXCategoryView/Common/JXCategoryCollectionView.h
+15
-0
JXCategoryCollectionView.m
...agerView/JXCategoryView/Common/JXCategoryCollectionView.m
+22
-0
JXCategoryFactory.h
...ses/JXPagerView/JXCategoryView/Common/JXCategoryFactory.h
+18
-0
JXCategoryFactory.m
...ses/JXPagerView/JXCategoryView/Common/JXCategoryFactory.m
+31
-0
JXCategoryIndicatorParamsModel.h
...ew/JXCategoryView/Common/JXCategoryIndicatorParamsModel.h
+27
-0
JXCategoryIndicatorParamsModel.m
...ew/JXCategoryView/Common/JXCategoryIndicatorParamsModel.m
+13
-0
JXCategoryIndicatorProtocol.h
...rView/JXCategoryView/Common/JXCategoryIndicatorProtocol.h
+50
-0
JXCategoryListContainerView.h
...rView/JXCategoryView/Common/JXCategoryListContainerView.h
+87
-0
JXCategoryListContainerView.m
...rView/JXCategoryView/Common/JXCategoryListContainerView.m
+134
-0
JXCategoryListVCContainerView.h
...iew/JXCategoryView/Common/JXCategoryListVCContainerView.h
+39
-0
JXCategoryListVCContainerView.m
...iew/JXCategoryView/Common/JXCategoryListVCContainerView.m
+160
-0
JXCategoryViewDefines.h
...JXPagerView/JXCategoryView/Common/JXCategoryViewDefines.h
+22
-0
UIColor+JXAdd.h
...Classes/JXPagerView/JXCategoryView/Common/UIColor+JXAdd.h
+19
-0
UIColor+JXAdd.m
...Classes/JXPagerView/JXCategoryView/Common/UIColor+JXAdd.m
+35
-0
JXCategoryDotCell.h
...lasses/JXPagerView/JXCategoryView/Dot/JXCategoryDotCell.h
+13
-0
JXCategoryDotCell.m
...lasses/JXPagerView/JXCategoryView/Dot/JXCategoryDotCell.m
+78
-0
JXCategoryDotCellModel.h
...s/JXPagerView/JXCategoryView/Dot/JXCategoryDotCellModel.h
+31
-0
JXCategoryDotCellModel.m
...s/JXPagerView/JXCategoryView/Dot/JXCategoryDotCellModel.m
+13
-0
JXCategoryDotView.h
...lasses/JXPagerView/JXCategoryView/Dot/JXCategoryDotView.h
+25
-0
JXCategoryDotView.m
...lasses/JXPagerView/JXCategoryView/Dot/JXCategoryDotView.m
+50
-0
JXCategoryImageCell.h
...es/JXPagerView/JXCategoryView/Image/JXCategoryImageCell.h
+15
-0
JXCategoryImageCell.m
...es/JXPagerView/JXCategoryView/Image/JXCategoryImageCell.m
+60
-0
JXCategoryImageCellModel.h
...PagerView/JXCategoryView/Image/JXCategoryImageCellModel.h
+31
-0
JXCategoryImageCellModel.m
...PagerView/JXCategoryView/Image/JXCategoryImageCellModel.m
+13
-0
JXCategoryImageView.h
...es/JXPagerView/JXCategoryView/Image/JXCategoryImageView.h
+33
-0
JXCategoryImageView.m
...es/JXPagerView/JXCategoryView/Image/JXCategoryImageView.m
+92
-0
JXCategoryIndicatorBackgroundView.h
...icator/IndicatorViews/JXCategoryIndicatorBackgroundView.h
+23
-0
JXCategoryIndicatorBackgroundView.m
...icator/IndicatorViews/JXCategoryIndicatorBackgroundView.m
+113
-0
JXCategoryIndicatorBallView.h
...ew/Indicator/IndicatorViews/JXCategoryIndicatorBallView.h
+19
-0
JXCategoryIndicatorBallView.m
...ew/Indicator/IndicatorViews/JXCategoryIndicatorBallView.m
+179
-0
JXCategoryIndicatorComponentView.h
...dicator/IndicatorViews/JXCategoryIndicatorComponentView.h
+90
-0
JXCategoryIndicatorComponentView.m
...dicator/IndicatorViews/JXCategoryIndicatorComponentView.m
+75
-0
JXCategoryIndicatorImageView.h
...w/Indicator/IndicatorViews/JXCategoryIndicatorImageView.h
+19
-0
JXCategoryIndicatorImageView.m
...w/Indicator/IndicatorViews/JXCategoryIndicatorImageView.m
+102
-0
JXCategoryIndicatorLineView.h
...ew/Indicator/IndicatorViews/JXCategoryIndicatorLineView.h
+27
-0
JXCategoryIndicatorLineView.m
...ew/Indicator/IndicatorViews/JXCategoryIndicatorLineView.m
+195
-0
JXCategoryIndicatorRainbowLineView.h
...cator/IndicatorViews/JXCategoryIndicatorRainbowLineView.h
+22
-0
JXCategoryIndicatorRainbowLineView.m
...cator/IndicatorViews/JXCategoryIndicatorRainbowLineView.m
+38
-0
JXCategoryIndicatorTriangleView.h
...ndicator/IndicatorViews/JXCategoryIndicatorTriangleView.h
+17
-0
JXCategoryIndicatorTriangleView.m
...ndicator/IndicatorViews/JXCategoryIndicatorTriangleView.m
+96
-0
JXCategoryViewAnimator.h
...oryView/Indicator/IndicatorViews/JXCategoryViewAnimator.h
+23
-0
JXCategoryViewAnimator.m
...oryView/Indicator/IndicatorViews/JXCategoryViewAnimator.m
+71
-0
JXCategoryIndicatorCell.h
...erView/JXCategoryView/Indicator/JXCategoryIndicatorCell.h
+13
-0
JXCategoryIndicatorCell.m
...erView/JXCategoryView/Indicator/JXCategoryIndicatorCell.m
+54
-0
JXCategoryIndicatorCellModel.h
...w/JXCategoryView/Indicator/JXCategoryIndicatorCellModel.h
+28
-0
JXCategoryIndicatorCellModel.m
...w/JXCategoryView/Indicator/JXCategoryIndicatorCellModel.m
+13
-0
JXCategoryIndicatorView.h
...erView/JXCategoryView/Indicator/JXCategoryIndicatorView.h
+42
-0
JXCategoryIndicatorView.m
...erView/JXCategoryView/Indicator/JXCategoryIndicatorView.m
+215
-0
JXCategoryView.h
GMBase/Classes/JXPagerView/JXCategoryView/JXCategoryView.h
+24
-0
JXCategoryNumberCell.h
.../JXPagerView/JXCategoryView/Number/JXCategoryNumberCell.h
+13
-0
JXCategoryNumberCell.m
.../JXPagerView/JXCategoryView/Number/JXCategoryNumberCell.m
+57
-0
JXCategoryNumberCellModel.h
...gerView/JXCategoryView/Number/JXCategoryNumberCellModel.h
+20
-0
JXCategoryNumberCellModel.m
...gerView/JXCategoryView/Number/JXCategoryNumberCellModel.m
+13
-0
JXCategoryNumberView.h
.../JXPagerView/JXCategoryView/Number/JXCategoryNumberView.h
+45
-0
JXCategoryNumberView.m
.../JXPagerView/JXCategoryView/Number/JXCategoryNumberView.m
+49
-0
JXCategoryTitleCell.h
...es/JXPagerView/JXCategoryView/Title/JXCategoryTitleCell.h
+17
-0
JXCategoryTitleCell.m
...es/JXPagerView/JXCategoryView/Title/JXCategoryTitleCell.m
+101
-0
JXCategoryTitleCellModel.h
...PagerView/JXCategoryView/Title/JXCategoryTitleCellModel.h
+36
-0
JXCategoryTitleCellModel.m
...PagerView/JXCategoryView/Title/JXCategoryTitleCellModel.m
+13
-0
JXCategoryTitleView.h
...es/JXPagerView/JXCategoryView/Title/JXCategoryTitleView.h
+41
-0
JXCategoryTitleView.m
...es/JXPagerView/JXCategoryView/Title/JXCategoryTitleView.m
+135
-0
JXCategoryTitleImageCell.h
...XCategoryView/Title/TitleImage/JXCategoryTitleImageCell.h
+15
-0
JXCategoryTitleImageCell.m
...XCategoryView/Title/TitleImage/JXCategoryTitleImageCell.m
+119
-0
JXCategoryTitleImageCellModel.h
...goryView/Title/TitleImage/JXCategoryTitleImageCellModel.h
+42
-0
JXCategoryTitleImageCellModel.m
...goryView/Title/TitleImage/JXCategoryTitleImageCellModel.m
+13
-0
JXCategoryTitleImageView.h
...XCategoryView/Title/TitleImage/JXCategoryTitleImageView.h
+35
-0
JXCategoryTitleImageView.m
...XCategoryView/Title/TitleImage/JXCategoryTitleImageView.m
+120
-0
JXPagerCollectionViewCell.h
GMBase/Classes/JXPagerView/JXPagerCollectionViewCell.h
+17
-0
JXPagerCollectionViewCell.m
GMBase/Classes/JXPagerView/JXPagerCollectionViewCell.m
+23
-0
JXPagerListContainerView.h
GMBase/Classes/JXPagerView/JXPagerListContainerView.h
+55
-0
JXPagerListContainerView.m
GMBase/Classes/JXPagerView/JXPagerListContainerView.m
+147
-0
JXPagerListRefreshView.h
GMBase/Classes/JXPagerView/JXPagerListRefreshView.h
+14
-0
JXPagerListRefreshView.m
GMBase/Classes/JXPagerView/JXPagerListRefreshView.m
+85
-0
JXPagerMainTableView.h
GMBase/Classes/JXPagerView/JXPagerMainTableView.h
+19
-0
JXPagerMainTableView.m
GMBase/Classes/JXPagerView/JXPagerMainTableView.m
+25
-0
JXPagerView.h
GMBase/Classes/JXPagerView/JXPagerView.h
+174
-0
JXPagerView.m
GMBase/Classes/JXPagerView/JXPagerView.m
+293
-0
JXPageListContainerView.h
...lasses/JXPagerView/PageListView/JXPageListContainerView.h
+41
-0
JXPageListContainerView.m
...lasses/JXPagerView/PageListView/JXPageListContainerView.m
+98
-0
JXPageListMainTableView.h
...lasses/JXPagerView/PageListView/JXPageListMainTableView.h
+13
-0
JXPageListMainTableView.m
...lasses/JXPagerView/PageListView/JXPageListMainTableView.m
+20
-0
JXPageListView.h
GMBase/Classes/JXPagerView/PageListView/JXPageListView.h
+108
-0
JXPageListView.m
GMBase/Classes/JXPagerView/PageListView/JXPageListView.m
+253
-0
No files found.
GMBase/Classes/JXPagerView/JXCategoryView/Base/JXCategoryBaseCell.h
0 → 100755
View file @
a4f39813
//
// JXCategoryBaseCell.h
// UI系列测试
//
// Created by jiaxin on 2018/3/15.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "JXCategoryBaseCellModel.h"
@interface
JXCategoryBaseCell
:
UICollectionViewCell
@property
(
nonatomic
,
strong
)
JXCategoryBaseCellModel
*
cellModel
;
-
(
void
)
initializeViews
NS_REQUIRES_SUPER
;
-
(
void
)
reloadData
:(
JXCategoryBaseCellModel
*
)
cellModel
NS_REQUIRES_SUPER
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Base/JXCategoryBaseCell.m
0 → 100755
View file @
a4f39813
//
// JXCategoryBaseCell.m
// UI系列测试
//
// Created by jiaxin on 2018/3/15.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryBaseCell.h"
@interface
JXCategoryBaseCell
()
@end
@implementation
JXCategoryBaseCell
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
{
self
=
[
super
initWithFrame
:
frame
];
if
(
self
)
{
[
self
initializeViews
];
}
return
self
;
}
-
(
void
)
initializeViews
{
}
-
(
void
)
reloadData
:
(
JXCategoryBaseCellModel
*
)
cellModel
{
self
.
cellModel
=
cellModel
;
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Base/JXCategoryBaseCellModel.h
0 → 100755
View file @
a4f39813
//
// JXCategoryBaseCellModel.h
// UI系列测试
//
// Created by jiaxin on 2018/3/15.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface
JXCategoryBaseCellModel
:
NSObject
@property
(
nonatomic
,
assign
)
NSUInteger
index
;
@property
(
nonatomic
,
assign
)
BOOL
selected
;
@property
(
nonatomic
,
assign
)
CGFloat
cellWidth
;
@property
(
nonatomic
,
assign
)
CGFloat
cellSpacing
;
@property
(
nonatomic
,
assign
)
BOOL
cellWidthZoomEnabled
;
@property
(
nonatomic
,
assign
)
CGFloat
cellWidthZoomScale
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Base/JXCategoryBaseCellModel.m
0 → 100755
View file @
a4f39813
//
// JXCategoryBaseCellModel.m
// UI系列测试
//
// Created by jiaxin on 2018/3/15.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryBaseCellModel.h"
@implementation
JXCategoryBaseCellModel
-
(
CGFloat
)
cellWidth
{
if
(
_cellWidthZoomEnabled
)
{
return
_cellWidth
*
_cellWidthZoomScale
;
}
return
_cellWidth
;
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Base/JXCategoryBaseView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryView.h
// UI系列测试
//
// Created by jiaxin on 2018/3/15.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "JXCategoryBaseCell.h"
#import "JXCategoryBaseCellModel.h"
#import "JXCategoryCollectionView.h"
#import "JXCategoryViewDefines.h"
@class
JXCategoryBaseView
;
@protocol
JXCategoryViewDelegate
<
NSObject
>
@optional
//为什么会把选中代理分为三个,因为有时候只关心点击选中的,有时候只关心滚动选中的,有时候只关心选中。所以具体情况,使用对应方法。
/**
点击选择或者滚动选中都会调用该方法,如果外部不关心具体是点击还是滚动选中的,只关心选中这个事件,就实现该方法。
@param categoryView categoryView description
@param index 选中的index
*/
-
(
void
)
categoryView
:
(
JXCategoryBaseView
*
)
categoryView
didSelectedItemAtIndex
:
(
NSInteger
)
index
;
/**
点击选中的情况才会调用该方法
@param categoryView categoryView description
@param index 选中的index
*/
-
(
void
)
categoryView
:(
JXCategoryBaseView
*
)
categoryView
didClickSelectedItemAtIndex
:(
NSInteger
)
index
;
/**
滚动选中的情况才会调用该方法
@param categoryView categoryView description
@param index 选中的index
*/
-
(
void
)
categoryView
:(
JXCategoryBaseView
*
)
categoryView
didScrollSelectedItemAtIndex
:(
NSInteger
)
index
;
/**
只有点击的切换才会调用!!!
因为用户点击,contentScrollView即将过渡到目标index的配置。内部默认实现`[self.contentScrollView setContentOffset:CGPointMake(targetIndex*self.contentScrollView.bounds.size.width, 0) animated:YES];`。如果实现该代理方法,以自定义实现为准。比如将animated设置为NO,点击切换时无需滚动效果。类似于今日头条APP。
@param categoryView categoryView description
@param index index description
*/
-
(
void
)
categoryView
:(
JXCategoryBaseView
*
)
categoryView
didClickedItemContentScrollViewTransitionToIndex
:(
NSInteger
)
index
;
/**
正在滚动中的回调
@param categoryView categoryView description
@param leftIndex 正在滚动中,相对位置处于左边的index
@param rightIndex 正在滚动中,相对位置处于右边的index
@param ratio 百分比
*/
-
(
void
)
categoryView
:(
JXCategoryBaseView
*
)
categoryView
scrollingFromLeftIndex
:(
NSInteger
)
leftIndex
toRightIndex
:(
NSInteger
)
rightIndex
ratio
:(
CGFloat
)
ratio
;
@end
@interface
JXCategoryBaseView
:
UIView
@property
(
nonatomic
,
strong
)
JXCategoryCollectionView
*
collectionView
;
@property
(
nonatomic
,
strong
)
NSArray
<
JXCategoryBaseCellModel
*>*
dataSource
;
@property
(
nonatomic
,
weak
)
id
<
JXCategoryViewDelegate
>
delegate
;
@property
(
nonatomic
,
strong
)
UIScrollView
*
contentScrollView
;
//需要关联的contentScrollView
@property
(
nonatomic
,
assign
)
NSInteger
defaultSelectedIndex
;
//修改初始化的时候默认选择的index
@property
(
nonatomic
,
assign
,
readonly
)
NSInteger
selectedIndex
;
@property
(
nonatomic
,
assign
)
CGFloat
contentEdgeInsetLeft
;
//整体内容的左边距,默认JXCategoryViewAutomaticDimension(等于cellSpacing)
@property
(
nonatomic
,
assign
)
CGFloat
contentEdgeInsetRight
;
//整体内容的右边距,默认JXCategoryViewAutomaticDimension(等于cellSpacing)
@property
(
nonatomic
,
assign
)
CGFloat
cellWidth
;
//默认JXCategoryViewAutomaticDimension
@property
(
nonatomic
,
assign
)
CGFloat
cellWidthIncrement
;
//cell宽度补偿。默认:0
@property
(
nonatomic
,
assign
)
CGFloat
cellSpacing
;
//cell之间的间距,默认20
@property
(
nonatomic
,
assign
)
BOOL
averageCellSpacingEnabled
;
//当item内容总宽度小于JXCategoryBaseView的宽度,是否将cellSpacing均分。默认为YES。
//----------------------cellWidthZoomEnabled-----------------------//
//cell宽度的缩放主要是为了腾讯视频、汽车之家效果打造的,一般情况下慎用,不太好控制。
@property
(
nonatomic
,
assign
)
BOOL
cellWidthZoomEnabled
;
//默认为NO
@property
(
nonatomic
,
assign
)
BOOL
cellWidthZoomScrollGradientEnabled
;
//手势滚动中,是否需要更新状态。默认为YES
@property
(
nonatomic
,
assign
)
CGFloat
cellWidthZoomScale
;
//默认1.2,cellWidthZoomEnabled为YES才生效
/**
代码调用选中了目标index的item
@param index 目标index
*/
-
(
void
)
selectItemAtIndex
:(
NSInteger
)
index
;
/**
初始化的时候无需调用。初始化之后更新其他配置属性,需要调用该方法,进行刷新。
*/
-
(
void
)
reloadData
;
/**
刷新指定的index的cell
@param index 指定cell的index
*/
-
(
void
)
reloadCellAtIndex
:(
NSInteger
)
index
;
#pragma mark - Subclass use
-
(
CGRect
)
getTargetCellFrame
:(
NSInteger
)
targetIndex
;
#pragma mark - Subclass Override
-
(
void
)
initializeData
NS_REQUIRES_SUPER
;
-
(
void
)
initializeViews
NS_REQUIRES_SUPER
;
/**
reloadData方法调用,重新生成数据源赋值到self.dataSource
*/
-
(
void
)
refreshDataSource
;
/**
reloadData方法调用,根据数据源重新刷新状态;
*/
-
(
void
)
refreshState
NS_REQUIRES_SUPER
;
/**
用户点击了某个item,刷新选中与取消选中的cellModel
@param selectedCellModel 选中的cellModel
@param unselectedCellModel 取消选中的cellModel
*/
-
(
void
)
refreshSelectedCellModel
:(
JXCategoryBaseCellModel
*
)
selectedCellModel
unselectedCellModel
:(
JXCategoryBaseCellModel
*
)
unselectedCellModel
NS_REQUIRES_SUPER
;
/**
关联的contentScrollView的contentOffset发生了改变
@param contentOffset 偏移量
*/
-
(
void
)
contentOffsetOfContentScrollViewDidChanged
:(
CGPoint
)
contentOffset
NS_REQUIRES_SUPER
;
/**
该方法用于子类重载,如果外部要选中某个index,请使用`- (void)selectItemAtIndex:(NSUInteger)index;`
点击某一个item,或者contentScrollView滚动到某一个item的时候调用。根据selectIndex刷新选中状态。
@param index 选中的index
@param isClicked YES:点击选中;NO:滚动选中。
@return 返回值为NO,表示触发内部某些判断(点击了同一个cell),子类无需后续操作。
*/
-
(
BOOL
)
selectCellAtIndex
:(
NSInteger
)
index
isClicked
:(
BOOL
)
isClicked
NS_REQUIRES_SUPER
;
/**
reloadData时,返回每个cell的宽度
@param index 目标index
@return cellWidth
*/
-
(
CGFloat
)
preferredCellWidthAtIndex
:(
NSInteger
)
index
;
/**
返回自定义cell的class
@return cell class
*/
-
(
Class
)
preferredCellClass
;
/**
refreshState时调用,重置cellModel的状态
@param cellModel 待重置的cellModel
@param index 目标index
*/
-
(
void
)
refreshCellModel
:(
JXCategoryBaseCellModel
*
)
cellModel
index
:(
NSInteger
)
index
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Base/JXCategoryBaseView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryBaseView.m
// UI系列测试
//
// Created by jiaxin on 2018/3/15.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryBaseView.h"
#import "JXCategoryFactory.h"
struct
DelegateFlags
{
unsigned
int
didSelectedItemAtIndexFlag
:
1
;
unsigned
int
didClickSelectedItemAtIndexFlag
:
1
;
unsigned
int
didScrollSelectedItemAtIndexFlag
:
1
;
unsigned
int
didClickedItemContentScrollViewTransitionToIndexFlag
:
1
;
unsigned
int
scrollingFromLeftIndexToRightIndexFlag
:
1
;
};
@interface
JXCategoryBaseView
()
<
UICollectionViewDataSource
,
UICollectionViewDelegate
,
UICollectionViewDelegateFlowLayout
>
@property
(
nonatomic
,
assign
)
struct
DelegateFlags
delegateFlags
;
@property
(
nonatomic
,
assign
)
NSInteger
selectedIndex
;
@property
(
nonatomic
,
assign
)
CGFloat
innerCellSpacing
;
@property
(
nonatomic
,
assign
)
CGPoint
lastContentViewContentOffset
;
@end
@implementation
JXCategoryBaseView
-
(
void
)
dealloc
{
if
(
self
.
contentScrollView
)
{
[
self
.
contentScrollView
removeObserver
:
self
forKeyPath
:
@"contentOffset"
];
}
}
-
(
instancetype
)
initWithFrame
:
(
CGRect
)
frame
{
self
=
[
super
initWithFrame
:
frame
];
if
(
self
)
{
[
self
initializeData
];
[
self
initializeViews
];
}
return
self
;
}
-
(
instancetype
)
initWithCoder
:
(
NSCoder
*
)
coder
{
self
=
[
super
initWithCoder
:
coder
];
if
(
self
)
{
[
self
initializeData
];
[
self
initializeViews
];
}
return
self
;
}
-
(
void
)
setDelegate
:
(
id
<
JXCategoryViewDelegate
>
)
delegate
{
_delegate
=
delegate
;
_delegateFlags
.
didSelectedItemAtIndexFlag
=
[
delegate
respondsToSelector
:
@selector
(
categoryView
:
didSelectedItemAtIndex
:
)];
_delegateFlags
.
didClickSelectedItemAtIndexFlag
=
[
delegate
respondsToSelector
:
@selector
(
categoryView
:
didClickSelectedItemAtIndex
:
)];
_delegateFlags
.
didScrollSelectedItemAtIndexFlag
=
[
delegate
respondsToSelector
:
@selector
(
categoryView
:
didScrollSelectedItemAtIndex
:
)];
_delegateFlags
.
didClickedItemContentScrollViewTransitionToIndexFlag
=
[
delegate
respondsToSelector
:
@selector
(
categoryView
:
didClickedItemContentScrollViewTransitionToIndex
:
)];
_delegateFlags
.
scrollingFromLeftIndexToRightIndexFlag
=
[
delegate
respondsToSelector
:
@selector
(
categoryView
:
scrollingFromLeftIndex
:
toRightIndex
:
ratio
:
)];
}
-
(
void
)
initializeData
{
_dataSource
=
[
NSMutableArray
array
];
_selectedIndex
=
0
;
_cellWidth
=
JXCategoryViewAutomaticDimension
;
_cellWidthIncrement
=
0
;
_cellSpacing
=
20
;
_averageCellSpacingEnabled
=
YES
;
_cellWidthZoomEnabled
=
NO
;
_cellWidthZoomScale
=
1
.
2
;
_cellWidthZoomScrollGradientEnabled
=
YES
;
_contentEdgeInsetLeft
=
JXCategoryViewAutomaticDimension
;
_contentEdgeInsetRight
=
JXCategoryViewAutomaticDimension
;
_lastContentViewContentOffset
=
CGPointZero
;
}
-
(
void
)
initializeViews
{
self
.
collectionView
=
({
UICollectionViewFlowLayout
*
layout
=
[[
UICollectionViewFlowLayout
alloc
]
init
];
layout
.
scrollDirection
=
UICollectionViewScrollDirectionHorizontal
;
JXCategoryCollectionView
*
collectionView
=
[[
JXCategoryCollectionView
alloc
]
initWithFrame
:
self
.
bounds
collectionViewLayout
:
layout
];
collectionView
.
backgroundColor
=
[
UIColor
clearColor
];
collectionView
.
showsHorizontalScrollIndicator
=
NO
;
collectionView
.
showsVerticalScrollIndicator
=
NO
;
collectionView
.
scrollsToTop
=
NO
;
collectionView
.
dataSource
=
self
;
collectionView
.
delegate
=
self
;
[
collectionView
registerClass
:[
self
preferredCellClass
]
forCellWithReuseIdentifier
:
NSStringFromClass
([
self
preferredCellClass
])];
collectionView
.
autoresizingMask
=
UIViewAutoresizingFlexibleWidth
|
UIViewAutoresizingFlexibleHeight
;
collectionView
;
});
[
self
addSubview
:
self
.
collectionView
];
}
-
(
void
)
setDefaultSelectedIndex
:
(
NSInteger
)
defaultSelectedIndex
{
_defaultSelectedIndex
=
defaultSelectedIndex
;
self
.
selectedIndex
=
defaultSelectedIndex
;
}
-
(
void
)
setContentScrollView
:
(
UIScrollView
*
)
contentScrollView
{
if
(
_contentScrollView
!=
nil
)
{
[
_contentScrollView
removeObserver
:
self
forKeyPath
:
@"contentOffset"
];
}
_contentScrollView
=
contentScrollView
;
_contentScrollView
.
scrollsToTop
=
NO
;
[
contentScrollView
addObserver
:
self
forKeyPath
:
@"contentOffset"
options
:
NSKeyValueObservingOptionNew
context
:
nil
];
}
-
(
void
)
reloadData
{
[
self
refreshDataSource
];
[
self
refreshState
];
[
self
.
collectionView
.
collectionViewLayout
invalidateLayout
];
[
self
.
collectionView
reloadData
];
}
-
(
void
)
reloadCellAtIndex
:
(
NSInteger
)
index
{
if
(
index
>=
self
.
dataSource
.
count
)
{
return
;
}
JXCategoryBaseCellModel
*
cellModel
=
self
.
dataSource
[
index
];
[
self
refreshCellModel
:
cellModel
index
:
index
];
JXCategoryBaseCell
*
cell
=
(
JXCategoryBaseCell
*
)[
self
.
collectionView
cellForItemAtIndexPath
:[
NSIndexPath
indexPathForItem
:
index
inSection
:
0
]];
[
cell
reloadData
:
cellModel
];
}
-
(
void
)
selectItemAtIndex
:
(
NSInteger
)
index
{
[
self
selectCellAtIndex
:
index
isClicked
:
YES
];
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
[
self
reloadData
];
}
#pragma mark - Subclass Override
-
(
void
)
refreshDataSource
{
}
-
(
void
)
refreshState
{
if
(
self
.
selectedIndex
>=
self
.
dataSource
.
count
)
{
self
.
selectedIndex
=
0
;
}
self
.
innerCellSpacing
=
self
.
cellSpacing
;
__block
CGFloat
totalItemWidth
=
[
self
getContentEdgeInsetLeft
];
CGFloat
totalCellWidth
=
0
;
for
(
int
i
=
0
;
i
<
self
.
dataSource
.
count
;
i
++
)
{
JXCategoryBaseCellModel
*
cellModel
=
self
.
dataSource
[
i
];
cellModel
.
index
=
i
;
cellModel
.
cellWidth
=
[
self
preferredCellWidthAtIndex
:
i
]
+
self
.
cellWidthIncrement
;
totalCellWidth
+=
cellModel
.
cellWidth
;
cellModel
.
cellWidthZoomEnabled
=
self
.
cellWidthZoomEnabled
;
cellModel
.
cellWidthZoomScale
=
1
.
0
;
cellModel
.
cellSpacing
=
self
.
cellSpacing
;
if
(
i
==
self
.
dataSource
.
count
-
1
)
{
totalItemWidth
+=
cellModel
.
cellWidth
+
[
self
getContentEdgeInsetRight
];
}
else
{
totalItemWidth
+=
cellModel
.
cellWidth
+
self
.
cellSpacing
;
}
if
(
i
==
self
.
selectedIndex
)
{
cellModel
.
selected
=
YES
;
cellModel
.
cellWidthZoomScale
=
self
.
cellWidthZoomScale
;
}
else
{
cellModel
.
selected
=
NO
;
}
[
self
refreshCellModel
:
cellModel
index
:
i
];
}
if
(
self
.
averageCellSpacingEnabled
&&
totalItemWidth
<
self
.
bounds
.
size
.
width
)
{
//如果总的内容宽度都没有超过视图度,就将cellWidth等分
NSInteger
cellSpacingItemCount
=
self
.
dataSource
.
count
-
1
;
CGFloat
totalCellSpacingWidth
=
self
.
bounds
.
size
.
width
-
totalCellWidth
;
//如果内容左边距是Automatic,就加1
if
(
self
.
contentEdgeInsetLeft
==
JXCategoryViewAutomaticDimension
)
{
cellSpacingItemCount
+=
1
;
}
else
{
totalCellSpacingWidth
-=
self
.
contentEdgeInsetLeft
;
}
//如果内容右边距是Automatic,就加1
if
(
self
.
contentEdgeInsetRight
==
JXCategoryViewAutomaticDimension
)
{
cellSpacingItemCount
+=
1
;
}
else
{
totalCellSpacingWidth
-=
self
.
contentEdgeInsetRight
;
}
CGFloat
cellSpacing
=
0
;
if
(
cellSpacingItemCount
>
0
)
{
cellSpacing
=
totalCellSpacingWidth
/
cellSpacingItemCount
;
}
self
.
innerCellSpacing
=
cellSpacing
;
[
self
.
dataSource
enumerateObjectsUsingBlock
:
^
(
JXCategoryBaseCellModel
*
_Nonnull
obj
,
NSUInteger
idx
,
BOOL
*
_Nonnull
stop
)
{
obj
.
cellSpacing
=
cellSpacing
;
}];
}
__block
CGFloat
frameXOfSelectedCell
=
self
.
innerCellSpacing
;
__block
CGFloat
selectedCellWidth
=
0
;
totalItemWidth
=
self
.
innerCellSpacing
;
[
self
.
dataSource
enumerateObjectsUsingBlock
:
^
(
JXCategoryBaseCellModel
*
cellModel
,
NSUInteger
idx
,
BOOL
*
_Nonnull
stop
)
{
if
(
idx
<
self
.
selectedIndex
)
{
frameXOfSelectedCell
+=
cellModel
.
cellWidth
+
self
.
innerCellSpacing
;
}
else
if
(
idx
==
self
.
selectedIndex
)
{
selectedCellWidth
=
cellModel
.
cellWidth
;
}
totalItemWidth
+=
cellModel
.
cellWidth
+
self
.
innerCellSpacing
;
}];
CGFloat
minX
=
0
;
CGFloat
maxX
=
totalItemWidth
-
self
.
bounds
.
size
.
width
;
CGFloat
targetX
=
frameXOfSelectedCell
-
self
.
bounds
.
size
.
width
/
2
.
0
+
selectedCellWidth
/
2
.
0
;
[
self
.
collectionView
setContentOffset
:
CGPointMake
(
MAX
(
MIN
(
maxX
,
targetX
),
minX
),
0
)
animated
:
NO
];
if
(
CGRectEqualToRect
(
self
.
contentScrollView
.
frame
,
CGRectZero
)
&&
self
.
contentScrollView
.
superview
!=
nil
)
{
//某些情况、系统会出现JXCategoryView先布局,contentScrollView后布局。就会导致下面指定defaultSelectedIndex失效,所以发现frame为zero时,强行触发布局。
[
self
.
contentScrollView
.
superview
setNeedsLayout
];
[
self
.
contentScrollView
.
superview
layoutIfNeeded
];
}
[
self
.
contentScrollView
setContentOffset
:
CGPointMake
(
self
.
selectedIndex
*
self
.
contentScrollView
.
bounds
.
size
.
width
,
0
)
animated
:
NO
];
}
-
(
BOOL
)
selectCellAtIndex
:
(
NSInteger
)
targetIndex
isClicked
:
(
BOOL
)
isClicked
{
return
[
self
_selectCellAtIndex
:
targetIndex
isClicked
:
isClicked
];
}
-
(
BOOL
)
_selectCellAtIndex
:
(
NSInteger
)
targetIndex
isClicked
:
(
BOOL
)
isClicked
{
if
(
targetIndex
>=
self
.
dataSource
.
count
)
{
return
NO
;
}
if
(
self
.
selectedIndex
==
targetIndex
)
{
if
(
isClicked
)
{
if
(
self
.
delegateFlags
.
didClickSelectedItemAtIndexFlag
)
{
[
self
.
delegate
categoryView
:
self
didClickSelectedItemAtIndex
:
targetIndex
];
}
}
else
{
if
(
self
.
delegateFlags
.
didScrollSelectedItemAtIndexFlag
)
{
[
self
.
delegate
categoryView
:
self
didScrollSelectedItemAtIndex
:
targetIndex
];
}
}
if
(
self
.
delegateFlags
.
didSelectedItemAtIndexFlag
)
{
[
self
.
delegate
categoryView
:
self
didSelectedItemAtIndex
:
targetIndex
];
}
return
NO
;
}
JXCategoryBaseCellModel
*
lastCellModel
=
self
.
dataSource
[
self
.
selectedIndex
];
JXCategoryBaseCellModel
*
selectedCellModel
=
self
.
dataSource
[
targetIndex
];
[
self
refreshSelectedCellModel
:
selectedCellModel
unselectedCellModel
:
lastCellModel
];
JXCategoryBaseCell
*
lastCell
=
(
JXCategoryBaseCell
*
)[
self
.
collectionView
cellForItemAtIndexPath
:[
NSIndexPath
indexPathForItem
:
self
.
selectedIndex
inSection
:
0
]];
[
lastCell
reloadData
:
lastCellModel
];
JXCategoryBaseCell
*
selectedCell
=
(
JXCategoryBaseCell
*
)[
self
.
collectionView
cellForItemAtIndexPath
:[
NSIndexPath
indexPathForItem
:
targetIndex
inSection
:
0
]];
[
selectedCell
reloadData
:
selectedCellModel
];
if
(
self
.
cellWidthZoomEnabled
)
{
[
self
.
collectionView
.
collectionViewLayout
invalidateLayout
];
//延时为了解决cellwidth变化,点击最后几个cell,scrollToItem会出现位置偏移bug
dispatch_after
(
dispatch_time
(
DISPATCH_TIME_NOW
,
(
int64_t
)(
0
.
01
*
NSEC_PER_SEC
)),
dispatch_get_main_queue
(),
^
{
[
self
.
collectionView
scrollToItemAtIndexPath
:[
NSIndexPath
indexPathForItem
:
targetIndex
inSection
:
0
]
atScrollPosition
:
UICollectionViewScrollPositionCenteredHorizontally
animated
:
YES
];
});
}
else
{
[
self
.
collectionView
scrollToItemAtIndexPath
:[
NSIndexPath
indexPathForItem
:
targetIndex
inSection
:
0
]
atScrollPosition
:
UICollectionViewScrollPositionCenteredHorizontally
animated
:
YES
];
}
if
(
isClicked
)
{
if
(
self
.
delegateFlags
.
didClickedItemContentScrollViewTransitionToIndexFlag
)
{
[
self
.
delegate
categoryView
:
self
didClickedItemContentScrollViewTransitionToIndex
:
targetIndex
];
}
else
{
[
self
.
contentScrollView
setContentOffset
:
CGPointMake
(
targetIndex
*
self
.
contentScrollView
.
bounds
.
size
.
width
,
0
)
animated
:
YES
];
}
}
self
.
selectedIndex
=
targetIndex
;
if
(
isClicked
)
{
if
(
self
.
delegateFlags
.
didClickSelectedItemAtIndexFlag
)
{
[
self
.
delegate
categoryView
:
self
didClickSelectedItemAtIndex
:
targetIndex
];
}
}
else
{
if
(
self
.
delegateFlags
.
didScrollSelectedItemAtIndexFlag
)
{
[
self
.
delegate
categoryView
:
self
didScrollSelectedItemAtIndex
:
targetIndex
];
}
}
if
(
self
.
delegateFlags
.
didSelectedItemAtIndexFlag
)
{
[
self
.
delegate
categoryView
:
self
didSelectedItemAtIndex
:
targetIndex
];
}
return
YES
;
}
-
(
void
)
refreshSelectedCellModel
:
(
JXCategoryBaseCellModel
*
)
selectedCellModel
unselectedCellModel
:
(
JXCategoryBaseCellModel
*
)
unselectedCellModel
{
selectedCellModel
.
selected
=
YES
;
selectedCellModel
.
cellWidthZoomScale
=
self
.
cellWidthZoomScale
;
unselectedCellModel
.
selected
=
NO
;
unselectedCellModel
.
cellWidthZoomScale
=
1
.
0
;
}
-
(
void
)
contentOffsetOfContentScrollViewDidChanged
:
(
CGPoint
)
contentOffset
{
CGFloat
ratio
=
contentOffset
.
x
/
self
.
contentScrollView
.
bounds
.
size
.
width
;
if
(
ratio
>
self
.
dataSource
.
count
-
1
||
ratio
<
0
)
{
//超过了边界,不需要处理
return
;
}
if
(
contentOffset
.
x
==
0
&&
self
.
selectedIndex
==
0
&&
self
.
lastContentViewContentOffset
.
x
==
0
)
{
//滚动到了最左边,且已经选中了第一个,且之前的contentOffset.x为0
return
;
}
CGFloat
maxContentOffsetX
=
self
.
contentScrollView
.
contentSize
.
width
-
self
.
contentScrollView
.
bounds
.
size
.
width
;
if
(
contentOffset
.
x
==
maxContentOffsetX
&&
self
.
selectedIndex
==
self
.
dataSource
.
count
-
1
&&
self
.
lastContentViewContentOffset
.
x
==
maxContentOffsetX
)
{
//滚动到了最右边,且已经选中了最后一个,且之前的contentOffset.x为maxContentOffsetX
return
;
}
ratio
=
MAX
(
0
,
MIN
(
self
.
dataSource
.
count
-
1
,
ratio
));
NSInteger
baseIndex
=
floorf
(
ratio
);
CGFloat
remainderRatio
=
ratio
-
baseIndex
;
if
(
remainderRatio
==
0
)
{
//滑动翻页,需要更新选中状态
//滑动一小段距离,然后放开回到原位,contentOffset同样的值会回调多次。例如在index为1的情况,滑动放开回到原位,contentOffset会多次回调CGPoint(width, 0)
if
(
!
(
self
.
lastContentViewContentOffset
.
x
==
contentOffset
.
x
&&
self
.
selectedIndex
==
baseIndex
))
{
[
self
scrollselectItemAtIndex
:
baseIndex
];
}
}
else
{
//快速滑动翻页,当remainderRatio没有变成0,但是已经翻页了,需要通过下面的判断,触发选中
if
(
fabs
(
ratio
-
self
.
selectedIndex
)
>
1
)
{
NSInteger
targetIndex
=
baseIndex
;
if
(
ratio
<
self
.
selectedIndex
)
{
targetIndex
=
baseIndex
+
1
;
}
[
self
_selectCellAtIndex
:
targetIndex
isClicked
:
NO
];
}
if
(
self
.
cellWidthZoomEnabled
&&
self
.
cellWidthZoomScrollGradientEnabled
)
{
JXCategoryBaseCellModel
*
leftCellModel
=
(
JXCategoryBaseCellModel
*
)
self
.
dataSource
[
baseIndex
];
JXCategoryBaseCellModel
*
rightCellModel
=
(
JXCategoryBaseCellModel
*
)
self
.
dataSource
[
baseIndex
+
1
];
leftCellModel
.
cellWidthZoomScale
=
[
JXCategoryFactory
interpolationFrom
:
self
.
cellWidthZoomScale
to
:
1
.
0
percent
:
remainderRatio
];
rightCellModel
.
cellWidthZoomScale
=
[
JXCategoryFactory
interpolationFrom
:
1
.
0
to
:
self
.
cellWidthZoomScale
percent
:
remainderRatio
];
[
self
.
collectionView
.
collectionViewLayout
invalidateLayout
];
}
if
(
self
.
delegateFlags
.
scrollingFromLeftIndexToRightIndexFlag
)
{
[
self
.
delegate
categoryView
:
self
scrollingFromLeftIndex
:
baseIndex
toRightIndex
:
baseIndex
+
1
ratio
:
remainderRatio
];
}
}
}
-
(
CGFloat
)
preferredCellWidthAtIndex
:
(
NSInteger
)
index
{
return
0
;
}
-
(
Class
)
preferredCellClass
{
return
JXCategoryBaseCell
.
class
;
}
-
(
void
)
refreshCellModel
:
(
JXCategoryBaseCellModel
*
)
cellModel
index
:
(
NSInteger
)
index
{
}
#pragma mark - <UICollectionViewDataSource, UICollectionViewDelegate>
-
(
NSInteger
)
numberOfSectionsInCollectionView
:
(
UICollectionView
*
)
collectionView
{
return
1
;
}
-
(
NSInteger
)
collectionView
:
(
UICollectionView
*
)
collectionView
numberOfItemsInSection
:
(
NSInteger
)
section
{
return
self
.
dataSource
.
count
;
}
-
(
UICollectionViewCell
*
)
collectionView
:
(
UICollectionView
*
)
collectionView
cellForItemAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
return
[
collectionView
dequeueReusableCellWithReuseIdentifier
:
NSStringFromClass
([
self
preferredCellClass
])
forIndexPath
:
indexPath
];
}
-
(
void
)
collectionView
:
(
UICollectionView
*
)
collectionView
willDisplayCell
:
(
UICollectionViewCell
*
)
cell
forItemAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
JXCategoryBaseCell
*
categoryCell
=
(
JXCategoryBaseCell
*
)
cell
;
[
categoryCell
reloadData
:
self
.
dataSource
[
indexPath
.
item
]];
}
-
(
void
)
collectionView
:
(
UICollectionView
*
)
collectionView
didSelectItemAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
[
self
clickselectItemAtIndex
:
indexPath
.
row
];
}
#pragma mark - <UICollectionViewDelegateFlowLayout>
-
(
UIEdgeInsets
)
collectionView
:
(
UICollectionView
*
)
collectionView
layout
:
(
UICollectionViewLayout
*
)
collectionViewLayout
insetForSectionAtIndex
:
(
NSInteger
)
section
{
return
UIEdgeInsetsMake
(
0
,
[
self
getContentEdgeInsetLeft
],
0
,
[
self
getContentEdgeInsetRight
]);
}
-
(
CGSize
)
collectionView
:
(
UICollectionView
*
)
collectionView
layout
:
(
UICollectionViewLayout
*
)
collectionViewLayout
sizeForItemAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
JXCategoryBaseCellModel
*
cellModel
=
self
.
dataSource
[
indexPath
.
item
];
return
CGSizeMake
(
cellModel
.
cellWidth
,
self
.
bounds
.
size
.
height
);
}
-
(
CGFloat
)
collectionView
:
(
UICollectionView
*
)
collectionView
layout
:
(
UICollectionViewLayout
*
)
collectionViewLayout
minimumLineSpacingForSectionAtIndex
:
(
NSInteger
)
section
{
return
self
.
innerCellSpacing
;
}
-
(
CGFloat
)
collectionView
:
(
UICollectionView
*
)
collectionView
layout
:
(
UICollectionViewLayout
*
)
collectionViewLayout
minimumInteritemSpacingForSectionAtIndex
:
(
NSInteger
)
section
{
return
self
.
innerCellSpacing
;
}
#pragma mark - KVO
-
(
void
)
observeValueForKeyPath
:
(
NSString
*
)
keyPath
ofObject
:
(
id
)
object
change
:
(
NSDictionary
<
NSKeyValueChangeKey
,
id
>
*
)
change
context
:
(
void
*
)
context
{
if
([
keyPath
isEqualToString
:
@"contentOffset"
])
{
CGPoint
contentOffset
=
[
change
[
NSKeyValueChangeNewKey
]
CGPointValue
];
if
((
self
.
contentScrollView
.
isTracking
||
self
.
contentScrollView
.
isDecelerating
))
{
//用户滚动引起的contentOffset变化,才处理。
[
self
contentOffsetOfContentScrollViewDidChanged
:
contentOffset
];
}
self
.
lastContentViewContentOffset
=
contentOffset
;
}
}
#pragma mark - Other
-
(
CGRect
)
getTargetCellFrame
:
(
NSInteger
)
targetIndex
{
CGFloat
x
=
[
self
getContentEdgeInsetLeft
];
for
(
int
i
=
0
;
i
<
targetIndex
;
i
++
)
{
JXCategoryBaseCellModel
*
cellModel
=
self
.
dataSource
[
i
];
x
+=
cellModel
.
cellWidth
+
self
.
innerCellSpacing
;
}
CGFloat
width
=
self
.
dataSource
[
targetIndex
].
cellWidth
;
return
CGRectMake
(
x
,
0
,
width
,
self
.
bounds
.
size
.
height
);
}
#pragma mark - Private
-
(
CGFloat
)
getContentEdgeInsetLeft
{
if
(
self
.
contentEdgeInsetLeft
==
JXCategoryViewAutomaticDimension
)
{
return
self
.
innerCellSpacing
;
}
return
self
.
contentEdgeInsetLeft
;
}
-
(
CGFloat
)
getContentEdgeInsetRight
{
if
(
self
.
contentEdgeInsetRight
==
JXCategoryViewAutomaticDimension
)
{
return
self
.
innerCellSpacing
;
}
return
self
.
contentEdgeInsetRight
;
}
-
(
void
)
clickselectItemAtIndex
:
(
NSInteger
)
index
{
[
self
selectCellAtIndex
:
index
isClicked
:
YES
];
}
-
(
void
)
scrollselectItemAtIndex
:
(
NSInteger
)
index
{
[
self
selectCellAtIndex
:
index
isClicked
:
NO
];
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Common/JXCategoryCollectionView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryCollectionView.h
// UI系列测试
//
// Created by jiaxin on 2018/3/21.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "JXCategoryIndicatorProtocol.h"
@interface
JXCategoryCollectionView
:
UICollectionView
@property
(
nonatomic
,
strong
)
NSArray
<
UIView
<
JXCategoryIndicatorProtocol
>
*>
*
indicators
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Common/JXCategoryCollectionView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryCollectionView.m
// UI系列测试
//
// Created by jiaxin on 2018/3/21.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryCollectionView.h"
@implementation
JXCategoryCollectionView
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
for
(
UIView
<
JXCategoryIndicatorProtocol
>
*
view
in
self
.
indicators
)
{
[
self
sendSubviewToBack
:
view
];
}
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Common/JXCategoryFactory.h
0 → 100755
View file @
a4f39813
//
// 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
GMBase/Classes/JXPagerView/JXCategoryView/Common/JXCategoryFactory.m
0 → 100755
View file @
a4f39813
//
// 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
));
NSLog
(
@"percent---%.2f"
,
percent
);
NSLog
(
@"from + (to - from)*---%.2f"
,
(
from
+
(
to
-
from
)
*
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
GMBase/Classes/JXPagerView/JXCategoryView/Common/JXCategoryIndicatorParamsModel.h
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorParamsModel.h
// JXCategoryView
//
// Created by jiaxin on 2018/12/13.
// Copyright © 2018 jiaxin. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
/**
指示器不同情况处理时传递的数据模型,不同情况会对不同的属性赋值,根据不同情况的api说明确认。
为什么会通过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
)
BOOL
isClicked
;
//YES:通过点击选中;NO:通过滚动选中
@end
GMBase/Classes/JXPagerView/JXCategoryView/Common/JXCategoryIndicatorParamsModel.m
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorParamsModel.m
// JXCategoryView
//
// Created by jiaxin on 2018/12/13.
// Copyright © 2018 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorParamsModel.h"
@implementation
JXCategoryIndicatorParamsModel
@end
GMBase/Classes/JXPagerView/JXCategoryView/Common/JXCategoryIndicatorProtocol.h
0 → 100755
View file @
a4f39813
//
// 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
>
/**
视图重置状态时调用
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 isClicked YES:点击选中;NO:滚动选中。
@param model 数据模型
*/
-
(
void
)
jx_selectedCell
:(
JXCategoryIndicatorParamsModel
*
)
model
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Common/JXCategoryListContainerView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryListScrollView.h
// JXCategoryView
//
// Created by jiaxin on 2018/9/12.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
@class
JXCategoryListContainerView
;
@protocol
JXCategoryListContentViewDelegate
<
NSObject
>
/**
如果列表是VC,就返回VC.view
如果列表是View,就返回View自己
@return 返回列表视图
*/
-
(
UIView
*
)
listView
;
@optional
/**
可选实现,列表逻辑层面显示的时候调用
*/
-
(
void
)
listDidAppear
;
/**
可选实现,列表逻辑层面消失的时候调用
*/
-
(
void
)
listDidDisappear
;
@end
@protocol
JXCategoryListContainerViewDelegate
<
NSObject
>
/**
返回list的数量
@param listContainerView 列表的容器视图
@return list的数量
*/
-
(
NSInteger
)
numberOfListsInlistContainerView
:
(
JXCategoryListContainerView
*
)
listContainerView
;
/**
根据index初始化对应的遵从JXCategoryListContentViewDelegate协议的list,注意是初始化哟,要new一个新的实例!!!
@param listContainerView 列表的容器视图
@param index 目标下标
@return 新的遵从JXCategoryListContentViewDelegate协议的list实例
*/
-
(
id
<
JXCategoryListContentViewDelegate
>
)
listContainerView
:(
JXCategoryListContainerView
*
)
listContainerView
initListForIndex
:(
NSInteger
)
index
;
@end
@interface
JXCategoryListContainerView
:
UIView
@property
(
nonatomic
,
strong
,
readonly
)
UIScrollView
*
scrollView
;
/**
滚动切换的时候,滚动距离超过一页的多少百分比,就认为切换了页面。默认0.5(即滚动超过了半屏,就认为翻页了)。范围0~1,开区间不包括0和1
*/
@property
(
nonatomic
,
assign
)
CGFloat
didAppearPercent
;
/**
需要和self.categoryView.defaultSelectedIndex保持一致
*/
@property
(
nonatomic
,
assign
)
NSInteger
defaultSelectedIndex
;
-
(
instancetype
)
init
NS_UNAVAILABLE
;
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
NS_UNAVAILABLE
;
-
(
instancetype
)
initWithCoder
:(
NSCoder
*
)
aDecoder
NS_UNAVAILABLE
;
/**
指定的初始化器
@param parentVC 父vc
@param delegate JXCategoryListContainerViewDelegate代理
@return JXCategoryListContainerView实例
*/
-
(
instancetype
)
initWithParentVC
:(
UIViewController
*
)
parentVC
delegate
:(
id
<
JXCategoryListContainerViewDelegate
>
)
delegate
NS_DESIGNATED_INITIALIZER
;
-
(
void
)
reloadData
;
//必须调用,请按照demo示例那样调用
-
(
void
)
scrollingFromLeftIndex
:(
NSInteger
)
leftIndex
toRightIndex
:(
NSInteger
)
rightIndex
ratio
:(
CGFloat
)
ratio
selectedIndex
:(
NSInteger
)
selectedIndex
;
//必须调用,请按照demo示例那样调用(注意是是点击选中的回调,不是其他回调)
-
(
void
)
didClickSelectedItemAtIndex
:(
NSInteger
)
index
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Common/JXCategoryListContainerView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryListContainerView.m
// JXCategoryView
//
// Created by jiaxin on 2018/9/12.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryListContainerView.h"
@interface
JXCategoryListContainerView
()
@property
(
nonatomic
,
weak
)
id
<
JXCategoryListContainerViewDelegate
>
delegate
;
@property
(
nonatomic
,
weak
)
UIViewController
*
parentViewController
;
@property
(
nonatomic
,
strong
)
UIScrollView
*
scrollView
;
@property
(
nonatomic
,
assign
)
NSInteger
currentIndex
;
@property
(
nonatomic
,
strong
)
NSMutableDictionary
<
NSNumber
*
,
id
<
JXCategoryListContentViewDelegate
>>
*
listVCDict
;
@property
(
nonatomic
,
assign
)
BOOL
isLayoutSubviewsed
;
@end
@implementation
JXCategoryListContainerView
-
(
instancetype
)
initWithParentVC
:(
UIViewController
*
)
parentVC
delegate
:(
id
<
JXCategoryListContainerViewDelegate
>
)
delegate
{
self
=
[
super
initWithFrame
:
CGRectZero
];
if
(
self
)
{
_didAppearPercent
=
0
.
5
;
_parentViewController
=
parentVC
;
_parentViewController
.
automaticallyAdjustsScrollViewInsets
=
NO
;
_delegate
=
delegate
;
_listVCDict
=
[
NSMutableDictionary
dictionary
];
[
self
initializeViews
];
}
return
self
;
}
-
(
void
)
initializeViews
{
_scrollView
=
[[
UIScrollView
alloc
]
init
];
self
.
scrollView
.
pagingEnabled
=
YES
;
self
.
scrollView
.
showsHorizontalScrollIndicator
=
NO
;
self
.
scrollView
.
showsHorizontalScrollIndicator
=
NO
;
self
.
scrollView
.
scrollsToTop
=
NO
;
self
.
scrollView
.
bounces
=
NO
;
if
(
@available
(
iOS
11
.
0
,
*
))
{
self
.
scrollView
.
contentInsetAdjustmentBehavior
=
UIScrollViewContentInsetAdjustmentNever
;
}
[
self
addSubview
:
self
.
scrollView
];
}
-
(
void
)
reloadData
{
for
(
id
<
JXCategoryListContentViewDelegate
>
list
in
self
.
listVCDict
.
allValues
)
{
[
list
.
listView
removeFromSuperview
];
}
[
self
.
listVCDict
removeAllObjects
];
self
.
scrollView
.
contentSize
=
CGSizeMake
(
self
.
scrollView
.
bounds
.
size
.
width
*
[
self
.
delegate
numberOfListsInlistContainerView
:
self
],
self
.
scrollView
.
bounds
.
size
.
height
);
[
self
listDidAppear
:
self
.
currentIndex
];
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
self
.
scrollView
.
frame
=
self
.
bounds
;
self
.
scrollView
.
contentSize
=
CGSizeMake
(
self
.
scrollView
.
bounds
.
size
.
width
*
[
self
.
delegate
numberOfListsInlistContainerView
:
self
],
self
.
scrollView
.
bounds
.
size
.
height
);
if
(
!
self
.
isLayoutSubviewsed
)
{
self
.
isLayoutSubviewsed
=
YES
;
//初始化第一次调用
[
self
listDidAppear
:
self
.
currentIndex
];
}
}
-
(
void
)
setDefaultSelectedIndex
:
(
NSInteger
)
defaultSelectedIndex
{
_defaultSelectedIndex
=
defaultSelectedIndex
;
self
.
currentIndex
=
defaultSelectedIndex
;
}
#pragma mark - JXCategoryBaseView回调
-
(
void
)
scrollingFromLeftIndex
:
(
NSInteger
)
leftIndex
toRightIndex
:
(
NSInteger
)
rightIndex
ratio
:
(
CGFloat
)
ratio
selectedIndex
:
(
NSInteger
)
selectedIndex
{
NSInteger
targetIndex
=
-
1
;
NSInteger
disappearIndex
=
-
1
;
if
(
rightIndex
==
selectedIndex
)
{
//当前选中的在右边,用户正在从右边往左边滑动
if
(
ratio
<
(
1
-
self
.
didAppearPercent
))
{
targetIndex
=
leftIndex
;
disappearIndex
=
rightIndex
;
}
}
else
{
//当前选中的在左边,用户正在从左边往右边滑动
if
(
ratio
>
self
.
didAppearPercent
)
{
targetIndex
=
rightIndex
;
disappearIndex
=
leftIndex
;
}
}
if
(
targetIndex
!=
-
1
&&
self
.
currentIndex
!=
targetIndex
)
{
[
self
listDidAppear
:
targetIndex
];
[
self
listDidDisappear
:
disappearIndex
];
}
}
-
(
void
)
didClickSelectedItemAtIndex
:
(
NSInteger
)
index
{
[
self
listDidDisappear
:
self
.
currentIndex
];
[
self
listDidAppear
:
index
];
}
#pragma mark - Private
-
(
void
)
listDidAppear
:
(
NSInteger
)
index
{
self
.
currentIndex
=
index
;
id
<
JXCategoryListContentViewDelegate
>
list
=
self
.
listVCDict
[
@
(
index
)];
if
(
list
==
nil
)
{
list
=
[
self
.
delegate
listContainerView
:
self
initListForIndex
:
index
];
}
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
];
self
.
listVCDict
[
@
(
index
)]
=
list
;
}
if
(
list
&&
[
list
respondsToSelector
:
@selector
(
listDidAppear
)])
{
[
list
listDidAppear
];
}
}
-
(
void
)
listDidDisappear
:
(
NSInteger
)
index
{
id
<
JXCategoryListContentViewDelegate
>
list
=
self
.
listVCDict
[
@
(
index
)];
if
(
list
&&
[
list
respondsToSelector
:
@selector
(
listDidDisappear
)])
{
[
list
listDidDisappear
];
}
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Common/JXCategoryListVCContainerView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryListScrollView.h
// JXCategoryView
//
// Created by jiaxin on 2018/9/12.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
此类已不再维护,推荐使用JXCategoryListContainerView类!!!
*/
@interface
JXCategoryListVCContainerView
:
UIView
@property
(
nonatomic
,
weak
)
UIViewController
*
parentViewController
;
@property
(
nonatomic
,
strong
,
readonly
)
UIScrollView
*
scrollView
;
@property
(
nonatomic
,
strong
)
NSArray
<
UIViewController
*>
*
listVCArray
;
//这个defaultSelectedIndex仅仅用于触发对应index的数据加载,如果要让categoryView和listView都处于对应的index。还应该添加后面这段代码:self.categoryView.defaultSelectedIndex = n
@property
(
nonatomic
,
assign
)
NSInteger
defaultSelectedIndex
;
-
(
void
)
reloadData
;
-
(
void
)
scrollingFromLeftIndex
:(
NSInteger
)
leftIndex
toRightIndex
:(
NSInteger
)
rightIndex
ratio
:(
CGFloat
)
ratio
;
-
(
void
)
didClickSelectedItemAtIndex
:(
NSInteger
)
index
;
-
(
void
)
didScrollSelectedItemAtIndex
:(
NSInteger
)
index
;
-
(
void
)
parentVCWillAppear
:(
BOOL
)
animated
;
-
(
void
)
parentVCDidAppear
:(
BOOL
)
animated
;
-
(
void
)
parentVCWillDisappear
:(
BOOL
)
animated
;
-
(
void
)
parentVCDidDisappear
:(
BOOL
)
animated
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Common/JXCategoryListVCContainerView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryListContainerView.m
// JXCategoryView
//
// Created by jiaxin on 2018/9/12.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryListVCContainerView.h"
@interface
JXCategoryListVCContainerView
()
<
UIScrollViewDelegate
>
@property
(
nonatomic
,
strong
)
UIScrollView
*
scrollView
;
@property
(
nonatomic
,
assign
)
NSInteger
currentIndex
;
@property
(
nonatomic
,
assign
)
NSInteger
targetIndex
;
@end
@implementation
JXCategoryListVCContainerView
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
{
self
=
[
super
initWithFrame
:
frame
];
if
(
self
)
{
[
self
initializeViews
];
}
return
self
;
}
-
(
instancetype
)
initWithCoder
:(
NSCoder
*
)
coder
{
self
=
[
super
initWithCoder
:
coder
];
if
(
self
)
{
[
self
initializeViews
];
}
return
self
;
}
-
(
void
)
initializeViews
{
_scrollView
=
[[
UIScrollView
alloc
]
init
];
self
.
scrollView
.
pagingEnabled
=
YES
;
self
.
scrollView
.
showsHorizontalScrollIndicator
=
NO
;
[
self
addSubview
:
self
.
scrollView
];
}
-
(
void
)
reloadData
{
[
self
listVCWillAppear
:
self
.
defaultSelectedIndex
];
[
self
listVCDidAppear
:
self
.
defaultSelectedIndex
];
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
self
.
scrollView
.
frame
=
self
.
bounds
;
//根据新的数据源重新添加listView
for
(
int
i
=
0
;
i
<
self
.
listVCArray
.
count
;
i
++
)
{
UIViewController
*
listVC
=
self
.
listVCArray
[
i
];
[
listVC
willMoveToParentViewController
:
self
.
parentViewController
];
[
self
.
parentViewController
addChildViewController
:
self
.
parentViewController
];
[
listVC
didMoveToParentViewController
:
self
.
parentViewController
];
listVC
.
view
.
frame
=
CGRectMake
(
i
*
self
.
scrollView
.
bounds
.
size
.
width
,
0
,
self
.
scrollView
.
bounds
.
size
.
width
,
self
.
scrollView
.
bounds
.
size
.
height
);
[
self
.
scrollView
addSubview
:
listVC
.
view
];
}
self
.
scrollView
.
contentSize
=
CGSizeMake
(
self
.
scrollView
.
bounds
.
size
.
width
*
self
.
listVCArray
.
count
,
self
.
scrollView
.
bounds
.
size
.
height
);
}
-
(
void
)
setListVCArray
:
(
NSArray
<
UIViewController
*>
*
)
listVCArray
{
for
(
UIViewController
*
vc
in
self
.
listVCArray
)
{
[
vc
.
view
removeFromSuperview
];
}
_listVCArray
=
listVCArray
;
[
self
setNeedsLayout
];
}
-
(
void
)
setDefaultSelectedIndex
:
(
NSInteger
)
defaultSelectedIndex
{
_defaultSelectedIndex
=
defaultSelectedIndex
;
self
.
currentIndex
=
defaultSelectedIndex
;
}
-
(
void
)
parentVCWillAppear
:
(
BOOL
)
animated
{
[
self
listVCWillAppear
:
self
.
currentIndex
];
}
-
(
void
)
parentVCDidAppear
:
(
BOOL
)
animated
{
[
self
listVCDidAppear
:
self
.
currentIndex
];
}
-
(
void
)
parentVCWillDisappear
:
(
BOOL
)
animated
{
[
self
listVCWillDisappear
:
self
.
currentIndex
];
}
-
(
void
)
parentVCDidDisappear
:
(
BOOL
)
animated
{
[
self
listVCDidDisappear
:
self
.
currentIndex
];
}
-
(
void
)
scrollingFromLeftIndex
:
(
NSInteger
)
leftIndex
toRightIndex
:
(
NSInteger
)
rightIndex
ratio
:
(
CGFloat
)
ratio
{
NSInteger
targetIndex
=
0
;
if
(
ratio
>
0
.
5
)
{
targetIndex
=
rightIndex
;
}
else
{
targetIndex
=
leftIndex
;
}
if
(
self
.
targetIndex
!=
targetIndex
)
{
[
self
listVCWillAppear
:
targetIndex
];
[
self
listVCDidAppear
:
targetIndex
];
//源代码
//[self listVCWillDisappear:self.currentIndex];
//[self listVCDidDisappear:self.currentIndex];
//add by wuna 解决了部分生命周期问题和标题跟页面正确对应问题
if
(
ratio
>
0
.
5
)
{
[
self
listVCWillDisappear
:
leftIndex
];
[
self
listVCDidDisappear
:
leftIndex
];
}
else
{
[
self
listVCWillDisappear
:
rightIndex
];
[
self
listVCDidDisappear
:
rightIndex
];
}
}
}
-
(
void
)
didScrollSelectedItemAtIndex
:
(
NSInteger
)
index
{
}
-
(
void
)
didClickSelectedItemAtIndex
:
(
NSInteger
)
index
{
[
self
listVCWillDisappear
:
self
.
currentIndex
];
[
self
listVCDidDisappear
:
self
.
currentIndex
];
[
self
listVCWillAppear
:
index
];
[
self
listVCDidAppear
:
index
];
}
#pragma mark - Private
-
(
void
)
listVCWillAppear
:
(
NSInteger
)
index
{
self
.
targetIndex
=
index
;
UIViewController
*
vc
=
self
.
listVCArray
[
index
];
[
vc
beginAppearanceTransition
:
YES
animated
:
YES
];
}
-
(
void
)
listVCDidAppear
:
(
NSInteger
)
index
{
self
.
currentIndex
=
index
;
UIViewController
*
vc
=
self
.
listVCArray
[
index
];
[
vc
endAppearanceTransition
];
}
-
(
void
)
listVCWillDisappear
:
(
NSInteger
)
index
{
UIViewController
*
vc
=
self
.
listVCArray
[
index
];
[
vc
beginAppearanceTransition
:
NO
animated
:
YES
];
}
-
(
void
)
listVCDidDisappear
:
(
NSInteger
)
index
{
UIViewController
*
vc
=
self
.
listVCArray
[
index
];
[
vc
endAppearanceTransition
];
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Common/JXCategoryViewDefines.h
0 → 100755
View file @
a4f39813
//
// 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
NS_ENUM
(
NSUInteger
,
JXCategoryComponentPosition
)
{
JXCategoryComponentPosition_Bottom
,
JXCategoryComponentPosition_Top
,
};
typedef
NS_ENUM
(
NSUInteger
,
JXCategoryIndicatorScrollStyle
)
{
JXCategoryIndicatorScrollStyleSimple
,
//简单滚动,即从当前位置过渡到目标位置
JXCategoryIndicatorScrollStyleSameAsUserScroll
,
//和用户左右滚动列表时的效果一样
};
GMBase/Classes/JXPagerView/JXCategoryView/Common/UIColor+JXAdd.h
0 → 100755
View file @
a4f39813
//
// 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
GMBase/Classes/JXPagerView/JXCategoryView/Common/UIColor+JXAdd.m
0 → 100755
View file @
a4f39813
//
// 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
GMBase/Classes/JXPagerView/JXCategoryView/Dot/JXCategoryDotCell.h
0 → 100755
View file @
a4f39813
//
// JXCategoryDotCell.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/20.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryTitleCell.h"
@interface
JXCategoryDotCell
:
JXCategoryTitleCell
@end
GMBase/Classes/JXPagerView/JXCategoryView/Dot/JXCategoryDotCell.m
0 → 100755
View file @
a4f39813
//
// JXCategoryDotCell.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/20.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryDotCell.h"
#import "JXCategoryDotCellModel.h"
@interface
JXCategoryDotCell
()
@property
(
nonatomic
,
strong
)
CALayer
*
dotLayer
;
@end
@implementation
JXCategoryDotCell
-
(
void
)
initializeViews
{
[
super
initializeViews
];
_dotLayer
=
[
CALayer
layer
];
[
self
.
contentView
.
layer
addSublayer
:
self
.
dotLayer
];
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
[
CATransaction
begin
];
[
CATransaction
setDisableActions
:
YES
];
JXCategoryDotCellModel
*
myCellModel
=
(
JXCategoryDotCellModel
*
)
self
.
cellModel
;
self
.
dotLayer
.
bounds
=
CGRectMake
(
0
,
0
,
myCellModel
.
dotSize
.
width
,
myCellModel
.
dotSize
.
height
);
switch
(
myCellModel
.
relativePosition
)
{
case
JXCategoryDotRelativePosition_TopLeft
:
{
self
.
dotLayer
.
position
=
CGPointMake
(
CGRectGetMinX
(
self
.
titleLabel
.
frame
),
CGRectGetMinY
(
self
.
titleLabel
.
frame
));
}
break
;
case
JXCategoryDotRelativePosition_TopRight
:
{
self
.
dotLayer
.
position
=
CGPointMake
(
CGRectGetMaxX
(
self
.
titleLabel
.
frame
),
CGRectGetMinY
(
self
.
titleLabel
.
frame
));
}
break
;
case
JXCategoryDotRelativePosition_BottomLeft
:
{
self
.
dotLayer
.
position
=
CGPointMake
(
CGRectGetMinX
(
self
.
titleLabel
.
frame
),
CGRectGetMaxY
(
self
.
titleLabel
.
frame
));
}
break
;
case
JXCategoryDotRelativePosition_BottomRight
:
{
self
.
dotLayer
.
position
=
CGPointMake
(
CGRectGetMaxX
(
self
.
titleLabel
.
frame
),
CGRectGetMaxY
(
self
.
titleLabel
.
frame
));
}
break
;
default
:
break
;
}
self
.
dotLayer
.
position
=
CGPointMake
(
CGRectGetMaxX
(
self
.
titleLabel
.
frame
),
CGRectGetMinY
(
self
.
titleLabel
.
frame
));
[
CATransaction
commit
];
}
-
(
void
)
reloadData
:
(
JXCategoryBaseCellModel
*
)
cellModel
{
[
super
reloadData
:
cellModel
];
JXCategoryDotCellModel
*
myCellModel
=
(
JXCategoryDotCellModel
*
)
cellModel
;
[
CATransaction
begin
];
[
CATransaction
setDisableActions
:
YES
];
self
.
dotLayer
.
hidden
=
!
myCellModel
.
dotHidden
;
self
.
dotLayer
.
backgroundColor
=
myCellModel
.
dotColor
.
CGColor
;
self
.
dotLayer
.
cornerRadius
=
myCellModel
.
dotCornerRadius
;
[
CATransaction
commit
];
[
self
setNeedsLayout
];
[
self
layoutIfNeeded
];
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Dot/JXCategoryDotCellModel.h
0 → 100755
View file @
a4f39813
//
// JXCategoryDotCellModel.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/20.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryTitleCellModel.h"
typedef
NS_ENUM
(
NSUInteger
,
JXCategoryDotRelativePosition
)
{
JXCategoryDotRelativePosition_TopLeft
=
0
,
JXCategoryDotRelativePosition_TopRight
,
JXCategoryDotRelativePosition_BottomLeft
,
JXCategoryDotRelativePosition_BottomRight
,
};
@interface
JXCategoryDotCellModel
:
JXCategoryTitleCellModel
@property
(
nonatomic
,
assign
)
BOOL
dotHidden
;
@property
(
nonatomic
,
assign
)
JXCategoryDotRelativePosition
relativePosition
;
@property
(
nonatomic
,
assign
)
CGSize
dotSize
;
@property
(
nonatomic
,
assign
)
CGFloat
dotCornerRadius
;
@property
(
nonatomic
,
strong
)
UIColor
*
dotColor
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Dot/JXCategoryDotCellModel.m
0 → 100755
View file @
a4f39813
//
// JXCategoryDotCellModel.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/20.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryDotCellModel.h"
@implementation
JXCategoryDotCellModel
@end
GMBase/Classes/JXPagerView/JXCategoryView/Dot/JXCategoryDotView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryDotView.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/20.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryTitleView.h"
#import "JXCategoryDotCell.h"
#import "JXCategoryDotCellModel.h"
@interface
JXCategoryDotView
:
JXCategoryTitleView
@property
(
nonatomic
,
assign
)
JXCategoryDotRelativePosition
relativePosition
;
//相对于titleLabel的位置,默认:JXCategoryDotRelativePosition_TopRight
@property
(
nonatomic
,
strong
)
NSArray
<
NSNumber
*>
*
dotStates
;
//@(布尔值),控制红点是否显示
@property
(
nonatomic
,
assign
)
CGSize
dotSize
;
//默认:CGSizeMake(10, 10)
@property
(
nonatomic
,
assign
)
CGFloat
dotCornerRadius
;
//默认:JXCategoryViewAutomaticDimension(self.dotSize.height/2)
@property
(
nonatomic
,
strong
)
UIColor
*
dotColor
;
//默认:[UIColor redColor]
@end
GMBase/Classes/JXPagerView/JXCategoryView/Dot/JXCategoryDotView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryDotView.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/20.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryDotView.h"
@implementation
JXCategoryDotView
-
(
void
)
initializeData
{
[
super
initializeData
];
_relativePosition
=
JXCategoryDotRelativePosition_TopRight
;
_dotSize
=
CGSizeMake
(
10
,
10
);
_dotCornerRadius
=
JXCategoryViewAutomaticDimension
;
_dotColor
=
[
UIColor
redColor
];
}
-
(
Class
)
preferredCellClass
{
return
[
JXCategoryDotCell
class
];
}
-
(
void
)
refreshDataSource
{
NSMutableArray
*
tempArray
=
[
NSMutableArray
array
];
for
(
int
i
=
0
;
i
<
self
.
titles
.
count
;
i
++
)
{
JXCategoryDotCellModel
*
cellModel
=
[[
JXCategoryDotCellModel
alloc
]
init
];
[
tempArray
addObject
:
cellModel
];
}
self
.
dataSource
=
tempArray
;
}
-
(
void
)
refreshCellModel
:
(
JXCategoryBaseCellModel
*
)
cellModel
index
:
(
NSInteger
)
index
{
[
super
refreshCellModel
:
cellModel
index
:
index
];
JXCategoryDotCellModel
*
myCellModel
=
(
JXCategoryDotCellModel
*
)
cellModel
;
myCellModel
.
dotHidden
=
[
self
.
dotStates
[
index
]
boolValue
];
myCellModel
.
relativePosition
=
self
.
relativePosition
;
myCellModel
.
dotSize
=
self
.
dotSize
;
myCellModel
.
dotColor
=
self
.
dotColor
;
if
(
self
.
dotCornerRadius
==
JXCategoryViewAutomaticDimension
)
{
myCellModel
.
dotCornerRadius
=
self
.
dotSize
.
height
/
2
;
}
else
{
myCellModel
.
dotCornerRadius
=
self
.
dotCornerRadius
;
}
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Image/JXCategoryImageCell.h
0 → 100755
View file @
a4f39813
//
// JXCategoryImageCell.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/20.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorCell.h"
@interface
JXCategoryImageCell
:
JXCategoryIndicatorCell
@property
(
nonatomic
,
strong
)
UIImageView
*
imageView
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Image/JXCategoryImageCell.m
0 → 100755
View file @
a4f39813
//
// JXCategoryImageCell.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/20.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryImageCell.h"
#import "JXCategoryImageCellModel.h"
@implementation
JXCategoryImageCell
-
(
void
)
initializeViews
{
[
super
initializeViews
];
_imageView
=
[[
UIImageView
alloc
]
init
];
_imageView
.
contentMode
=
UIViewContentModeScaleAspectFit
;
_imageView
.
layer
.
masksToBounds
=
YES
;
[
self
.
contentView
addSubview
:
_imageView
];
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
JXCategoryImageCellModel
*
myCellModel
=
(
JXCategoryImageCellModel
*
)
self
.
cellModel
;
self
.
imageView
.
bounds
=
CGRectMake
(
0
,
0
,
myCellModel
.
imageSize
.
width
,
myCellModel
.
imageSize
.
height
);
self
.
imageView
.
center
=
self
.
contentView
.
center
;
self
.
imageView
.
layer
.
cornerRadius
=
myCellModel
.
imageCornerRadius
;
}
-
(
void
)
reloadData
:
(
JXCategoryBaseCellModel
*
)
cellModel
{
[
super
reloadData
:
cellModel
];
JXCategoryImageCellModel
*
myCellModel
=
(
JXCategoryImageCellModel
*
)
cellModel
;
if
(
myCellModel
.
imageName
!=
nil
)
{
self
.
imageView
.
image
=
[
UIImage
imageNamed
:
myCellModel
.
imageName
];
}
else
if
(
myCellModel
.
imageURL
!=
nil
)
{
if
(
myCellModel
.
loadImageCallback
!=
nil
)
{
myCellModel
.
loadImageCallback
(
self
.
imageView
,
myCellModel
.
imageURL
);
}
}
if
(
myCellModel
.
selected
)
{
if
(
myCellModel
.
selectedImageName
!=
nil
)
{
self
.
imageView
.
image
=
[
UIImage
imageNamed
:
myCellModel
.
selectedImageName
];
}
else
if
(
myCellModel
.
selectedImageURL
!=
nil
)
{
if
(
myCellModel
.
loadImageCallback
!=
nil
)
{
myCellModel
.
loadImageCallback
(
self
.
imageView
,
myCellModel
.
selectedImageURL
);
}
}
}
if
(
myCellModel
.
imageZoomEnabled
)
{
self
.
imageView
.
transform
=
CGAffineTransformMakeScale
(
myCellModel
.
imageZoomScale
,
myCellModel
.
imageZoomScale
);
}
else
{
self
.
imageView
.
transform
=
CGAffineTransformIdentity
;
}
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Image/JXCategoryImageCellModel.h
0 → 100755
View file @
a4f39813
//
// JXCategoryImageCellModel.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/20.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorCellModel.h"
@interface
JXCategoryImageCellModel
:
JXCategoryIndicatorCellModel
@property
(
nonatomic
,
copy
)
void
(
^
loadImageCallback
)(
UIImageView
*
imageView
,
NSURL
*
imageURL
);
@property
(
nonatomic
,
copy
)
NSString
*
imageName
;
//加载bundle内的图片
@property
(
nonatomic
,
strong
)
NSURL
*
imageURL
;
//图片URL
@property
(
nonatomic
,
copy
)
NSString
*
selectedImageName
;
@property
(
nonatomic
,
strong
)
NSURL
*
selectedImageURL
;
@property
(
nonatomic
,
assign
)
CGSize
imageSize
;
@property
(
nonatomic
,
assign
)
CGFloat
imageCornerRadius
;
@property
(
nonatomic
,
assign
)
BOOL
imageZoomEnabled
;
@property
(
nonatomic
,
assign
)
CGFloat
imageZoomScale
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Image/JXCategoryImageCellModel.m
0 → 100755
View file @
a4f39813
//
// JXCategoryImageCellModel.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/20.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryImageCellModel.h"
@implementation
JXCategoryImageCellModel
@end
GMBase/Classes/JXPagerView/JXCategoryView/Image/JXCategoryImageView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryImageView.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/20.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorView.h"
#import "JXCategoryImageCell.h"
#import "JXCategoryImageCellModel.h"
@interface
JXCategoryImageView
:
JXCategoryIndicatorView
@property
(
nonatomic
,
strong
)
NSArray
<
NSString
*>*
imageNames
;
@property
(
nonatomic
,
strong
)
NSArray
<
NSURL
*>*
imageURLs
;
@property
(
nonatomic
,
strong
)
NSArray
<
NSString
*>*
selectedImageNames
;
@property
(
nonatomic
,
strong
)
NSArray
<
NSURL
*>*
selectedImageURLs
;
@property
(
nonatomic
,
copy
)
void
(
^
loadImageCallback
)(
UIImageView
*
imageView
,
NSURL
*
imageURL
);
//使用imageURL从远端下载图片进行加载,建议使用SDWebImage等第三方库进行下载。
@property
(
nonatomic
,
assign
)
CGSize
imageSize
;
//默认CGSizeMake(20, 20)
@property
(
nonatomic
,
assign
)
CGFloat
imageCornerRadius
;
//图片圆角
@property
(
nonatomic
,
assign
)
BOOL
imageZoomEnabled
;
//默认为NO
@property
(
nonatomic
,
assign
)
CGFloat
imageZoomScale
;
//默认1.2,imageZoomEnabled为YES才生效
@end
GMBase/Classes/JXPagerView/JXCategoryView/Image/JXCategoryImageView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryImageView.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/20.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryImageView.h"
#import "JXCategoryFactory.h"
@implementation
JXCategoryImageView
-
(
void
)
dealloc
{
self
.
loadImageCallback
=
nil
;
}
-
(
void
)
initializeData
{
[
super
initializeData
];
_imageSize
=
CGSizeMake
(
20
,
20
);
_imageZoomEnabled
=
NO
;
_imageZoomScale
=
1
.
2
;
_imageCornerRadius
=
0
;
}
-
(
Class
)
preferredCellClass
{
return
[
JXCategoryImageCell
class
];
}
-
(
void
)
refreshDataSource
{
NSMutableArray
*
tempArray
=
[
NSMutableArray
array
];
NSUInteger
count
=
(
self
.
imageNames
.
count
>
0
)
?
self
.
imageNames
.
count
:
(
self
.
imageURLs
.
count
>
0
?
self
.
imageURLs
.
count
:
0
);
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
JXCategoryImageCellModel
*
cellModel
=
[[
JXCategoryImageCellModel
alloc
]
init
];
[
tempArray
addObject
:
cellModel
];
}
self
.
dataSource
=
tempArray
;
}
-
(
void
)
refreshSelectedCellModel
:
(
JXCategoryBaseCellModel
*
)
selectedCellModel
unselectedCellModel
:
(
JXCategoryBaseCellModel
*
)
unselectedCellModel
{
[
super
refreshSelectedCellModel
:
selectedCellModel
unselectedCellModel
:
unselectedCellModel
];
JXCategoryImageCellModel
*
myUnselectedCellModel
=
(
JXCategoryImageCellModel
*
)
unselectedCellModel
;
myUnselectedCellModel
.
imageZoomScale
=
1
.
0
;
JXCategoryImageCellModel
*
myselectedCellModel
=
(
JXCategoryImageCellModel
*
)
selectedCellModel
;
myselectedCellModel
.
imageZoomScale
=
self
.
imageZoomScale
;
}
-
(
void
)
refreshCellModel
:
(
JXCategoryBaseCellModel
*
)
cellModel
index
:
(
NSInteger
)
index
{
[
super
refreshCellModel
:
cellModel
index
:
index
];
JXCategoryImageCellModel
*
myCellModel
=
(
JXCategoryImageCellModel
*
)
cellModel
;
myCellModel
.
loadImageCallback
=
self
.
loadImageCallback
;
myCellModel
.
imageSize
=
self
.
imageSize
;
myCellModel
.
imageCornerRadius
=
self
.
imageCornerRadius
;
if
(
self
.
imageNames
!=
nil
)
{
myCellModel
.
imageName
=
self
.
imageNames
[
index
];
}
else
if
(
self
.
imageURLs
!=
nil
)
{
myCellModel
.
imageURL
=
self
.
imageURLs
[
index
];
}
if
(
self
.
selectedImageNames
!=
nil
)
{
myCellModel
.
selectedImageName
=
self
.
selectedImageNames
[
index
];
}
else
if
(
self
.
selectedImageURLs
!=
nil
)
{
myCellModel
.
selectedImageURL
=
self
.
selectedImageURLs
[
index
];
}
myCellModel
.
imageZoomEnabled
=
self
.
imageZoomEnabled
;
myCellModel
.
imageZoomScale
=
1
.
0
;
if
(
index
==
self
.
selectedIndex
)
{
myCellModel
.
imageZoomScale
=
self
.
imageZoomScale
;
}
}
-
(
void
)
refreshLeftCellModel
:
(
JXCategoryBaseCellModel
*
)
leftCellModel
rightCellModel
:
(
JXCategoryBaseCellModel
*
)
rightCellModel
ratio
:
(
CGFloat
)
ratio
{
[
super
refreshLeftCellModel
:
leftCellModel
rightCellModel
:
rightCellModel
ratio
:
ratio
];
JXCategoryImageCellModel
*
leftModel
=
(
JXCategoryImageCellModel
*
)
leftCellModel
;
JXCategoryImageCellModel
*
rightModel
=
(
JXCategoryImageCellModel
*
)
rightCellModel
;
if
(
self
.
imageZoomEnabled
)
{
leftModel
.
imageZoomScale
=
[
JXCategoryFactory
interpolationFrom
:
self
.
imageZoomScale
to
:
1
.
0
percent
:
ratio
];
rightModel
.
imageZoomScale
=
[
JXCategoryFactory
interpolationFrom
:
1
.
0
to
:
self
.
imageZoomScale
percent
:
ratio
];
}
}
-
(
CGFloat
)
preferredCellWidthAtIndex
:
(
NSInteger
)
index
{
return
self
.
imageSize
.
width
;
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorBackgroundView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorBackgroundView.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/17.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorComponentView.h"
@interface
JXCategoryIndicatorBackgroundView
:
JXCategoryIndicatorComponentView
@property
(
nonatomic
,
assign
)
CGFloat
backgroundViewWidth
;
//默认JXCategoryViewAutomaticDimension(与cellWidth相等)
@property
(
nonatomic
,
assign
)
CGFloat
backgroundViewWidthIncrement
;
//宽度增量补偿,因为backgroundEllipseLayer一般会比实际内容大一些。默认10
@property
(
nonatomic
,
assign
)
CGFloat
backgroundViewHeight
;
//默认JXCategoryViewAutomaticDimension(与cell高度相等)
@property
(
nonatomic
,
assign
)
CGFloat
backgroundViewCornerRadius
;
//默认JXCategoryViewAutomaticDimension(即backgroundViewHeight/2)
@property
(
nonatomic
,
strong
)
UIColor
*
backgroundViewColor
;
//默认为[UIColor redColor]
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorBackgroundView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorBackgroundView.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/17.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorBackgroundView.h"
#import "JXCategoryFactory.h"
@implementation
JXCategoryIndicatorBackgroundView
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
{
self
=
[
super
initWithFrame
:
frame
];
if
(
self
)
{
_backgroundViewWidth
=
JXCategoryViewAutomaticDimension
;
_backgroundViewHeight
=
JXCategoryViewAutomaticDimension
;
_backgroundViewCornerRadius
=
JXCategoryViewAutomaticDimension
;
_backgroundViewColor
=
[
UIColor
lightGrayColor
];
_backgroundViewWidthIncrement
=
10
;
}
return
self
;
}
#pragma mark - JXCategoryIndicatorProtocol
-
(
void
)
jx_refreshState
:(
JXCategoryIndicatorParamsModel
*
)
model
{
self
.
layer
.
cornerRadius
=
[
self
getBackgroundViewCornerRadius
:
model
.
selectedCellFrame
];
self
.
backgroundColor
=
self
.
backgroundViewColor
;
CGFloat
width
=
[
self
getBackgroundViewWidth
:
model
.
selectedCellFrame
];
CGFloat
height
=
[
self
getBackgroundViewHeight
:
model
.
selectedCellFrame
];
CGFloat
x
=
model
.
selectedCellFrame
.
origin
.
x
+
(
model
.
selectedCellFrame
.
size
.
width
-
width
)
/
2
;
CGFloat
y
=
(
model
.
selectedCellFrame
.
size
.
height
-
height
)
/
2
;
self
.
frame
=
CGRectMake
(
x
,
y
,
width
,
height
);
}
-
(
void
)
jx_contentScrollViewDidScroll
:(
JXCategoryIndicatorParamsModel
*
)
model
{
CGRect
rightCellFrame
=
model
.
rightCellFrame
;
CGRect
leftCellFrame
=
model
.
leftCellFrame
;
CGFloat
percent
=
model
.
percent
;
CGFloat
targetX
=
0
;
CGFloat
targetWidth
=
[
self
getBackgroundViewWidth
:
leftCellFrame
];
if
(
percent
==
0
)
{
targetX
=
leftCellFrame
.
origin
.
x
+
(
leftCellFrame
.
size
.
width
-
targetWidth
)
/
2
.
0
;
}
else
{
CGFloat
leftWidth
=
targetWidth
;
CGFloat
rightWidth
=
[
self
getBackgroundViewWidth
:
rightCellFrame
];
CGFloat
leftX
=
leftCellFrame
.
origin
.
x
+
(
leftCellFrame
.
size
.
width
-
leftWidth
)
/
2
;
CGFloat
rightX
=
rightCellFrame
.
origin
.
x
+
(
rightCellFrame
.
size
.
width
-
rightWidth
)
/
2
;
targetX
=
[
JXCategoryFactory
interpolationFrom
:
leftX
to
:
rightX
percent
:
percent
];
if
(
self
.
backgroundViewWidth
==
JXCategoryViewAutomaticDimension
)
{
targetWidth
=
[
JXCategoryFactory
interpolationFrom
:
leftWidth
to
:
rightWidth
percent
:
percent
];
}
}
//允许变动frame的情况:1、允许滚动;2、不允许滚动,但是已经通过手势滚动切换一页内容了;
if
(
self
.
scrollEnabled
==
YES
||
(
self
.
scrollEnabled
==
NO
&&
percent
==
0
))
{
CGFloat
height
=
[
self
getBackgroundViewHeight
:
leftCellFrame
];
CGFloat
y
=
(
leftCellFrame
.
size
.
height
-
height
)
/
2
;
self
.
frame
=
CGRectMake
(
targetX
,
y
,
targetWidth
,
height
);
}
}
-
(
void
)
jx_selectedCell
:(
JXCategoryIndicatorParamsModel
*
)
model
{
CGFloat
width
=
[
self
getBackgroundViewWidth
:
model
.
selectedCellFrame
];
CGFloat
height
=
[
self
getBackgroundViewHeight
:
model
.
selectedCellFrame
];
CGFloat
x
=
model
.
selectedCellFrame
.
origin
.
x
+
(
model
.
selectedCellFrame
.
size
.
width
-
width
)
/
2
;
CGFloat
y
=
(
model
.
selectedCellFrame
.
size
.
height
-
height
)
/
2
;
CGRect
toFrame
=
CGRectMake
(
x
,
y
,
width
,
height
);
if
(
self
.
scrollEnabled
)
{
[
UIView
animateWithDuration
:
0
.
25
delay
:
0
options
:
UIViewAnimationOptionCurveLinear
animations
:^
{
self
.
frame
=
toFrame
;
}
completion
:^
(
BOOL
finished
)
{
}];
}
else
{
self
.
frame
=
toFrame
;
}
}
#pragma mark - Private
-
(
CGFloat
)
getBackgroundViewWidth
:(
CGRect
)
cellFrame
{
if
(
self
.
backgroundViewWidth
==
JXCategoryViewAutomaticDimension
)
{
return
cellFrame
.
size
.
width
+
self
.
backgroundViewWidthIncrement
;
}
return
self
.
backgroundViewWidth
+
self
.
backgroundViewWidthIncrement
;
}
-
(
CGFloat
)
getBackgroundViewHeight
:(
CGRect
)
cellFrame
{
if
(
self
.
backgroundViewHeight
==
JXCategoryViewAutomaticDimension
)
{
return
cellFrame
.
size
.
height
;
}
return
self
.
backgroundViewHeight
;
}
-
(
CGFloat
)
getBackgroundViewCornerRadius
:(
CGRect
)
cellFrame
{
if
(
self
.
backgroundViewCornerRadius
==
JXCategoryViewAutomaticDimension
)
{
return
[
self
getBackgroundViewHeight
:
cellFrame
]
/
2
;
}
return
self
.
backgroundViewCornerRadius
;
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorBallView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorBallView.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/21.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorComponentView.h"
@interface
JXCategoryIndicatorBallView
:
JXCategoryIndicatorComponentView
@property
(
nonatomic
,
assign
)
CGSize
ballViewSize
;
//默认:CGSizeMake(15, 15)
@property
(
nonatomic
,
assign
)
CGFloat
ballScrollOffsetX
;
//小红点的偏移量 默认:20
@property
(
nonatomic
,
strong
)
UIColor
*
ballViewColor
;
//默认为[UIColor redColor]
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorBallView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorBallView.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/21.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorBallView.h"
#import "JXCategoryFactory.h"
@interface
JXCategoryIndicatorBallView
()
@property
(
nonatomic
,
strong
)
UIView
*
smallBall
;
@property
(
nonatomic
,
strong
)
UIView
*
bigBall
;
@property
(
nonatomic
,
strong
)
CAShapeLayer
*
shapeLayer
;
@end
@implementation
JXCategoryIndicatorBallView
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
{
self
=
[
super
initWithFrame
:
frame
];
if
(
self
)
{
_ballViewSize
=
CGSizeMake
(
15
,
15
);
_ballScrollOffsetX
=
20
;
_ballViewColor
=
[
UIColor
redColor
];
_smallBall
=
[[
UIView
alloc
]
init
];
[
self
addSubview
:
self
.
smallBall
];
_bigBall
=
[[
UIView
alloc
]
init
];
[
self
addSubview
:
self
.
bigBall
];
_shapeLayer
=
[
CAShapeLayer
layer
];
[
self
.
layer
addSublayer
:
self
.
shapeLayer
];
}
return
self
;
}
#pragma mark - JXCategoryIndicatorProtocol
-
(
void
)
jx_refreshState
:(
JXCategoryIndicatorParamsModel
*
)
model
{
[
CATransaction
begin
];
[
CATransaction
setDisableActions
:
YES
];
self
.
shapeLayer
.
fillColor
=
self
.
ballViewColor
.
CGColor
;
[
CATransaction
commit
];
self
.
smallBall
.
backgroundColor
=
self
.
ballViewColor
;
self
.
smallBall
.
layer
.
cornerRadius
=
self
.
ballViewSize
.
height
/
2
;
self
.
bigBall
.
backgroundColor
=
self
.
ballViewColor
;
self
.
bigBall
.
layer
.
cornerRadius
=
self
.
ballViewSize
.
height
/
2
;
CGFloat
x
=
model
.
selectedCellFrame
.
origin
.
x
+
(
model
.
selectedCellFrame
.
size
.
width
-
self
.
ballViewSize
.
width
)
/
2
;
CGFloat
y
=
self
.
superview
.
bounds
.
size
.
height
-
self
.
ballViewSize
.
height
-
self
.
verticalMargin
;
if
(
self
.
componentPosition
==
JXCategoryComponentPosition_Top
)
{
y
=
self
.
verticalMargin
;
}
self
.
smallBall
.
frame
=
CGRectMake
(
x
,
y
,
self
.
ballViewSize
.
width
,
self
.
ballViewSize
.
height
);
self
.
bigBall
.
frame
=
CGRectMake
(
x
,
y
,
self
.
ballViewSize
.
width
,
self
.
ballViewSize
.
height
);
}
-
(
void
)
jx_contentScrollViewDidScroll
:(
JXCategoryIndicatorParamsModel
*
)
model
{
CGRect
rightCellFrame
=
model
.
rightCellFrame
;
CGRect
leftCellFrame
=
model
.
leftCellFrame
;
CGFloat
percent
=
model
.
percent
;
CGFloat
targetXOfBigBall
=
0
;
CGFloat
targetXOfSmallBall
=
leftCellFrame
.
origin
.
x
+
(
leftCellFrame
.
size
.
width
-
self
.
ballViewSize
.
width
)
/
2
;
CGFloat
targetWidthOfSmallBall
=
self
.
ballViewSize
.
width
;
if
(
percent
==
0
)
{
targetXOfBigBall
=
leftCellFrame
.
origin
.
x
+
(
leftCellFrame
.
size
.
width
-
self
.
ballViewSize
.
width
)
/
2
.
0
;
targetXOfSmallBall
=
leftCellFrame
.
origin
.
x
+
(
leftCellFrame
.
size
.
width
-
targetWidthOfSmallBall
)
/
2
.
0
;
}
else
{
CGFloat
leftX
=
leftCellFrame
.
origin
.
x
+
(
leftCellFrame
.
size
.
width
-
self
.
ballViewSize
.
width
)
/
2
;
CGFloat
rightX
=
rightCellFrame
.
origin
.
x
+
(
rightCellFrame
.
size
.
width
-
self
.
ballViewSize
.
width
)
/
2
;
//前50%,移动bigBall的x,缩小smallBall;后50%,移动bigBall的x,缩小smallBall,移动smallBall的x
if
(
percent
<=
0
.
5
)
{
targetXOfBigBall
=
[
JXCategoryFactory
interpolationFrom
:
leftX
to
:(
rightX
-
self
.
ballScrollOffsetX
)
percent
:
percent
*
2
];
targetWidthOfSmallBall
=
[
JXCategoryFactory
interpolationFrom
:
self
.
ballViewSize
.
width
to
:
self
.
ballViewSize
.
width
/
2
percent
:
percent
*
2
];
}
else
{
targetXOfBigBall
=
[
JXCategoryFactory
interpolationFrom
:(
rightX
-
self
.
ballScrollOffsetX
)
to
:
rightX
percent
:
(
percent
-
0
.
5
)
*
2
];
targetWidthOfSmallBall
=
[
JXCategoryFactory
interpolationFrom
:
self
.
ballViewSize
.
width
/
2
to
:
0
percent
:
(
percent
-
0
.
5
)
*
2
];
targetXOfSmallBall
=
[
JXCategoryFactory
interpolationFrom
:
leftX
to
:
rightX
percent
:
(
percent
-
0
.
5
)
*
2
];
}
}
//允许变动frame的情况:1、允许滚动;2、不允许滚动,但是已经通过手势滚动切换一页内容了;
if
(
self
.
scrollEnabled
==
YES
||
(
self
.
scrollEnabled
==
NO
&&
percent
==
0
))
{
CGRect
bigBallFrame
=
self
.
bigBall
.
frame
;
bigBallFrame
.
origin
.
x
=
targetXOfBigBall
;
self
.
bigBall
.
frame
=
bigBallFrame
;
self
.
bigBall
.
layer
.
cornerRadius
=
bigBallFrame
.
size
.
height
/
2
;
CGFloat
targetYOfSmallBall
=
self
.
superview
.
bounds
.
size
.
height
-
self
.
ballViewSize
.
height
/
2
-
targetWidthOfSmallBall
/
2
-
self
.
verticalMargin
;
if
(
self
.
componentPosition
==
JXCategoryComponentPosition_Top
)
{
targetYOfSmallBall
=
self
.
ballViewSize
.
height
/
2
-
targetWidthOfSmallBall
/
2
+
self
.
verticalMargin
;
}
self
.
smallBall
.
frame
=
CGRectMake
(
targetXOfSmallBall
,
targetYOfSmallBall
,
targetWidthOfSmallBall
,
targetWidthOfSmallBall
);
self
.
smallBall
.
layer
.
cornerRadius
=
targetWidthOfSmallBall
/
2
;
[
CATransaction
begin
];
[
CATransaction
setDisableActions
:
YES
];
self
.
shapeLayer
.
path
=
[
self
getBezierPathWithSmallCir
:
self
.
smallBall
andBigCir
:
self
.
bigBall
].
CGPath
;
[
CATransaction
commit
];
}
}
-
(
void
)
jx_selectedCell
:(
JXCategoryIndicatorParamsModel
*
)
model
{
CGFloat
x
=
model
.
selectedCellFrame
.
origin
.
x
+
(
model
.
selectedCellFrame
.
size
.
width
-
self
.
ballViewSize
.
width
)
/
2
;
CGFloat
y
=
self
.
superview
.
bounds
.
size
.
height
-
self
.
ballViewSize
.
height
-
self
.
verticalMargin
;
if
(
self
.
componentPosition
==
JXCategoryComponentPosition_Top
)
{
y
=
self
.
verticalMargin
;
}
CGRect
toFrame
=
CGRectMake
(
x
,
y
,
self
.
ballViewSize
.
width
,
self
.
ballViewSize
.
height
);
if
(
self
.
scrollEnabled
)
{
[
UIView
animateWithDuration
:
0
.
25
delay
:
0
options
:
UIViewAnimationOptionCurveEaseOut
animations
:^
{
self
.
smallBall
.
frame
=
toFrame
;
self
.
bigBall
.
frame
=
toFrame
;
self
.
smallBall
.
layer
.
cornerRadius
=
self
.
ballViewSize
.
height
/
2
;
self
.
bigBall
.
layer
.
cornerRadius
=
self
.
ballViewSize
.
height
/
2
;
}
completion
:^
(
BOOL
finished
)
{
}];
}
else
{
self
.
smallBall
.
frame
=
toFrame
;
self
.
bigBall
.
frame
=
toFrame
;
self
.
smallBall
.
layer
.
cornerRadius
=
self
.
ballViewSize
.
height
/
2
;
self
.
bigBall
.
layer
.
cornerRadius
=
self
.
ballViewSize
.
height
/
2
;
}
}
-
(
UIBezierPath
*
)
getBezierPathWithSmallCir
:(
UIView
*
)
smallCir
andBigCir
:(
UIView
*
)
bigCir
{
// 获取最小的圆
if
(
bigCir
.
frame
.
size
.
width
<
smallCir
.
frame
.
size
.
width
)
{
UIView
*
view
=
bigCir
;
bigCir
=
smallCir
;
smallCir
=
view
;
}
// 获取小圆的信息
CGFloat
d
=
self
.
bigBall
.
center
.
x
-
self
.
smallBall
.
center
.
x
;
if
(
d
==
0
)
{
return
nil
;
}
CGFloat
x1
=
smallCir
.
center
.
x
;
CGFloat
y1
=
smallCir
.
center
.
y
;
CGFloat
r1
=
smallCir
.
bounds
.
size
.
width
/
2
;
// 获取大圆的信息
CGFloat
x2
=
bigCir
.
center
.
x
;
CGFloat
y2
=
bigCir
.
center
.
y
;
CGFloat
r2
=
bigCir
.
bounds
.
size
.
width
/
2
;
// 获取三角函数
CGFloat
sinA
=
(
y2
-
y1
)
/
d
;
CGFloat
cosA
=
(
x2
-
x1
)
/
d
;
// 获取矩形四个点
CGPoint
pointA
=
CGPointMake
(
x1
-
sinA
*
r1
,
y1
+
cosA
*
r1
);
CGPoint
pointB
=
CGPointMake
(
x1
+
sinA
*
r1
,
y1
-
cosA
*
r1
);
CGPoint
pointC
=
CGPointMake
(
x2
+
sinA
*
r2
,
y2
-
cosA
*
r2
);
CGPoint
pointD
=
CGPointMake
(
x2
-
sinA
*
r2
,
y2
+
cosA
*
r2
);
// 获取控制点,以便画出曲线
CGPoint
pointO
=
CGPointMake
(
pointA
.
x
+
d
/
2
*
cosA
,
pointA
.
y
+
d
/
2
*
sinA
);
CGPoint
pointP
=
CGPointMake
(
pointB
.
x
+
d
/
2
*
cosA
,
pointB
.
y
+
d
/
2
*
sinA
);
// 创建路径
UIBezierPath
*
path
=
[
UIBezierPath
bezierPath
];
[
path
moveToPoint
:
pointA
];
[
path
addLineToPoint
:
pointB
];
[
path
addQuadCurveToPoint
:
pointC
controlPoint
:
pointP
];
[
path
addLineToPoint
:
pointD
];
[
path
addQuadCurveToPoint
:
pointA
controlPoint
:
pointO
];
return
path
;
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorComponentView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryComponentBaseView.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/17.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "JXCategoryIndicatorProtocol.h"
#import "JXCategoryViewDefines.h"
@interface
JXCategoryIndicatorComponentView
:
UIView
<
JXCategoryIndicatorProtocol
>
/**
指示器的位置。底部或者顶部
*/
@property
(
nonatomic
,
assign
)
JXCategoryComponentPosition
componentPosition
;
/**
默认JXCategoryViewAutomaticDimension(与cell的宽度相等)。内部通过`- (CGFloat)indicatorWidthValue:(CGRect)cellFrame`方法获取实际的值
*/
@property
(
nonatomic
,
assign
)
CGFloat
indicatorWidth
;
/**
指示器的宽度增量。比如需求是指示器宽度比cell宽度多10 point。就可以将该属性赋值为10。最终指示器的宽度=indicatorWidth+indicatorWidthIncrement
*/
@property
(
nonatomic
,
assign
)
CGFloat
indicatorWidthIncrement
;
/**
默认:3。内部通过`- (CGFloat)indicatorHeightValue:(CGRect)cellFrame`方法获取实际的值
*/
@property
(
nonatomic
,
assign
)
CGFloat
indicatorHeight
;
/**
默认JXCategoryViewAutomaticDimension (等于indicatorHeight/2)。内部通过`- (CGFloat)indicatorCornerRadiusValue:(CGRect)cellFrame`方法获取实际的值
*/
@property
(
nonatomic
,
assign
)
CGFloat
indicatorCornerRadius
;
/**
指示器的颜色
*/
@property
(
nonatomic
,
strong
)
UIColor
*
indicatorColor
;
/**
垂直方向偏移。数值越大越靠近中心。默认:0。
*/
@property
(
nonatomic
,
assign
)
CGFloat
verticalMargin
;
/**
手势滚动、点击切换的时候,是否允许滚动,默认YES
*/
@property
(
nonatomic
,
assign
,
getter
=
isScrollEnabled
)
BOOL
scrollEnabled
;
/**
手势滚动、点击切换的时候,如果允许滚动,分为简单滚动和复杂滚动。默认为:JXCategoryIndicatorScrollStyleSimple
目前仅JXCategoryIndicatorLineView、JXCategoryIndicatorDotLineView支持,其他子类暂不支持。
*/
@property
(
nonatomic
,
assign
)
JXCategoryIndicatorScrollStyle
scrollStyle
;
/**
滚动动画的时间。默认0.25
*/
@property
(
nonatomic
,
assign
)
NSTimeInterval
scrollAnimationDuration
;
/**
传入cellFrame获取指示器的最终宽度
@param cellFrame cellFrame
@return 指示器的最终宽度
*/
-
(
CGFloat
)
indicatorWidthValue
:(
CGRect
)
cellFrame
;
/**
传入cellFrame获取指示器的最终高度
@param cellFrame cellFrame
@return 指示器的最终高度
*/
-
(
CGFloat
)
indicatorHeightValue
:(
CGRect
)
cellFrame
;
/**
传入cellFrame获取指示器的最终圆角
@param cellFrame cellFrame
@return 指示器的最终圆角
*/
-
(
CGFloat
)
indicatorCornerRadiusValue
:(
CGRect
)
cellFrame
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorComponentView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryComponentBaseView.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/17.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorComponentView.h"
@implementation
JXCategoryIndicatorComponentView
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
{
self
=
[
super
initWithFrame
:
frame
];
if
(
self
)
{
_componentPosition
=
JXCategoryComponentPosition_Bottom
;
_scrollEnabled
=
YES
;
_verticalMargin
=
0
;
_scrollAnimationDuration
=
0
.
25
;
_indicatorWidth
=
JXCategoryViewAutomaticDimension
;
_indicatorWidthIncrement
=
0
;
_indicatorHeight
=
3
;
_indicatorCornerRadius
=
JXCategoryViewAutomaticDimension
;
_indicatorColor
=
[
UIColor
redColor
];
_scrollStyle
=
JXCategoryIndicatorScrollStyleSimple
;
}
return
self
;
}
-
(
instancetype
)
initWithCoder
:(
NSCoder
*
)
coder
{
self
=
[
super
initWithCoder
:
coder
];
if
(
self
)
{
NSAssert
(
NO
,
@"Use initWithFrame"
);
}
return
self
;
}
-
(
CGFloat
)
indicatorWidthValue
:(
CGRect
)
cellFrame
{
if
(
self
.
indicatorWidth
==
JXCategoryViewAutomaticDimension
)
{
return
cellFrame
.
size
.
width
+
self
.
indicatorWidthIncrement
;
}
return
self
.
indicatorWidth
+
self
.
indicatorWidthIncrement
;
}
-
(
CGFloat
)
indicatorHeightValue
:(
CGRect
)
cellFrame
{
if
(
self
.
indicatorHeight
==
JXCategoryViewAutomaticDimension
)
{
return
cellFrame
.
size
.
height
;
}
return
self
.
indicatorHeight
;
}
-
(
CGFloat
)
indicatorCornerRadiusValue
:(
CGRect
)
cellFrame
{
if
(
self
.
indicatorCornerRadius
==
JXCategoryViewAutomaticDimension
)
{
return
[
self
indicatorHeightValue
:
cellFrame
]
/
2
;
}
return
self
.
indicatorCornerRadius
;
}
#pragma mark - JXCategoryIndicatorProtocol
-
(
void
)
jx_refreshState
:(
JXCategoryIndicatorParamsModel
*
)
model
{
}
-
(
void
)
jx_contentScrollViewDidScroll
:(
JXCategoryIndicatorParamsModel
*
)
model
{
}
-
(
void
)
jx_selectedCell
:(
JXCategoryIndicatorParamsModel
*
)
model
{
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorImageView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorImageView.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/17.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorComponentView.h"
@interface
JXCategoryIndicatorImageView
:
JXCategoryIndicatorComponentView
@property
(
nonatomic
,
strong
,
readonly
)
UIImageView
*
indicatorImageView
;
@property
(
nonatomic
,
assign
)
BOOL
indicatorImageViewRollEnabled
;
//默认NO
@property
(
nonatomic
,
assign
)
CGSize
indicatorImageViewSize
;
//默认:CGSizeMake(30, 20)
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorImageView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorImageView.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/17.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorImageView.h"
#import "JXCategoryFactory.h"
@implementation
JXCategoryIndicatorImageView
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
{
self
=
[
super
initWithFrame
:
frame
];
if
(
self
)
{
_indicatorImageViewSize
=
CGSizeMake
(
30
,
20
);
_indicatorImageViewRollEnabled
=
NO
;
_indicatorImageView
=
[[
UIImageView
alloc
]
init
];
self
.
indicatorImageView
.
frame
=
CGRectMake
(
0
,
0
,
self
.
indicatorImageViewSize
.
width
,
self
.
indicatorImageViewSize
.
height
);
self
.
indicatorImageView
.
contentMode
=
UIViewContentModeScaleAspectFit
;
[
self
addSubview
:
self
.
indicatorImageView
];
}
return
self
;
}
-
(
void
)
setIndicatorImageViewSize
:(
CGSize
)
indicatorImageViewSize
{
_indicatorImageViewSize
=
indicatorImageViewSize
;
self
.
indicatorImageView
.
frame
=
CGRectMake
(
0
,
0
,
self
.
indicatorImageViewSize
.
width
,
self
.
indicatorImageViewSize
.
height
);
}
#pragma mark - JXCategoryIndicatorProtocol
-
(
void
)
jx_refreshState
:(
JXCategoryIndicatorParamsModel
*
)
model
{
CGFloat
x
=
model
.
selectedCellFrame
.
origin
.
x
+
(
model
.
selectedCellFrame
.
size
.
width
-
self
.
indicatorImageViewSize
.
width
)
/
2
;
CGFloat
y
=
self
.
superview
.
bounds
.
size
.
height
-
self
.
indicatorImageViewSize
.
height
-
self
.
verticalMargin
;
if
(
self
.
componentPosition
==
JXCategoryComponentPosition_Top
)
{
y
=
self
.
verticalMargin
;
}
self
.
frame
=
CGRectMake
(
x
,
y
,
self
.
indicatorImageViewSize
.
width
,
self
.
indicatorImageViewSize
.
height
);
}
-
(
void
)
jx_contentScrollViewDidScroll
:(
JXCategoryIndicatorParamsModel
*
)
model
{
CGRect
rightCellFrame
=
model
.
rightCellFrame
;
CGRect
leftCellFrame
=
model
.
leftCellFrame
;
CGFloat
percent
=
model
.
percent
;
CGFloat
targetWidth
=
self
.
indicatorImageViewSize
.
width
;
CGFloat
targetX
=
0
;
if
(
percent
==
0
)
{
targetX
=
leftCellFrame
.
origin
.
x
+
(
leftCellFrame
.
size
.
width
-
targetWidth
)
/
2
.
0
;
}
else
{
CGFloat
leftX
=
leftCellFrame
.
origin
.
x
+
(
leftCellFrame
.
size
.
width
-
targetWidth
)
/
2
;
CGFloat
rightX
=
rightCellFrame
.
origin
.
x
+
(
rightCellFrame
.
size
.
width
-
targetWidth
)
/
2
;
targetX
=
[
JXCategoryFactory
interpolationFrom
:
leftX
to
:
rightX
percent
:
percent
];
}
//允许变动frame的情况:1、允许滚动;2、不允许滚动,但是已经通过手势滚动切换一页内容了;
if
(
self
.
scrollEnabled
==
YES
||
(
self
.
scrollEnabled
==
NO
&&
percent
==
0
))
{
CGRect
frame
=
self
.
frame
;
frame
.
origin
.
x
=
targetX
;
self
.
frame
=
frame
;
if
(
self
.
indicatorImageViewRollEnabled
)
{
self
.
indicatorImageView
.
transform
=
CGAffineTransformMakeRotation
(
M_PI
*
2
*
percent
);
}
}
}
-
(
void
)
jx_selectedCell
:(
JXCategoryIndicatorParamsModel
*
)
model
{
CGRect
toFrame
=
self
.
frame
;
toFrame
.
origin
.
x
=
model
.
selectedCellFrame
.
origin
.
x
+
(
model
.
selectedCellFrame
.
size
.
width
-
self
.
indicatorImageViewSize
.
width
)
/
2
;
if
(
self
.
scrollEnabled
)
{
[
UIView
animateWithDuration
:
0
.
25
delay
:
0
options
:
UIViewAnimationOptionCurveLinear
animations
:^
{
self
.
frame
=
toFrame
;
}
completion
:^
(
BOOL
finished
)
{
}];
if
(
self
.
indicatorImageViewRollEnabled
&&
model
.
isClicked
)
{
[
self
.
indicatorImageView
.
layer
removeAnimationForKey
:
@"rotate"
];
CABasicAnimation
*
rotateAnimation
=
[
CABasicAnimation
animationWithKeyPath
:
@"transform.rotation.z"
];
if
(
model
.
selectedIndex
>
model
.
lastSelectedIndex
)
{
rotateAnimation
.
fromValue
=
@
(
0
);
rotateAnimation
.
toValue
=
@
(
M_PI
*
2
);
}
else
{
rotateAnimation
.
fromValue
=
@
(
M_PI
*
2
);
rotateAnimation
.
toValue
=
@
(
0
);
}
rotateAnimation
.
fillMode
=
kCAFillModeBackwards
;
rotateAnimation
.
removedOnCompletion
=
YES
;
rotateAnimation
.
duration
=
0
.
25
;
[
self
.
indicatorImageView
.
layer
addAnimation
:
rotateAnimation
forKey
:
@"rotate"
];
}
}
else
{
self
.
frame
=
toFrame
;
}
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorLineView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorLineView.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/17.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorComponentView.h"
typedef
NS_ENUM
(
NSUInteger
,
JXCategoryIndicatorLineStyle
)
{
JXCategoryIndicatorLineStyle_Normal
=
0
,
JXCategoryIndicatorLineStyle_Lengthen
=
1
,
JXCategoryIndicatorLineStyle_LengthenOffset
=
2
,
};
@interface
JXCategoryIndicatorLineView
:
JXCategoryIndicatorComponentView
@property
(
nonatomic
,
assign
)
JXCategoryIndicatorLineStyle
lineStyle
;
/**
line滚动时x的偏移量,默认为10;
lineStyle为JXCategoryIndicatorLineStyle_LengthenOffset有用;
*/
@property
(
nonatomic
,
assign
)
CGFloat
lineScrollOffsetX
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorLineView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorLineView.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/17.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorLineView.h"
#import "JXCategoryFactory.h"
#import "JXCategoryViewDefines.h"
#import "JXCategoryViewAnimator.h"
@interface
JXCategoryIndicatorLineView
()
@property
(
nonatomic
,
strong
)
JXCategoryViewAnimator
*
animator
;
@end
@implementation
JXCategoryIndicatorLineView
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
{
self
=
[
super
initWithFrame
:
frame
];
if
(
self
)
{
_lineStyle
=
JXCategoryIndicatorLineStyle_Normal
;
_lineScrollOffsetX
=
10
;
self
.
indicatorHeight
=
3
;
}
return
self
;
}
#pragma mark - JXCategoryIndicatorProtocol
-
(
void
)
jx_refreshState
:(
JXCategoryIndicatorParamsModel
*
)
model
{
self
.
backgroundColor
=
self
.
indicatorColor
;
self
.
layer
.
cornerRadius
=
[
self
indicatorCornerRadiusValue
:
model
.
selectedCellFrame
];
CGFloat
selectedLineWidth
=
[
self
indicatorWidthValue
:
model
.
selectedCellFrame
];
CGFloat
x
=
model
.
selectedCellFrame
.
origin
.
x
+
(
model
.
selectedCellFrame
.
size
.
width
-
selectedLineWidth
)
/
2
;
CGFloat
y
=
self
.
superview
.
bounds
.
size
.
height
-
[
self
indicatorHeightValue
:
model
.
selectedCellFrame
]
-
self
.
verticalMargin
;
if
(
self
.
componentPosition
==
JXCategoryComponentPosition_Top
)
{
y
=
self
.
verticalMargin
;
}
self
.
frame
=
CGRectMake
(
x
,
y
,
selectedLineWidth
,
[
self
indicatorHeightValue
:
model
.
selectedCellFrame
]);
}
-
(
void
)
jx_contentScrollViewDidScroll
:(
JXCategoryIndicatorParamsModel
*
)
model
{
if
(
self
.
animator
.
isExecuting
)
{
[
self
.
animator
invalid
];
self
.
animator
=
nil
;
}
CGRect
rightCellFrame
=
model
.
rightCellFrame
;
CGRect
leftCellFrame
=
model
.
leftCellFrame
;
CGFloat
percent
=
model
.
percent
;
CGFloat
targetX
=
leftCellFrame
.
origin
.
x
;
CGFloat
targetWidth
=
[
self
indicatorWidthValue
:
leftCellFrame
];
CGFloat
leftWidth
=
targetWidth
;
CGFloat
rightWidth
=
[
self
indicatorWidthValue
:
rightCellFrame
];
CGFloat
leftX
=
leftCellFrame
.
origin
.
x
+
(
leftCellFrame
.
size
.
width
-
leftWidth
)
/
2
;
CGFloat
rightX
=
rightCellFrame
.
origin
.
x
+
(
rightCellFrame
.
size
.
width
-
rightWidth
)
/
2
;
if
(
self
.
lineStyle
==
JXCategoryIndicatorLineStyle_Normal
)
{
targetX
=
[
JXCategoryFactory
interpolationFrom
:
leftX
to
:
rightX
percent
:
0
];
NSLog
(
@"targetX--%.2f"
,
targetX
);
if
(
self
.
indicatorWidth
==
JXCategoryViewAutomaticDimension
)
{
targetWidth
=
[
JXCategoryFactory
interpolationFrom
:
leftWidth
to
:
rightWidth
percent
:
percent
];
NSLog
(
@"targetWidth--%.2f"
,
targetX
);
}
}
else
if
(
self
.
lineStyle
==
JXCategoryIndicatorLineStyle_Lengthen
)
{
CGFloat
maxWidth
=
rightX
-
leftX
+
rightWidth
;
//前50%,只增加width;后50%,移动x并减小width
if
(
percent
<=
0
.
5
)
{
targetX
=
leftX
;
targetWidth
=
[
JXCategoryFactory
interpolationFrom
:
leftWidth
to
:
maxWidth
percent
:
percent
*
2
];
}
else
{
targetX
=
[
JXCategoryFactory
interpolationFrom
:
leftX
to
:
rightX
percent
:
(
percent
-
0
.
5
)
*
2
];
NSLog
(
@"targetX--%.2f"
,
targetX
);
targetWidth
=
[
JXCategoryFactory
interpolationFrom
:
maxWidth
to
:
rightWidth
percent
:
(
percent
-
0
.
5
)
*
2
];
NSLog
(
@"targetWidth--%.2f"
,
targetWidth
);
}
}
else
if
(
self
.
lineStyle
==
JXCategoryIndicatorLineStyle_LengthenOffset
)
{
//前50%,增加width,并少量移动x;后50%,少量移动x并减小width
CGFloat
offsetX
=
self
.
lineScrollOffsetX
;
//x的少量偏移量
CGFloat
maxWidth
=
rightX
-
leftX
+
rightWidth
-
offsetX
*
2
;
if
(
percent
<=
0
.
5
)
{
targetX
=
[
JXCategoryFactory
interpolationFrom
:
leftX
to
:
leftX
+
offsetX
percent
:
percent
*
2
];;
targetWidth
=
[
JXCategoryFactory
interpolationFrom
:
leftWidth
to
:
maxWidth
percent
:
percent
*
2
];
}
else
{
targetX
=
[
JXCategoryFactory
interpolationFrom
:(
leftX
+
offsetX
)
to
:
rightX
percent
:
(
percent
-
0
.
5
)
*
2
];
targetWidth
=
[
JXCategoryFactory
interpolationFrom
:
maxWidth
to
:
rightWidth
percent
:
(
percent
-
0
.
5
)
*
2
];
}
}
//允许变动frame的情况:1、允许滚动;2、不允许滚动,但是已经通过手势滚动切换一页内容了;
if
(
self
.
isScrollEnabled
==
YES
||
(
self
.
isScrollEnabled
==
NO
&&
percent
==
0
))
{
CGRect
frame
=
self
.
frame
;
frame
.
origin
.
x
=
targetX
;
frame
.
size
.
width
=
targetWidth
;
self
.
frame
=
frame
;
}
}
-
(
void
)
jx_selectedCell
:(
JXCategoryIndicatorParamsModel
*
)
model
{
CGRect
targetIndicatorFrame
=
self
.
frame
;
CGFloat
targetIndicatorWidth
=
[
self
indicatorWidthValue
:
model
.
selectedCellFrame
];
targetIndicatorFrame
.
origin
.
x
=
model
.
selectedCellFrame
.
origin
.
x
+
(
model
.
selectedCellFrame
.
size
.
width
-
targetIndicatorWidth
)
/
2
.
0
;
targetIndicatorFrame
.
size
.
width
=
targetIndicatorWidth
;
if
(
self
.
isScrollEnabled
)
{
if
(
self
.
scrollStyle
==
JXCategoryIndicatorScrollStyleSameAsUserScroll
)
{
if
(
self
.
animator
.
isExecuting
)
{
[
self
.
animator
invalid
];
self
.
animator
=
nil
;
}
CGFloat
leftX
=
0
;
CGFloat
rightX
=
0
;
CGFloat
leftWidth
=
0
;
CGFloat
rightWidth
=
0
;
BOOL
isNeedReversePercent
=
NO
;
if
(
self
.
frame
.
origin
.
x
>
model
.
selectedCellFrame
.
origin
.
x
)
{
leftWidth
=
[
self
indicatorWidthValue
:
model
.
selectedCellFrame
];
rightWidth
=
self
.
frame
.
size
.
width
;
leftX
=
model
.
selectedCellFrame
.
origin
.
x
+
(
model
.
selectedCellFrame
.
size
.
width
-
leftWidth
)
/
2
;;
rightX
=
self
.
frame
.
origin
.
x
;
isNeedReversePercent
=
YES
;
}
else
{
leftWidth
=
self
.
frame
.
size
.
width
;
rightWidth
=
[
self
indicatorWidthValue
:
model
.
selectedCellFrame
];
leftX
=
self
.
frame
.
origin
.
x
;
rightX
=
model
.
selectedCellFrame
.
origin
.
x
+
(
model
.
selectedCellFrame
.
size
.
width
-
rightWidth
)
/
2
;
}
__weak
typeof
(
self
)
weakSelf
=
self
;
if
(
self
.
lineStyle
==
JXCategoryIndicatorLineStyle_Normal
)
{
[
UIView
animateWithDuration
:
self
.
scrollAnimationDuration
delay
:
0
options
:
UIViewAnimationOptionCurveEaseOut
animations
:^
{
self
.
frame
=
targetIndicatorFrame
;
}
completion
:
nil
];
}
else
if
(
self
.
lineStyle
==
JXCategoryIndicatorLineStyle_Lengthen
)
{
CGFloat
maxWidth
=
rightX
-
leftX
+
rightWidth
;
//前50%,只增加width;后50%,移动x并减小width
self
.
animator
=
[[
JXCategoryViewAnimator
alloc
]
init
];
self
.
animator
.
progressCallback
=
^
(
CGFloat
percent
)
{
if
(
isNeedReversePercent
)
{
percent
=
1
-
percent
;
}
CGFloat
targetX
=
0
;
CGFloat
targetWidth
=
0
;
if
(
percent
<=
0
.
5
)
{
targetX
=
leftX
;
targetWidth
=
[
JXCategoryFactory
interpolationFrom
:
leftWidth
to
:
maxWidth
percent
:
percent
*
2
];
}
else
{
targetX
=
[
JXCategoryFactory
interpolationFrom
:
leftX
to
:
rightX
percent
:
(
percent
-
0
.
5
)
*
2
];
targetWidth
=
[
JXCategoryFactory
interpolationFrom
:
maxWidth
to
:
rightWidth
percent
:
(
percent
-
0
.
5
)
*
2
];
}
CGRect
toFrame
=
weakSelf
.
frame
;
toFrame
.
origin
.
x
=
targetX
;
toFrame
.
size
.
width
=
targetWidth
;
weakSelf
.
frame
=
toFrame
;
};
[
self
.
animator
start
];
}
else
if
(
self
.
lineStyle
==
JXCategoryIndicatorLineStyle_LengthenOffset
)
{
//前50%,增加width,并少量移动x;后50%,少量移动x并减小width
CGFloat
offsetX
=
self
.
lineScrollOffsetX
;
//x的少量偏移量
CGFloat
maxWidth
=
rightX
-
leftX
+
rightWidth
-
offsetX
*
2
;
self
.
animator
=
[[
JXCategoryViewAnimator
alloc
]
init
];
self
.
animator
.
progressCallback
=
^
(
CGFloat
percent
)
{
if
(
isNeedReversePercent
)
{
percent
=
1
-
percent
;
}
CGFloat
targetX
=
0
;
CGFloat
targetWidth
=
0
;
if
(
percent
<=
0
.
5
)
{
targetX
=
[
JXCategoryFactory
interpolationFrom
:
leftX
to
:
leftX
+
offsetX
percent
:
percent
*
2
];;
targetWidth
=
[
JXCategoryFactory
interpolationFrom
:
leftWidth
to
:
maxWidth
percent
:
percent
*
2
];
}
else
{
targetX
=
[
JXCategoryFactory
interpolationFrom
:(
leftX
+
offsetX
)
to
:
rightX
percent
:
(
percent
-
0
.
5
)
*
2
];
targetWidth
=
[
JXCategoryFactory
interpolationFrom
:
maxWidth
to
:
rightWidth
percent
:
(
percent
-
0
.
5
)
*
2
];
}
CGRect
toFrame
=
weakSelf
.
frame
;
toFrame
.
origin
.
x
=
targetX
;
toFrame
.
size
.
width
=
targetWidth
;
weakSelf
.
frame
=
toFrame
;
};
[
self
.
animator
start
];
}
}
else
if
(
self
.
scrollStyle
==
JXCategoryIndicatorScrollStyleSimple
)
{
[
UIView
animateWithDuration
:
self
.
scrollAnimationDuration
delay
:
0
options
:
UIViewAnimationOptionCurveEaseOut
animations
:^
{
self
.
frame
=
targetIndicatorFrame
;
}
completion
:
nil
];
}
}
else
{
self
.
frame
=
targetIndicatorFrame
;
}
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorRainbowLineView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorRainbowLineView.h
// JXCategoryView
//
// Created by jiaxin on 2018/12/13.
// Copyright © 2018 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorLineView.h"
NS_ASSUME_NONNULL_BEGIN
/**
会无视JXCategoryIndicatorLineView的indicatorLineViewColor属性,以indicatorColors为准
*/
@interface
JXCategoryIndicatorRainbowLineView
:
JXCategoryIndicatorLineView
@property
(
nonatomic
,
strong
)
NSArray
<
UIColor
*>
*
indicatorColors
;
//数量需要与cell的数量相等。没有提供默认值,必须要赋值该属性。categoryView在reloadData的时候,也要一并更新该属性,不然会出现数组越界。
@end
NS_ASSUME_NONNULL_END
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorRainbowLineView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorRainbowLineView.m
// JXCategoryView
//
// Created by jiaxin on 2018/12/13.
// Copyright © 2018 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorRainbowLineView.h"
#import "JXCategoryFactory.h"
@implementation
JXCategoryIndicatorRainbowLineView
-
(
void
)
jx_refreshState
:(
JXCategoryIndicatorParamsModel
*
)
model
{
[
super
jx_refreshState
:
model
];
UIColor
*
color
=
self
.
indicatorColors
[
model
.
selectedIndex
];
self
.
backgroundColor
=
color
;
}
-
(
void
)
jx_contentScrollViewDidScroll
:(
JXCategoryIndicatorParamsModel
*
)
model
{
[
super
jx_contentScrollViewDidScroll
:
model
];
UIColor
*
leftColor
=
self
.
indicatorColors
[
model
.
leftIndex
];
UIColor
*
rightColor
=
self
.
indicatorColors
[
model
.
rightIndex
];
UIColor
*
color
=
[
JXCategoryFactory
interpolationColorFrom
:
leftColor
to
:
rightColor
percent
:
model
.
percent
];
self
.
backgroundColor
=
color
;
}
-
(
void
)
jx_selectedCell
:(
JXCategoryIndicatorParamsModel
*
)
model
{
[
super
jx_selectedCell
:
model
];
UIColor
*
color
=
self
.
indicatorColors
[
model
.
selectedIndex
];
self
.
backgroundColor
=
color
;
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorTriangleView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorTriangleView.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/17.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorComponentView.h"
@interface
JXCategoryIndicatorTriangleView
:
JXCategoryIndicatorComponentView
@property
(
nonatomic
,
assign
)
CGSize
triangleViewSize
;
//默认:CGSizeMake(14, 10)
@property
(
nonatomic
,
strong
)
UIColor
*
triangleViewColor
;
//默认:[UIColor redColor]
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryIndicatorTriangleView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryIndicatorTriangleView.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/17.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorTriangleView.h"
#import "JXCategoryFactory.h"
@interface
JXCategoryIndicatorTriangleView
()
@property
(
nonatomic
,
strong
)
CAShapeLayer
*
triangleLayer
;
@end
@implementation
JXCategoryIndicatorTriangleView
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
{
self
=
[
super
initWithFrame
:
frame
];
if
(
self
)
{
_triangleViewSize
=
CGSizeMake
(
14
,
10
);
_triangleViewColor
=
[
UIColor
redColor
];
_triangleLayer
=
[
CAShapeLayer
layer
];
[
self
.
layer
addSublayer
:
self
.
triangleLayer
];
}
return
self
;
}
#pragma mark - JXCategoryIndicatorProtocol
-
(
void
)
jx_refreshState
:(
JXCategoryIndicatorParamsModel
*
)
model
{
CGFloat
x
=
model
.
selectedCellFrame
.
origin
.
x
+
(
model
.
selectedCellFrame
.
size
.
width
-
self
.
triangleViewSize
.
width
)
/
2
;
CGFloat
y
=
self
.
superview
.
bounds
.
size
.
height
-
self
.
triangleViewSize
.
height
-
self
.
verticalMargin
;
if
(
self
.
componentPosition
==
JXCategoryComponentPosition_Top
)
{
y
=
self
.
verticalMargin
;
}
self
.
frame
=
CGRectMake
(
x
,
y
,
self
.
triangleViewSize
.
width
,
self
.
triangleViewSize
.
height
);
[
CATransaction
begin
];
[
CATransaction
setDisableActions
:
NO
];
self
.
triangleLayer
.
fillColor
=
self
.
triangleViewColor
.
CGColor
;
self
.
triangleLayer
.
frame
=
self
.
bounds
;
UIBezierPath
*
path
=
[
UIBezierPath
bezierPath
];
if
(
self
.
componentPosition
==
JXCategoryComponentPosition_Bottom
)
{
[
path
moveToPoint
:
CGPointMake
(
self
.
bounds
.
size
.
width
/
2
,
0
)];
[
path
addLineToPoint
:
CGPointMake
(
0
,
self
.
bounds
.
size
.
height
)];
[
path
addLineToPoint
:
CGPointMake
(
self
.
bounds
.
size
.
width
,
self
.
bounds
.
size
.
height
)];
}
else
{
[
path
moveToPoint
:
CGPointMake
(
0
,
0
)];
[
path
addLineToPoint
:
CGPointMake
(
self
.
bounds
.
size
.
width
,
0
)];
[
path
addLineToPoint
:
CGPointMake
(
self
.
bounds
.
size
.
width
/
2
,
self
.
bounds
.
size
.
height
)];
}
[
path
closePath
];
self
.
triangleLayer
.
path
=
path
.
CGPath
;
[
CATransaction
commit
];
}
-
(
void
)
jx_contentScrollViewDidScroll
:(
JXCategoryIndicatorParamsModel
*
)
model
{
CGRect
rightCellFrame
=
model
.
rightCellFrame
;
CGRect
leftCellFrame
=
model
.
leftCellFrame
;
CGFloat
percent
=
model
.
percent
;
CGFloat
targetWidth
=
self
.
triangleViewSize
.
width
;
CGFloat
targetX
=
0
;
if
(
percent
==
0
)
{
targetX
=
leftCellFrame
.
origin
.
x
+
(
leftCellFrame
.
size
.
width
-
targetWidth
)
/
2
.
0
;
}
else
{
CGFloat
leftX
=
leftCellFrame
.
origin
.
x
+
(
leftCellFrame
.
size
.
width
-
targetWidth
)
/
2
;
CGFloat
rightX
=
rightCellFrame
.
origin
.
x
+
(
rightCellFrame
.
size
.
width
-
targetWidth
)
/
2
;
targetX
=
[
JXCategoryFactory
interpolationFrom
:
leftX
to
:
rightX
percent
:
percent
];
}
//允许变动frame的情况:1、允许滚动;2、不允许滚动,但是已经通过手势滚动切换一页内容了;
if
(
self
.
scrollEnabled
==
YES
||
(
self
.
scrollEnabled
==
NO
&&
percent
==
0
))
{
CGRect
frame
=
self
.
frame
;
frame
.
origin
.
x
=
targetX
;
self
.
frame
=
frame
;
}
}
-
(
void
)
jx_selectedCell
:(
JXCategoryIndicatorParamsModel
*
)
model
{
CGRect
toFrame
=
self
.
frame
;
toFrame
.
origin
.
x
=
model
.
selectedCellFrame
.
origin
.
x
+
(
model
.
selectedCellFrame
.
size
.
width
-
self
.
triangleViewSize
.
width
)
/
2
;
if
(
self
.
scrollEnabled
)
{
[
UIView
animateWithDuration
:
0
.
25
delay
:
0
options
:
UIViewAnimationOptionCurveLinear
animations
:^
{
self
.
frame
=
toFrame
;
}
completion
:^
(
BOOL
finished
)
{
}];
}
else
{
self
.
frame
=
toFrame
;
}
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryViewAnimator.h
0 → 100755
View file @
a4f39813
//
// 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
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/IndicatorViews/JXCategoryViewAnimator.m
0 → 100755
View file @
a4f39813
//
// 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
-
(
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
;
}
-
(
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
;
}
-
(
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
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/JXCategoryIndicatorCell.h
0 → 100755
View file @
a4f39813
//
// JXCategoryComponetCell.h
// DQGuess
//
// Created by jiaxin on 2018/7/25.
// Copyright © 2018年 jingbo. All rights reserved.
//
#import "JXCategoryBaseCell.h"
@interface
JXCategoryIndicatorCell
:
JXCategoryBaseCell
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/JXCategoryIndicatorCell.m
0 → 100755
View file @
a4f39813
//
// JXCategoryComponetCell.m
// DQGuess
//
// Created by jiaxin on 2018/7/25.
// Copyright © 2018年 jingbo. All rights reserved.
//
#import "JXCategoryIndicatorCell.h"
#import "JXCategoryIndicatorCellModel.h"
@interface
JXCategoryIndicatorCell
()
@property
(
nonatomic
,
strong
)
UIView
*
separatorLine
;
@end
@implementation
JXCategoryIndicatorCell
-
(
void
)
initializeViews
{
[
super
initializeViews
];
self
.
separatorLine
=
[[
UIView
alloc
]
init
];
self
.
separatorLine
.
hidden
=
YES
;
[
self
.
contentView
addSubview
:
self
.
separatorLine
];
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
JXCategoryIndicatorCellModel
*
model
=
(
JXCategoryIndicatorCellModel
*
)
self
.
cellModel
;
CGFloat
lineWidth
=
model
.
separatorLineSize
.
width
;
CGFloat
lineHeight
=
model
.
separatorLineSize
.
height
;
self
.
separatorLine
.
frame
=
CGRectMake
(
self
.
bounds
.
size
.
width
-
lineWidth
+
self
.
cellModel
.
cellSpacing
/
2
,
(
self
.
bounds
.
size
.
height
-
lineHeight
)
/
2
.
0
,
lineWidth
,
lineHeight
);
}
-
(
void
)
reloadData
:
(
JXCategoryBaseCellModel
*
)
cellModel
{
[
super
reloadData
:
cellModel
];
JXCategoryIndicatorCellModel
*
model
=
(
JXCategoryIndicatorCellModel
*
)
cellModel
;
self
.
separatorLine
.
backgroundColor
=
model
.
separatorLineColor
;
self
.
separatorLine
.
hidden
=
!
model
.
sepratorLineShowEnabled
;
if
(
model
.
cellBackgroundColorGradientEnabled
)
{
if
(
model
.
selected
)
{
self
.
contentView
.
backgroundColor
=
model
.
cellBackgroundSelectedColor
;
}
else
{
self
.
contentView
.
backgroundColor
=
model
.
cellBackgroundUnselectedColor
;
}
}
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/JXCategoryIndicatorCellModel.h
0 → 100755
View file @
a4f39813
//
// JXCategoryComponentCellModel.h
// DQGuess
//
// Created by jiaxin on 2018/7/25.
// Copyright © 2018年 jingbo. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "JXCategoryBaseCellModel.h"
@interface
JXCategoryIndicatorCellModel
:
JXCategoryBaseCellModel
@property
(
nonatomic
,
assign
)
BOOL
sepratorLineShowEnabled
;
@property
(
nonatomic
,
strong
)
UIColor
*
separatorLineColor
;
@property
(
nonatomic
,
assign
)
CGSize
separatorLineSize
;
@property
(
nonatomic
,
assign
)
CGRect
backgroundViewMaskFrame
;
@property
(
nonatomic
,
assign
)
BOOL
cellBackgroundColorGradientEnabled
;
@property
(
nonatomic
,
strong
)
UIColor
*
cellBackgroundUnselectedColor
;
@property
(
nonatomic
,
strong
)
UIColor
*
cellBackgroundSelectedColor
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/JXCategoryIndicatorCellModel.m
0 → 100755
View file @
a4f39813
//
// JXCategoryComponentCellModel.m
// DQGuess
//
// Created by jiaxin on 2018/7/25.
// Copyright © 2018年 jingbo. All rights reserved.
//
#import "JXCategoryIndicatorCellModel.h"
@implementation
JXCategoryIndicatorCellModel
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/JXCategoryIndicatorView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryComponentView.h
// DQGuess
//
// Created by jiaxin on 2018/7/25.
// Copyright © 2018年 jingbo. All rights reserved.
//
#import "JXCategoryBaseView.h"
#import "JXCategoryIndicatorCell.h"
#import "JXCategoryIndicatorCellModel.h"
#import "JXCategoryIndicatorProtocol.h"
@interface
JXCategoryIndicatorView
:
JXCategoryBaseView
@property
(
nonatomic
,
strong
)
NSArray
<
UIView
<
JXCategoryIndicatorProtocol
>
*>
*
indicators
;
//----------------------ellBackgroundColor-----------------------//
@property
(
nonatomic
,
assign
)
BOOL
cellBackgroundColorGradientEnabled
;
//默认:NO
@property
(
nonatomic
,
strong
)
UIColor
*
cellBackgroundUnselectedColor
;
//默认:[UIColor clearColor]
@property
(
nonatomic
,
strong
)
UIColor
*
cellBackgroundSelectedColor
;
//默认:[UIColor grayColor]
//----------------------separatorLine-----------------------//
@property
(
nonatomic
,
assign
)
BOOL
separatorLineShowEnabled
;
//默认为NO
@property
(
nonatomic
,
strong
)
UIColor
*
separatorLineColor
;
//默认为[UIColor lightGrayColor]
@property
(
nonatomic
,
assign
)
CGSize
separatorLineSize
;
//默认为CGSizeMake(1/[UIScreen mainScreen].scale, 20)
/**
当contentScrollView滚动时候,处理跟随手势的过渡效果。
根据cellModel的左右位置、是否选中、ratio进行过滤数据计算。
@param leftCellModel 左边的cellModel
@param rightCellModel 右边的cellModel
@param ratio 从左往右方向计算的百分比
*/
-
(
void
)
refreshLeftCellModel
:(
JXCategoryBaseCellModel
*
)
leftCellModel
rightCellModel
:(
JXCategoryBaseCellModel
*
)
rightCellModel
ratio
:(
CGFloat
)
ratio
NS_REQUIRES_SUPER
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Indicator/JXCategoryIndicatorView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryComponentView.m
// DQGuess
//
// Created by jiaxin on 2018/7/25.
// Copyright © 2018年 jingbo. All rights reserved.
//
#import "JXCategoryIndicatorView.h"
#import "JXCategoryIndicatorBackgroundView.h"
#import "JXCategoryFactory.h"
@interface
JXCategoryIndicatorView
()
@property
(
nonatomic
,
strong
)
CALayer
*
backgroundEllipseLayer
;
@end
@implementation
JXCategoryIndicatorView
-
(
void
)
initializeData
{
[
super
initializeData
];
_separatorLineShowEnabled
=
NO
;
_separatorLineColor
=
[
UIColor
lightGrayColor
];
_separatorLineSize
=
CGSizeMake
(
1
/
[
UIScreen
mainScreen
].
scale
,
20
);
_cellBackgroundColorGradientEnabled
=
NO
;
_cellBackgroundUnselectedColor
=
[
UIColor
whiteColor
];
_cellBackgroundSelectedColor
=
[
UIColor
lightGrayColor
];
}
-
(
void
)
initializeViews
{
[
super
initializeViews
];
}
-
(
void
)
setIndicators
:
(
NSArray
<
UIView
<
JXCategoryIndicatorProtocol
>
*>
*
)
indicators
{
for
(
UIView
*
component
in
self
.
indicators
)
{
//先移除之前的component
[
component
removeFromSuperview
];
}
_indicators
=
indicators
;
for
(
UIView
*
component
in
self
.
indicators
)
{
[
self
.
collectionView
addSubview
:
component
];
}
self
.
collectionView
.
indicators
=
indicators
;
}
-
(
void
)
refreshState
{
[
super
refreshState
];
CGRect
selectedCellFrame
=
CGRectZero
;
JXCategoryIndicatorCellModel
*
selectedCellModel
=
nil
;
for
(
int
i
=
0
;
i
<
self
.
dataSource
.
count
;
i
++
)
{
JXCategoryIndicatorCellModel
*
cellModel
=
(
JXCategoryIndicatorCellModel
*
)
self
.
dataSource
[
i
];
cellModel
.
sepratorLineShowEnabled
=
self
.
separatorLineShowEnabled
;
cellModel
.
separatorLineColor
=
self
.
separatorLineColor
;
cellModel
.
separatorLineSize
=
self
.
separatorLineSize
;
cellModel
.
backgroundViewMaskFrame
=
CGRectZero
;
cellModel
.
cellBackgroundColorGradientEnabled
=
self
.
cellBackgroundColorGradientEnabled
;
cellModel
.
cellBackgroundSelectedColor
=
self
.
cellBackgroundSelectedColor
;
cellModel
.
cellBackgroundUnselectedColor
=
self
.
cellBackgroundUnselectedColor
;
if
(
i
==
self
.
dataSource
.
count
-
1
)
{
cellModel
.
sepratorLineShowEnabled
=
NO
;
}
if
(
i
==
self
.
selectedIndex
)
{
selectedCellModel
=
cellModel
;
cellModel
.
selected
=
YES
;
selectedCellFrame
=
[
self
getTargetCellFrame
:
i
];
}
}
for
(
UIView
<
JXCategoryIndicatorProtocol
>
*
component
in
self
.
indicators
)
{
if
(
self
.
dataSource
.
count
<=
0
)
{
component
.
hidden
=
YES
;
}
else
{
component
.
hidden
=
NO
;
JXCategoryIndicatorParamsModel
*
indicatorParamsModel
=
[[
JXCategoryIndicatorParamsModel
alloc
]
init
];
indicatorParamsModel
.
selectedIndex
=
self
.
selectedIndex
;
indicatorParamsModel
.
selectedCellFrame
=
selectedCellFrame
;
[
component
jx_refreshState
:
indicatorParamsModel
];
if
([
component
isKindOfClass
:[
JXCategoryIndicatorBackgroundView
class
]])
{
CGRect
maskFrame
=
component
.
frame
;
maskFrame
.
origin
.
x
=
maskFrame
.
origin
.
x
-
selectedCellFrame
.
origin
.
x
;
selectedCellModel
.
backgroundViewMaskFrame
=
maskFrame
;
}
}
}
}
-
(
void
)
refreshSelectedCellModel
:
(
JXCategoryBaseCellModel
*
)
selectedCellModel
unselectedCellModel
:
(
JXCategoryBaseCellModel
*
)
unselectedCellModel
{
[
super
refreshSelectedCellModel
:
selectedCellModel
unselectedCellModel
:
unselectedCellModel
];
JXCategoryIndicatorCellModel
*
myUnselectedCellModel
=
(
JXCategoryIndicatorCellModel
*
)
unselectedCellModel
;
myUnselectedCellModel
.
backgroundViewMaskFrame
=
CGRectZero
;
myUnselectedCellModel
.
cellBackgroundUnselectedColor
=
self
.
cellBackgroundUnselectedColor
;
myUnselectedCellModel
.
cellBackgroundSelectedColor
=
self
.
cellBackgroundSelectedColor
;
JXCategoryIndicatorCellModel
*
myselectedCellModel
=
(
JXCategoryIndicatorCellModel
*
)
selectedCellModel
;
myselectedCellModel
.
cellBackgroundUnselectedColor
=
self
.
cellBackgroundUnselectedColor
;
myselectedCellModel
.
cellBackgroundSelectedColor
=
self
.
cellBackgroundSelectedColor
;
}
-
(
void
)
contentOffsetOfContentScrollViewDidChanged
:
(
CGPoint
)
contentOffset
{
[
super
contentOffsetOfContentScrollViewDidChanged
:
contentOffset
];
CGFloat
ratio
=
contentOffset
.
x
/
self
.
contentScrollView
.
bounds
.
size
.
width
;
if
(
ratio
>
self
.
dataSource
.
count
-
1
||
ratio
<
0
)
{
//超过了边界,不需要处理
return
;
}
ratio
=
MAX
(
0
,
MIN
(
self
.
dataSource
.
count
-
1
,
ratio
));
NSInteger
baseIndex
=
floorf
(
ratio
);
if
(
baseIndex
+
1
>=
self
.
dataSource
.
count
)
{
//右边越界了,不需要处理
return
;
}
CGFloat
remainderRatio
=
ratio
-
baseIndex
;
CGRect
leftCellFrame
=
[
self
getTargetCellFrame
:
baseIndex
];
CGRect
rightCellFrame
=
[
self
getTargetCellFrame
:
baseIndex
+
1
];
JXCategoryIndicatorParamsModel
*
indicatorParamsModel
=
[[
JXCategoryIndicatorParamsModel
alloc
]
init
];
indicatorParamsModel
.
selectedIndex
=
self
.
selectedIndex
;
indicatorParamsModel
.
leftIndex
=
baseIndex
;
indicatorParamsModel
.
leftCellFrame
=
leftCellFrame
;
indicatorParamsModel
.
rightIndex
=
baseIndex
+
1
;
indicatorParamsModel
.
rightCellFrame
=
rightCellFrame
;
indicatorParamsModel
.
percent
=
remainderRatio
;
if
(
remainderRatio
==
0
)
{
for
(
UIView
<
JXCategoryIndicatorProtocol
>
*
component
in
self
.
indicators
)
{
[
component
jx_contentScrollViewDidScroll
:
indicatorParamsModel
];
}
}
else
{
JXCategoryIndicatorCellModel
*
leftCellModel
=
(
JXCategoryIndicatorCellModel
*
)
self
.
dataSource
[
baseIndex
];
JXCategoryIndicatorCellModel
*
rightCellModel
=
(
JXCategoryIndicatorCellModel
*
)
self
.
dataSource
[
baseIndex
+
1
];
[
self
refreshLeftCellModel
:
leftCellModel
rightCellModel
:
rightCellModel
ratio
:
remainderRatio
];
for
(
UIView
<
JXCategoryIndicatorProtocol
>
*
component
in
self
.
indicators
)
{
[
component
jx_contentScrollViewDidScroll
:
indicatorParamsModel
];
if
([
component
isKindOfClass
:[
JXCategoryIndicatorBackgroundView
class
]])
{
CGRect
leftMaskFrame
=
component
.
frame
;
leftMaskFrame
.
origin
.
x
=
leftMaskFrame
.
origin
.
x
-
leftCellFrame
.
origin
.
x
;
leftCellModel
.
backgroundViewMaskFrame
=
leftMaskFrame
;
CGRect
rightMaskFrame
=
component
.
frame
;
rightMaskFrame
.
origin
.
x
=
rightMaskFrame
.
origin
.
x
-
rightCellFrame
.
origin
.
x
;
rightCellModel
.
backgroundViewMaskFrame
=
rightMaskFrame
;
}
}
JXCategoryBaseCell
*
leftCell
=
(
JXCategoryBaseCell
*
)[
self
.
collectionView
cellForItemAtIndexPath
:[
NSIndexPath
indexPathForItem
:
baseIndex
inSection
:
0
]];
[
leftCell
reloadData
:
leftCellModel
];
JXCategoryBaseCell
*
rightCell
=
(
JXCategoryBaseCell
*
)[
self
.
collectionView
cellForItemAtIndexPath
:[
NSIndexPath
indexPathForItem
:
baseIndex
+
1
inSection
:
0
]];
[
rightCell
reloadData
:
rightCellModel
];
}
}
-
(
BOOL
)
selectCellAtIndex
:
(
NSInteger
)
index
isClicked
:
(
BOOL
)
isClicked
{
NSInteger
lastSelectedIndex
=
self
.
selectedIndex
;
BOOL
result
=
[
super
selectCellAtIndex
:
index
isClicked
:
isClicked
];
if
(
!
result
)
{
return
NO
;
}
CGRect
clickedCellFrame
=
[
self
getTargetCellFrame
:
index
];
JXCategoryIndicatorCellModel
*
selectedCellModel
=
(
JXCategoryIndicatorCellModel
*
)
self
.
dataSource
[
index
];
for
(
UIView
<
JXCategoryIndicatorProtocol
>
*
component
in
self
.
indicators
)
{
JXCategoryIndicatorParamsModel
*
indicatorParamsModel
=
[[
JXCategoryIndicatorParamsModel
alloc
]
init
];
indicatorParamsModel
.
lastSelectedIndex
=
lastSelectedIndex
;
indicatorParamsModel
.
selectedIndex
=
index
;
indicatorParamsModel
.
selectedCellFrame
=
clickedCellFrame
;
indicatorParamsModel
.
isClicked
=
isClicked
;
[
component
jx_selectedCell
:
indicatorParamsModel
];
if
([
component
isKindOfClass
:[
JXCategoryIndicatorBackgroundView
class
]])
{
CGRect
maskFrame
=
component
.
frame
;
maskFrame
.
origin
.
x
=
maskFrame
.
origin
.
x
-
clickedCellFrame
.
origin
.
x
;
selectedCellModel
.
backgroundViewMaskFrame
=
maskFrame
;
}
}
JXCategoryIndicatorCell
*
selectedCell
=
(
JXCategoryIndicatorCell
*
)[
self
.
collectionView
cellForItemAtIndexPath
:[
NSIndexPath
indexPathForItem
:
index
inSection
:
0
]];
[
selectedCell
reloadData
:
selectedCellModel
];
return
YES
;
}
-
(
void
)
refreshLeftCellModel
:
(
JXCategoryBaseCellModel
*
)
leftCellModel
rightCellModel
:
(
JXCategoryBaseCellModel
*
)
rightCellModel
ratio
:
(
CGFloat
)
ratio
{
if
(
self
.
cellBackgroundColorGradientEnabled
)
{
//处理cell背景色渐变
JXCategoryIndicatorCellModel
*
leftModel
=
(
JXCategoryIndicatorCellModel
*
)
leftCellModel
;
JXCategoryIndicatorCellModel
*
rightModel
=
(
JXCategoryIndicatorCellModel
*
)
rightCellModel
;
if
(
leftModel
.
selected
)
{
leftModel
.
cellBackgroundSelectedColor
=
[
JXCategoryFactory
interpolationColorFrom
:
self
.
cellBackgroundSelectedColor
to
:
self
.
cellBackgroundUnselectedColor
percent
:
ratio
];
leftModel
.
cellBackgroundUnselectedColor
=
self
.
cellBackgroundUnselectedColor
;
}
else
{
leftModel
.
cellBackgroundUnselectedColor
=
[
JXCategoryFactory
interpolationColorFrom
:
self
.
cellBackgroundSelectedColor
to
:
self
.
cellBackgroundUnselectedColor
percent
:
ratio
];
leftModel
.
cellBackgroundSelectedColor
=
self
.
cellBackgroundSelectedColor
;
}
if
(
rightModel
.
selected
)
{
rightModel
.
cellBackgroundSelectedColor
=
[
JXCategoryFactory
interpolationColorFrom
:
self
.
cellBackgroundUnselectedColor
to
:
self
.
cellBackgroundSelectedColor
percent
:
ratio
];
rightModel
.
cellBackgroundUnselectedColor
=
self
.
cellBackgroundUnselectedColor
;
}
else
{
rightModel
.
cellBackgroundUnselectedColor
=
[
JXCategoryFactory
interpolationColorFrom
:
self
.
cellBackgroundUnselectedColor
to
:
self
.
cellBackgroundSelectedColor
percent
:
ratio
];
rightModel
.
cellBackgroundSelectedColor
=
self
.
cellBackgroundSelectedColor
;
}
}
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/JXCategoryView.h
0 → 100755
View file @
a4f39813
#import "JXCategoryBaseView.h"
#import "JXCategoryIndicatorView.h"
#import "JXCategoryTitleView.h"
#import "JXCategoryImageView.h"
#import "JXCategoryTitleImageView.h"
#import "JXCategoryNumberView.h"
#import "JXCategoryDotView.h"
#import "JXCategoryFactory.h"
#import "JXCategoryIndicatorProtocol.h"
#import "JXCategoryViewDefines.h"
#import "JXCategoryListVCContainerView.h"
#import "JXCategoryListContainerView.h"
#import "JXCategoryIndicatorComponentView.h"
#import "JXCategoryIndicatorLineView.h"
#import "JXCategoryIndicatorTriangleView.h"
#import "JXCategoryIndicatorImageView.h"
#import "JXCategoryIndicatorBackgroundView.h"
#import "JXCategoryIndicatorBallView.h"
#import "JXCategoryIndicatorRainbowLineView.h"
GMBase/Classes/JXPagerView/JXCategoryView/Number/JXCategoryNumberCell.h
0 → 100755
View file @
a4f39813
//
// JXCategoryNumberCell.h
// DQGuess
//
// Created by jiaxin on 2018/4/9.
// Copyright © 2018年 jingbo. All rights reserved.
//
#import "JXCategoryTitleCell.h"
@interface
JXCategoryNumberCell
:
JXCategoryTitleCell
@property
(
nonatomic
,
strong
)
UILabel
*
numberLabel
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Number/JXCategoryNumberCell.m
0 → 100755
View file @
a4f39813
//
// JXCategoryNumberCell.m
// DQGuess
//
// Created by jiaxin on 2018/4/9.
// Copyright © 2018年 jingbo. All rights reserved.
//
#import "JXCategoryNumberCell.h"
#import "JXCategoryNumberCellModel.h"
@interface
JXCategoryNumberCell
()
@end
@implementation
JXCategoryNumberCell
-
(
void
)
initializeViews
{
[
super
initializeViews
];
self
.
numberLabel
=
({
UILabel
*
label
=
[[
UILabel
alloc
]
init
];
label
.
textAlignment
=
NSTextAlignmentCenter
;
label
.
layer
.
masksToBounds
=
YES
;
label
;
});
[
self
.
contentView
addSubview
:
self
.
numberLabel
];
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
[
self
.
numberLabel
sizeToFit
];
JXCategoryNumberCellModel
*
myCellModel
=
(
JXCategoryNumberCellModel
*
)
self
.
cellModel
;
self
.
numberLabel
.
bounds
=
CGRectMake
(
0
,
0
,
self
.
numberLabel
.
bounds
.
size
.
width
+
myCellModel
.
numberLabelWidthIncrement
,
myCellModel
.
numberLabelHeight
);
self
.
numberLabel
.
layer
.
cornerRadius
=
myCellModel
.
numberLabelHeight
/
2
.
0
;
self
.
numberLabel
.
center
=
CGPointMake
(
CGRectGetMaxX
(
self
.
titleLabel
.
frame
),
CGRectGetMinY
(
self
.
titleLabel
.
frame
));
}
-
(
void
)
reloadData
:
(
JXCategoryBaseCellModel
*
)
cellModel
{
[
super
reloadData
:
cellModel
];
JXCategoryNumberCellModel
*
myCellModel
=
(
JXCategoryNumberCellModel
*
)
cellModel
;
self
.
numberLabel
.
hidden
=
myCellModel
.
count
==
0
;
self
.
numberLabel
.
backgroundColor
=
myCellModel
.
numberBackgroundColor
;
self
.
numberLabel
.
font
=
myCellModel
.
numberLabelFont
;
self
.
numberLabel
.
textColor
=
myCellModel
.
numberTitleColor
;
self
.
numberLabel
.
text
=
[
NSString
stringWithFormat
:
@"%ld"
,
(
long
)
myCellModel
.
count
];
if
(
myCellModel
.
count
>=
1000
)
{
self
.
numberLabel
.
text
=
@"999+"
;
}
[
self
setNeedsLayout
];
[
self
layoutIfNeeded
];
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Number/JXCategoryNumberCellModel.h
0 → 100755
View file @
a4f39813
//
// JXCategoryNumberCellModel.h
// DQGuess
//
// Created by jiaxin on 2018/4/24.
// Copyright © 2018年 jingbo. All rights reserved.
//
#import "JXCategoryTitleCellModel.h"
@interface
JXCategoryNumberCellModel
:
JXCategoryTitleCellModel
@property
(
nonatomic
,
assign
)
NSInteger
count
;
@property
(
nonatomic
,
strong
)
UIColor
*
numberBackgroundColor
;
@property
(
nonatomic
,
strong
)
UIColor
*
numberTitleColor
;
@property
(
nonatomic
,
assign
)
CGFloat
numberLabelWidthIncrement
;
@property
(
nonatomic
,
assign
)
CGFloat
numberLabelHeight
;
@property
(
nonatomic
,
strong
)
UIFont
*
numberLabelFont
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Number/JXCategoryNumberCellModel.m
0 → 100755
View file @
a4f39813
//
// JXCategoryNumberCellModel.m
// DQGuess
//
// Created by jiaxin on 2018/4/24.
// Copyright © 2018年 jingbo. All rights reserved.
//
#import "JXCategoryNumberCellModel.h"
@implementation
JXCategoryNumberCellModel
@end
GMBase/Classes/JXPagerView/JXCategoryView/Number/JXCategoryNumberView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryNumberView.h
// DQGuess
//
// Created by jiaxin on 2018/4/9.
// Copyright © 2018年 jingbo. All rights reserved.
//
#import "JXCategoryTitleView.h"
#import "JXCategoryNumberCell.h"
#import "JXCategoryNumberCellModel.h"
@interface
JXCategoryNumberView
:
JXCategoryTitleView
/**
需要与titles的count对应
*/
@property
(
nonatomic
,
strong
)
NSArray
<
NSNumber
*>
*
counts
;
/**
numberLabel的font,默认:[UIFont systemFontOfSize:11]
*/
@property
(
nonatomic
,
strong
)
UIFont
*
numberLabelFont
;
/**
数字的背景色,默认:[UIColor colorWithRed:241/255.0 green:147/255.0 blue:95/255.0 alpha:1]
*/
@property
(
nonatomic
,
strong
)
UIColor
*
numberBackgroundColor
;
/**
数字的title颜色,默认:[UIColor whiteColor]
*/
@property
(
nonatomic
,
strong
)
UIColor
*
numberTitleColor
;
/**
numberLabel的宽度补偿,label真实的宽度是文字内容的宽度加上补偿的宽度,默认:10
*/
@property
(
nonatomic
,
assign
)
CGFloat
numberLabelWidthIncrement
;
/**
numberLabel的高度,默认:14
*/
@property
(
nonatomic
,
assign
)
CGFloat
numberLabelHeight
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Number/JXCategoryNumberView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryNumberView.m
// DQGuess
//
// Created by jiaxin on 2018/4/9.
// Copyright © 2018年 jingbo. All rights reserved.
//
#import "JXCategoryNumberView.h"
@implementation
JXCategoryNumberView
-
(
void
)
initializeData
{
[
super
initializeData
];
self
.
cellSpacing
=
25
;
_numberTitleColor
=
[
UIColor
whiteColor
];
_numberBackgroundColor
=
[
UIColor
colorWithRed
:
241
/
255
.
0
green
:
147
/
255
.
0
blue
:
95
/
255
.
0
alpha
:
1
];
_numberLabelHeight
=
14
;
_numberLabelWidthIncrement
=
10
;
_numberLabelFont
=
[
UIFont
systemFontOfSize
:
11
];
}
-
(
Class
)
preferredCellClass
{
return
[
JXCategoryNumberCell
class
];
}
-
(
void
)
refreshDataSource
{
NSMutableArray
*
tempArray
=
[
NSMutableArray
array
];
for
(
int
i
=
0
;
i
<
self
.
titles
.
count
;
i
++
)
{
JXCategoryNumberCellModel
*
cellModel
=
[[
JXCategoryNumberCellModel
alloc
]
init
];
[
tempArray
addObject
:
cellModel
];
}
self
.
dataSource
=
tempArray
;
}
-
(
void
)
refreshCellModel
:
(
JXCategoryBaseCellModel
*
)
cellModel
index
:
(
NSInteger
)
index
{
[
super
refreshCellModel
:
cellModel
index
:
index
];
JXCategoryNumberCellModel
*
myCellModel
=
(
JXCategoryNumberCellModel
*
)
cellModel
;
myCellModel
.
count
=
[
self
.
counts
[
index
]
integerValue
];
myCellModel
.
numberBackgroundColor
=
self
.
numberBackgroundColor
;
myCellModel
.
numberTitleColor
=
self
.
numberTitleColor
;
myCellModel
.
numberLabelHeight
=
self
.
numberLabelHeight
;
myCellModel
.
numberLabelWidthIncrement
=
self
.
numberLabelWidthIncrement
;
myCellModel
.
numberLabelFont
=
self
.
numberLabelFont
;
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Title/JXCategoryTitleCell.h
0 → 100755
View file @
a4f39813
//
// JXCategoryTitleCell.h
// UI系列测试
//
// Created by jiaxin on 2018/3/15.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorCell.h"
@interface
JXCategoryTitleCell
:
JXCategoryIndicatorCell
@property
(
nonatomic
,
strong
)
UILabel
*
titleLabel
;
@property
(
nonatomic
,
strong
)
UILabel
*
maskTitleLabel
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Title/JXCategoryTitleCell.m
0 → 100755
View file @
a4f39813
//
// JXCategoryTitleCell.m
// UI系列测试
//
// Created by jiaxin on 2018/3/15.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryTitleCell.h"
#import "JXCategoryTitleCellModel.h"
@interface
JXCategoryTitleCell
()
@property
(
nonatomic
,
strong
)
CALayer
*
maskLayer
;
@end
@implementation
JXCategoryTitleCell
-
(
void
)
initializeViews
{
[
super
initializeViews
];
_titleLabel
=
[[
UILabel
alloc
]
init
];
self
.
titleLabel
.
textAlignment
=
NSTextAlignmentCenter
;
[
self
.
contentView
addSubview
:
self
.
titleLabel
];
_maskTitleLabel
=
[[
UILabel
alloc
]
init
];
_maskTitleLabel
.
hidden
=
YES
;
self
.
maskTitleLabel
.
textAlignment
=
NSTextAlignmentCenter
;
[
self
.
contentView
addSubview
:
self
.
maskTitleLabel
];
_maskLayer
=
[
CALayer
layer
];
self
.
maskLayer
.
backgroundColor
=
[
UIColor
redColor
].
CGColor
;
self
.
maskTitleLabel
.
layer
.
mask
=
self
.
maskLayer
;
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
self
.
titleLabel
.
center
=
self
.
contentView
.
center
;
self
.
maskTitleLabel
.
center
=
self
.
contentView
.
center
;
}
-
(
void
)
reloadData
:
(
JXCategoryBaseCellModel
*
)
cellModel
{
[
super
reloadData
:
cellModel
];
JXCategoryTitleCellModel
*
myCellModel
=
(
JXCategoryTitleCellModel
*
)
cellModel
;
CGFloat
pointSize
=
myCellModel
.
titleFont
.
pointSize
;
UIFontDescriptor
*
fontDescriptor
=
myCellModel
.
titleFont
.
fontDescriptor
;
if
(
myCellModel
.
selected
)
{
fontDescriptor
=
myCellModel
.
titleSelectedFont
.
fontDescriptor
;
pointSize
=
myCellModel
.
titleSelectedFont
.
pointSize
;
}
if
(
myCellModel
.
titleLabelZoomEnabled
)
{
self
.
titleLabel
.
font
=
[
UIFont
fontWithDescriptor
:
fontDescriptor
size
:
pointSize
*
myCellModel
.
titleLabelZoomScale
];
self
.
maskTitleLabel
.
font
=
[
UIFont
fontWithDescriptor
:
fontDescriptor
size
:
pointSize
*
myCellModel
.
titleLabelZoomScale
];
}
else
{
self
.
titleLabel
.
font
=
[
UIFont
fontWithDescriptor
:
fontDescriptor
size
:
pointSize
];
self
.
maskTitleLabel
.
font
=
[
UIFont
fontWithDescriptor
:
fontDescriptor
size
:
pointSize
];
}
NSString
*
titleString
=
myCellModel
.
title
?
myCellModel
.
title
:
@""
;
NSMutableAttributedString
*
attriString
=
[[
NSMutableAttributedString
alloc
]
initWithString
:
titleString
];
if
(
myCellModel
.
titleLabelStrokeWidthEnabled
)
{
[
attriString
addAttribute
:
NSStrokeWidthAttributeName
value
:
@
(
myCellModel
.
titleLabelSelectedStrokeWidth
)
range
:
NSMakeRange
(
0
,
myCellModel
.
title
.
length
)];
}
self
.
maskTitleLabel
.
hidden
=
!
myCellModel
.
titleLabelMaskEnabled
;
if
(
myCellModel
.
titleLabelMaskEnabled
)
{
self
.
titleLabel
.
textColor
=
myCellModel
.
titleColor
;
self
.
maskTitleLabel
.
font
=
myCellModel
.
titleFont
;
self
.
maskTitleLabel
.
textColor
=
myCellModel
.
titleSelectedColor
;
self
.
maskTitleLabel
.
attributedText
=
attriString
;
[
self
.
maskTitleLabel
sizeToFit
];
CGRect
frame
=
myCellModel
.
backgroundViewMaskFrame
;
frame
.
origin
.
x
-=
(
self
.
contentView
.
bounds
.
size
.
width
-
self
.
maskTitleLabel
.
bounds
.
size
.
width
)
/
2
;
frame
.
origin
.
y
=
0
;
[
CATransaction
begin
];
[
CATransaction
setDisableActions
:
YES
];
self
.
maskLayer
.
frame
=
frame
;
[
CATransaction
commit
];
}
else
{
if
(
myCellModel
.
selected
)
{
self
.
titleLabel
.
textColor
=
myCellModel
.
titleSelectedColor
;
}
else
{
self
.
titleLabel
.
textColor
=
myCellModel
.
titleColor
;
}
}
self
.
titleLabel
.
attributedText
=
attriString
;
[
self
.
titleLabel
sizeToFit
];
[
self
setNeedsLayout
];
[
self
layoutIfNeeded
];
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Title/JXCategoryTitleCellModel.h
0 → 100755
View file @
a4f39813
//
// JXCategoryTitleCellModel.h
// UI系列测试
//
// Created by jiaxin on 2018/3/15.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorCellModel.h"
#import <UIKit/UIKit.h>
@interface
JXCategoryTitleCellModel
:
JXCategoryIndicatorCellModel
@property
(
nonatomic
,
copy
)
NSString
*
title
;
@property
(
nonatomic
,
strong
)
UIColor
*
titleColor
;
@property
(
nonatomic
,
strong
)
UIColor
*
titleSelectedColor
;
@property
(
nonatomic
,
strong
)
UIFont
*
titleFont
;
@property
(
nonatomic
,
strong
)
UIFont
*
titleSelectedFont
;
@property
(
nonatomic
,
assign
)
BOOL
titleLabelMaskEnabled
;
@property
(
nonatomic
,
strong
)
CALayer
*
backgroundEllipseLayer
;
@property
(
nonatomic
,
assign
)
BOOL
titleLabelZoomEnabled
;
@property
(
nonatomic
,
assign
)
CGFloat
titleLabelZoomScale
;
@property
(
nonatomic
,
assign
)
CGFloat
titleLabelStrokeWidthEnabled
;
@property
(
nonatomic
,
assign
)
CGFloat
titleLabelSelectedStrokeWidth
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Title/JXCategoryTitleCellModel.m
0 → 100755
View file @
a4f39813
//
// JXCategoryTitleCellModel.m
// UI系列测试
//
// Created by jiaxin on 2018/3/15.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryTitleCellModel.h"
@implementation
JXCategoryTitleCellModel
@end
GMBase/Classes/JXPagerView/JXCategoryView/Title/JXCategoryTitleView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryView.h
// UI系列测试
//
// Created by jiaxin on 2018/3/15.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryIndicatorView.h"
#import "JXCategoryTitleCell.h"
#import "JXCategoryTitleCellModel.h"
@interface
JXCategoryTitleView
:
JXCategoryIndicatorView
@property
(
nonatomic
,
strong
)
NSArray
<
NSString
*>*
titles
;
@property
(
nonatomic
,
strong
)
UIColor
*
titleColor
;
//默认:[UIColor blackColor]
@property
(
nonatomic
,
strong
)
UIColor
*
titleSelectedColor
;
//默认:[UIColor redColor]
@property
(
nonatomic
,
strong
)
UIFont
*
titleFont
;
//默认:[UIFont systemFontOfSize:15]
@property
(
nonatomic
,
strong
)
UIFont
*
titleSelectedFont
;
//文字被选中的字体。默认:与titleFont一样
@property
(
nonatomic
,
assign
)
BOOL
titleColorGradientEnabled
;
//默认:NO,title的颜色是否渐变过渡
@property
(
nonatomic
,
assign
)
BOOL
titleLabelMaskEnabled
;
//默认:NO,titleLabel是否遮罩过滤。(需要backgroundEllipseLayerShowEnabled = YES)
//----------------------titleLabelZoomEnabled-----------------------//
@property
(
nonatomic
,
assign
)
BOOL
titleLabelZoomEnabled
;
//默认为NO
@property
(
nonatomic
,
assign
)
BOOL
titleLabelZoomScrollGradientEnabled
;
//手势滚动中,是否需要更新状态。默认为YES
@property
(
nonatomic
,
assign
)
CGFloat
titleLabelZoomScale
;
//默认1.2,titleLabelZoomEnabled为YES才生效
//----------------------titleLabelStrokeWidth-----------------------//
@property
(
nonatomic
,
assign
)
CGFloat
titleLabelStrokeWidthEnabled
;
//默认:NO
@property
(
nonatomic
,
assign
)
CGFloat
titleLabelSelectedStrokeWidth
;
//默认:-3,用于控制字体的粗细(底层通过NSStrokeWidthAttributeName实现)。使用该属性,务必让titleFont和titleSelectedFont设置为一样的!!!
@end
GMBase/Classes/JXPagerView/JXCategoryView/Title/JXCategoryTitleView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryView.m
// UI系列测试
//
// Created by jiaxin on 2018/3/15.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryTitleView.h"
#import "JXCategoryFactory.h"
@interface
JXCategoryTitleView
()
@end
@implementation
JXCategoryTitleView
-
(
void
)
initializeData
{
[
super
initializeData
];
_titleLabelZoomEnabled
=
NO
;
_titleLabelZoomScale
=
1
.
2
;
_titleColor
=
[
UIColor
blackColor
];
_titleSelectedColor
=
[
UIColor
redColor
];
_titleFont
=
[
UIFont
systemFontOfSize
:
15
];
_titleColorGradientEnabled
=
NO
;
_titleLabelMaskEnabled
=
NO
;
_titleLabelZoomScrollGradientEnabled
=
YES
;
_titleLabelStrokeWidthEnabled
=
NO
;
_titleLabelSelectedStrokeWidth
=
-
3
;
}
-
(
UIFont
*
)
titleSelectedFont
{
if
(
_titleSelectedFont
!=
nil
)
{
return
_titleSelectedFont
;
}
return
self
.
titleFont
;
}
#pragma mark - Override
-
(
Class
)
preferredCellClass
{
return
[
JXCategoryTitleCell
class
];
}
-
(
void
)
refreshDataSource
{
NSMutableArray
*
tempArray
=
[
NSMutableArray
array
];
for
(
int
i
=
0
;
i
<
self
.
titles
.
count
;
i
++
)
{
JXCategoryTitleCellModel
*
cellModel
=
[[
JXCategoryTitleCellModel
alloc
]
init
];
[
tempArray
addObject
:
cellModel
];
}
self
.
dataSource
=
tempArray
;
}
-
(
void
)
refreshSelectedCellModel
:
(
JXCategoryBaseCellModel
*
)
selectedCellModel
unselectedCellModel
:
(
JXCategoryBaseCellModel
*
)
unselectedCellModel
{
[
super
refreshSelectedCellModel
:
selectedCellModel
unselectedCellModel
:
unselectedCellModel
];
JXCategoryTitleCellModel
*
myUnselectedCellModel
=
(
JXCategoryTitleCellModel
*
)
unselectedCellModel
;
myUnselectedCellModel
.
titleColor
=
self
.
titleColor
;
myUnselectedCellModel
.
titleSelectedColor
=
self
.
titleSelectedColor
;
myUnselectedCellModel
.
titleLabelZoomScale
=
1
.
0
;
myUnselectedCellModel
.
titleLabelSelectedStrokeWidth
=
0
;
JXCategoryTitleCellModel
*
myselectedCellModel
=
(
JXCategoryTitleCellModel
*
)
selectedCellModel
;
myselectedCellModel
.
titleColor
=
self
.
titleColor
;
myselectedCellModel
.
titleSelectedColor
=
self
.
titleSelectedColor
;
myselectedCellModel
.
titleLabelZoomScale
=
self
.
titleLabelZoomScale
;
myselectedCellModel
.
titleLabelSelectedStrokeWidth
=
self
.
titleLabelSelectedStrokeWidth
;
}
-
(
void
)
refreshLeftCellModel
:
(
JXCategoryBaseCellModel
*
)
leftCellModel
rightCellModel
:
(
JXCategoryBaseCellModel
*
)
rightCellModel
ratio
:
(
CGFloat
)
ratio
{
[
super
refreshLeftCellModel
:
leftCellModel
rightCellModel
:
rightCellModel
ratio
:
ratio
];
JXCategoryTitleCellModel
*
leftModel
=
(
JXCategoryTitleCellModel
*
)
leftCellModel
;
JXCategoryTitleCellModel
*
rightModel
=
(
JXCategoryTitleCellModel
*
)
rightCellModel
;
if
(
self
.
titleLabelZoomEnabled
&&
self
.
titleLabelZoomScrollGradientEnabled
)
{
leftModel
.
titleLabelZoomScale
=
[
JXCategoryFactory
interpolationFrom
:
self
.
titleLabelZoomScale
to
:
1
.
0
percent
:
ratio
];
rightModel
.
titleLabelZoomScale
=
[
JXCategoryFactory
interpolationFrom
:
1
.
0
to
:
self
.
titleLabelZoomScale
percent
:
ratio
];
}
if
(
self
.
titleLabelStrokeWidthEnabled
)
{
leftModel
.
titleLabelSelectedStrokeWidth
=
[
JXCategoryFactory
interpolationFrom
:
self
.
titleLabelSelectedStrokeWidth
to
:
0
percent
:
ratio
];
rightModel
.
titleLabelSelectedStrokeWidth
=
[
JXCategoryFactory
interpolationFrom
:
0
to
:
self
.
titleLabelSelectedStrokeWidth
percent
:
ratio
];
}
if
(
self
.
titleColorGradientEnabled
)
{
//处理颜色渐变
if
(
leftModel
.
selected
)
{
leftModel
.
titleSelectedColor
=
[
JXCategoryFactory
interpolationColorFrom
:
self
.
titleSelectedColor
to
:
self
.
titleColor
percent
:
ratio
];
leftModel
.
titleColor
=
self
.
titleColor
;
}
else
{
leftModel
.
titleColor
=
[
JXCategoryFactory
interpolationColorFrom
:
self
.
titleSelectedColor
to
:
self
.
titleColor
percent
:
ratio
];
leftModel
.
titleSelectedColor
=
self
.
titleSelectedColor
;
}
if
(
rightModel
.
selected
)
{
rightModel
.
titleSelectedColor
=
[
JXCategoryFactory
interpolationColorFrom
:
self
.
titleColor
to
:
self
.
titleSelectedColor
percent
:
ratio
];
rightModel
.
titleColor
=
self
.
titleColor
;
}
else
{
rightModel
.
titleColor
=
[
JXCategoryFactory
interpolationColorFrom
:
self
.
titleColor
to
:
self
.
titleSelectedColor
percent
:
ratio
];
rightModel
.
titleSelectedColor
=
self
.
titleSelectedColor
;
}
}
}
-
(
CGFloat
)
preferredCellWidthAtIndex
:
(
NSInteger
)
index
{
if
(
self
.
cellWidth
==
JXCategoryViewAutomaticDimension
)
{
return
ceilf
([
self
.
titles
[
index
]
boundingRectWithSize
:
CGSizeMake
(
MAXFLOAT
,
self
.
bounds
.
size
.
height
)
options
:
NSStringDrawingUsesLineFragmentOrigin
|
NSStringDrawingUsesFontLeading
attributes
:
@{
NSFontAttributeName
:
self
.
titleFont
}
context
:
nil
].
size
.
width
);
}
else
{
return
self
.
cellWidth
;
}
}
-
(
void
)
refreshCellModel
:
(
JXCategoryBaseCellModel
*
)
cellModel
index
:
(
NSInteger
)
index
{
[
super
refreshCellModel
:
cellModel
index
:
index
];
JXCategoryTitleCellModel
*
model
=
(
JXCategoryTitleCellModel
*
)
cellModel
;
model
.
titleFont
=
self
.
titleFont
;
model
.
titleSelectedFont
=
self
.
titleSelectedFont
;
model
.
titleColor
=
self
.
titleColor
;
model
.
titleSelectedColor
=
self
.
titleSelectedColor
;
model
.
title
=
self
.
titles
[
index
];
model
.
titleLabelMaskEnabled
=
self
.
titleLabelMaskEnabled
;
model
.
titleLabelZoomEnabled
=
self
.
titleLabelZoomEnabled
;
model
.
titleLabelZoomScale
=
1
.
0
;
model
.
titleLabelStrokeWidthEnabled
=
self
.
titleLabelStrokeWidthEnabled
;
model
.
titleLabelSelectedStrokeWidth
=
0
;
if
(
index
==
self
.
selectedIndex
)
{
model
.
titleLabelZoomScale
=
self
.
titleLabelZoomScale
;
model
.
titleLabelSelectedStrokeWidth
=
self
.
titleLabelSelectedStrokeWidth
;
}
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Title/TitleImage/JXCategoryTitleImageCell.h
0 → 100755
View file @
a4f39813
//
// JXCategoryImageCell.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/8.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryTitleCell.h"
@interface
JXCategoryTitleImageCell
:
JXCategoryTitleCell
@property
(
nonatomic
,
strong
)
UIImageView
*
imageView
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Title/TitleImage/JXCategoryTitleImageCell.m
0 → 100755
View file @
a4f39813
//
// JXCategoryImageCell.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/8.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryTitleImageCell.h"
#import "JXCategoryTitleImageCellModel.h"
@interface
JXCategoryTitleImageCell
()
@end
@implementation
JXCategoryTitleImageCell
-
(
void
)
initializeViews
{
[
super
initializeViews
];
_imageView
=
[[
UIImageView
alloc
]
init
];
_imageView
.
contentMode
=
UIViewContentModeScaleAspectFit
;
[
self
.
contentView
addSubview
:
_imageView
];
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
JXCategoryTitleImageCellModel
*
myCellModel
=
(
JXCategoryTitleImageCellModel
*
)
self
.
cellModel
;
self
.
titleLabel
.
hidden
=
NO
;
self
.
imageView
.
hidden
=
NO
;
CGSize
imageSize
=
myCellModel
.
imageSize
;
self
.
imageView
.
bounds
=
CGRectMake
(
0
,
0
,
imageSize
.
width
,
imageSize
.
height
);
switch
(
myCellModel
.
imageType
)
{
case
JXCategoryTitleImageType_TopImage
:
{
CGFloat
contentHeight
=
imageSize
.
height
+
myCellModel
.
titleImageSpacing
+
self
.
titleLabel
.
bounds
.
size
.
height
;
self
.
imageView
.
center
=
CGPointMake
(
self
.
contentView
.
center
.
x
,
(
self
.
contentView
.
bounds
.
size
.
height
-
contentHeight
)
/
2
+
imageSize
.
height
/
2
);
self
.
titleLabel
.
center
=
CGPointMake
(
self
.
contentView
.
center
.
x
,
CGRectGetMaxY
(
self
.
imageView
.
frame
)
+
myCellModel
.
titleImageSpacing
+
self
.
titleLabel
.
bounds
.
size
.
height
/
2
);
}
break
;
case
JXCategoryTitleImageType_LeftImage
:
{
CGFloat
contentWidth
=
imageSize
.
width
+
myCellModel
.
titleImageSpacing
+
self
.
titleLabel
.
bounds
.
size
.
width
;
self
.
imageView
.
center
=
CGPointMake
((
self
.
contentView
.
bounds
.
size
.
width
-
contentWidth
)
/
2
+
imageSize
.
width
/
2
,
self
.
contentView
.
center
.
y
);
self
.
titleLabel
.
center
=
CGPointMake
(
CGRectGetMaxX
(
self
.
imageView
.
frame
)
+
myCellModel
.
titleImageSpacing
+
self
.
titleLabel
.
bounds
.
size
.
width
/
2
,
self
.
contentView
.
center
.
y
);
}
break
;
case
JXCategoryTitleImageType_BottomImage
:
{
CGFloat
contentHeight
=
imageSize
.
height
+
myCellModel
.
titleImageSpacing
+
self
.
titleLabel
.
bounds
.
size
.
height
;
self
.
titleLabel
.
center
=
CGPointMake
(
self
.
contentView
.
center
.
x
,
(
self
.
contentView
.
bounds
.
size
.
height
-
contentHeight
)
/
2
+
self
.
titleLabel
.
bounds
.
size
.
height
/
2
);
self
.
imageView
.
center
=
CGPointMake
(
self
.
contentView
.
center
.
x
,
CGRectGetMaxY
(
self
.
titleLabel
.
frame
)
+
myCellModel
.
titleImageSpacing
+
imageSize
.
height
/
2
);
}
break
;
case
JXCategoryTitleImageType_RightImage
:
{
CGFloat
contentWidth
=
imageSize
.
width
+
myCellModel
.
titleImageSpacing
+
self
.
titleLabel
.
bounds
.
size
.
width
;
self
.
titleLabel
.
center
=
CGPointMake
((
self
.
contentView
.
bounds
.
size
.
width
-
contentWidth
)
/
2
+
self
.
titleLabel
.
bounds
.
size
.
width
/
2
,
self
.
contentView
.
center
.
y
);
self
.
imageView
.
center
=
CGPointMake
(
CGRectGetMaxX
(
self
.
titleLabel
.
frame
)
+
myCellModel
.
titleImageSpacing
+
imageSize
.
width
/
2
,
self
.
contentView
.
center
.
y
);
}
break
;
case
JXCategoryTitleImageType_OnlyImage
:
{
self
.
titleLabel
.
hidden
=
YES
;
self
.
imageView
.
center
=
self
.
contentView
.
center
;
}
break
;
case
JXCategoryTitleImageType_OnlyTitle
:
{
self
.
imageView
.
hidden
=
YES
;
self
.
titleLabel
.
center
=
self
.
contentView
.
center
;
}
break
;
default
:
break
;
}
}
-
(
void
)
reloadData
:
(
JXCategoryBaseCellModel
*
)
cellModel
{
[
super
reloadData
:
cellModel
];
JXCategoryTitleImageCellModel
*
myCellModel
=
(
JXCategoryTitleImageCellModel
*
)
cellModel
;
if
(
myCellModel
.
imageName
!=
nil
)
{
self
.
imageView
.
image
=
[
UIImage
imageNamed
:
myCellModel
.
imageName
];
}
else
if
(
myCellModel
.
imageURL
!=
nil
)
{
if
(
myCellModel
.
loadImageCallback
!=
nil
)
{
myCellModel
.
loadImageCallback
(
self
.
imageView
,
myCellModel
.
imageURL
);
}
}
if
(
myCellModel
.
selected
)
{
if
(
myCellModel
.
selectedImageName
!=
nil
)
{
self
.
imageView
.
image
=
[
UIImage
imageNamed
:
myCellModel
.
selectedImageName
];
}
else
if
(
myCellModel
.
selectedImageURL
!=
nil
)
{
if
(
myCellModel
.
loadImageCallback
!=
nil
)
{
myCellModel
.
loadImageCallback
(
self
.
imageView
,
myCellModel
.
selectedImageURL
);
}
}
}
if
(
myCellModel
.
imageZoomEnabled
)
{
self
.
imageView
.
transform
=
CGAffineTransformMakeScale
(
myCellModel
.
imageZoomScale
,
myCellModel
.
imageZoomScale
);
}
else
{
self
.
imageView
.
transform
=
CGAffineTransformIdentity
;
}
[
self
setNeedsLayout
];
[
self
layoutIfNeeded
];
}
@end
GMBase/Classes/JXPagerView/JXCategoryView/Title/TitleImage/JXCategoryTitleImageCellModel.h
0 → 100755
View file @
a4f39813
//
// JXCategoryTitleImageCellModel.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/8.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryTitleCellModel.h"
typedef
NS_ENUM
(
NSUInteger
,
JXCategoryTitleImageType
)
{
JXCategoryTitleImageType_TopImage
=
0
,
JXCategoryTitleImageType_LeftImage
,
JXCategoryTitleImageType_BottomImage
,
JXCategoryTitleImageType_RightImage
,
JXCategoryTitleImageType_OnlyImage
,
JXCategoryTitleImageType_OnlyTitle
,
};
@interface
JXCategoryTitleImageCellModel
:
JXCategoryTitleCellModel
@property
(
nonatomic
,
assign
)
JXCategoryTitleImageType
imageType
;
@property
(
nonatomic
,
copy
)
void
(
^
loadImageCallback
)(
UIImageView
*
imageView
,
NSURL
*
imageURL
);
@property
(
nonatomic
,
copy
)
NSString
*
imageName
;
//加载bundle内的图片
@property
(
nonatomic
,
strong
)
NSURL
*
imageURL
;
//图片URL
@property
(
nonatomic
,
copy
)
NSString
*
selectedImageName
;
@property
(
nonatomic
,
strong
)
NSURL
*
selectedImageURL
;
@property
(
nonatomic
,
assign
)
CGSize
imageSize
;
//默认CGSizeMake(20, 20)
@property
(
nonatomic
,
assign
)
CGFloat
titleImageSpacing
;
//titleLabel和ImageView的间距,默认5
@property
(
nonatomic
,
assign
)
BOOL
imageZoomEnabled
;
@property
(
nonatomic
,
assign
)
CGFloat
imageZoomScale
;
@end
GMBase/Classes/JXPagerView/JXCategoryView/Title/TitleImage/JXCategoryTitleImageCellModel.m
0 → 100755
View file @
a4f39813
//
// JXCategoryTitleImageCellModel.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/8.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryTitleImageCellModel.h"
@implementation
JXCategoryTitleImageCellModel
@end
GMBase/Classes/JXPagerView/JXCategoryView/Title/TitleImage/JXCategoryTitleImageView.h
0 → 100755
View file @
a4f39813
//
// JXCategoryImageView.h
// JXCategoryView
//
// Created by jiaxin on 2018/8/8.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryTitleView.h"
#import "JXCategoryTitleImageCell.h"
#import "JXCategoryTitleImageCellModel.h"
@interface
JXCategoryTitleImageView
:
JXCategoryTitleView
@property
(
nonatomic
,
strong
)
NSArray
<
NSString
*>*
imageNames
;
@property
(
nonatomic
,
strong
)
NSArray
<
NSURL
*>*
imageURLs
;
@property
(
nonatomic
,
strong
)
NSArray
<
NSString
*>*
selectedImageNames
;
@property
(
nonatomic
,
strong
)
NSArray
<
NSURL
*>*
selectedImageURLs
;
@property
(
nonatomic
,
strong
)
NSArray
<
NSNumber
*>
*
imageTypes
;
//默认JXCategoryTitleImageType_LeftImage
@property
(
nonatomic
,
copy
)
void
(
^
loadImageCallback
)(
UIImageView
*
imageView
,
NSURL
*
imageURL
);
//使用imageURL从远端下载图片进行加载,建议使用SDWebImage等第三方库进行下载。
@property
(
nonatomic
,
assign
)
CGSize
imageSize
;
//默认CGSizeMake(20, 20)
@property
(
nonatomic
,
assign
)
CGFloat
titleImageSpacing
;
//titleLabel和ImageView的间距,默认5
@property
(
nonatomic
,
assign
)
BOOL
imageZoomEnabled
;
//默认为NO
@property
(
nonatomic
,
assign
)
CGFloat
imageZoomScale
;
//默认1.2,imageZoomEnabled为YES才生效
@end
GMBase/Classes/JXPagerView/JXCategoryView/Title/TitleImage/JXCategoryTitleImageView.m
0 → 100755
View file @
a4f39813
//
// JXCategoryImageView.m
// JXCategoryView
//
// Created by jiaxin on 2018/8/8.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXCategoryTitleImageView.h"
#import "JXCategoryTitleImageCell.h"
#import "JXCategoryTitleImageCellModel.h"
#import "JXCategoryFactory.h"
@implementation
JXCategoryTitleImageView
-
(
void
)
dealloc
{
self
.
loadImageCallback
=
nil
;
}
-
(
void
)
initializeData
{
[
super
initializeData
];
_imageSize
=
CGSizeMake
(
20
,
20
);
_titleImageSpacing
=
5
;
_imageZoomEnabled
=
NO
;
_imageZoomScale
=
1
.
2
;
}
-
(
Class
)
preferredCellClass
{
return
[
JXCategoryTitleImageCell
class
];
}
-
(
void
)
refreshDataSource
{
NSMutableArray
*
tempArray
=
[
NSMutableArray
array
];
for
(
int
i
=
0
;
i
<
self
.
titles
.
count
;
i
++
)
{
JXCategoryTitleImageCellModel
*
cellModel
=
[[
JXCategoryTitleImageCellModel
alloc
]
init
];
[
tempArray
addObject
:
cellModel
];
}
if
(
self
.
imageTypes
==
nil
||
self
.
imageTypes
.
count
==
0
)
{
NSMutableArray
*
types
=
[
NSMutableArray
array
];
for
(
int
i
=
0
;
i
<
self
.
titles
.
count
;
i
++
)
{
[
types
addObject
:
@
(
JXCategoryTitleImageType_LeftImage
)];
}
self
.
imageTypes
=
types
;
}
self
.
dataSource
=
tempArray
;
}
-
(
void
)
refreshCellModel
:
(
JXCategoryBaseCellModel
*
)
cellModel
index
:
(
NSInteger
)
index
{
[
super
refreshCellModel
:
cellModel
index
:
index
];
JXCategoryTitleImageCellModel
*
myCellModel
=
(
JXCategoryTitleImageCellModel
*
)
cellModel
;
myCellModel
.
loadImageCallback
=
self
.
loadImageCallback
;
myCellModel
.
imageType
=
[
self
.
imageTypes
[
index
]
integerValue
];
myCellModel
.
imageSize
=
self
.
imageSize
;
myCellModel
.
titleImageSpacing
=
self
.
titleImageSpacing
;
if
(
self
.
imageNames
!=
nil
)
{
myCellModel
.
imageName
=
self
.
imageNames
[
index
];
}
else
if
(
self
.
imageURLs
!=
nil
)
{
myCellModel
.
imageURL
=
self
.
imageURLs
[
index
];
}
if
(
self
.
selectedImageNames
!=
nil
)
{
myCellModel
.
selectedImageName
=
self
.
selectedImageNames
[
index
];
}
else
if
(
self
.
selectedImageURLs
!=
nil
)
{
myCellModel
.
selectedImageURL
=
self
.
selectedImageURLs
[
index
];
}
myCellModel
.
imageZoomEnabled
=
self
.
imageZoomEnabled
;
myCellModel
.
imageZoomScale
=
1
.
0
;
if
(
index
==
self
.
selectedIndex
)
{
myCellModel
.
imageZoomScale
=
self
.
imageZoomScale
;
}
}
-
(
void
)
refreshSelectedCellModel
:
(
JXCategoryBaseCellModel
*
)
selectedCellModel
unselectedCellModel
:
(
JXCategoryBaseCellModel
*
)
unselectedCellModel
{
[
super
refreshSelectedCellModel
:
selectedCellModel
unselectedCellModel
:
unselectedCellModel
];
JXCategoryTitleImageCellModel
*
myUnselectedCellModel
=
(
JXCategoryTitleImageCellModel
*
)
unselectedCellModel
;
myUnselectedCellModel
.
imageZoomScale
=
1
.
0
;
JXCategoryTitleImageCellModel
*
myselectedCellModel
=
(
JXCategoryTitleImageCellModel
*
)
selectedCellModel
;
myselectedCellModel
.
imageZoomScale
=
self
.
imageZoomScale
;
}
-
(
void
)
refreshLeftCellModel
:
(
JXCategoryBaseCellModel
*
)
leftCellModel
rightCellModel
:
(
JXCategoryBaseCellModel
*
)
rightCellModel
ratio
:
(
CGFloat
)
ratio
{
[
super
refreshLeftCellModel
:
leftCellModel
rightCellModel
:
rightCellModel
ratio
:
ratio
];
JXCategoryTitleImageCellModel
*
leftModel
=
(
JXCategoryTitleImageCellModel
*
)
leftCellModel
;
JXCategoryTitleImageCellModel
*
rightModel
=
(
JXCategoryTitleImageCellModel
*
)
rightCellModel
;
if
(
self
.
imageZoomEnabled
)
{
leftModel
.
imageZoomScale
=
[
JXCategoryFactory
interpolationFrom
:
self
.
imageZoomScale
to
:
1
.
0
percent
:
ratio
];
rightModel
.
imageZoomScale
=
[
JXCategoryFactory
interpolationFrom
:
1
.
0
to
:
self
.
imageZoomScale
percent
:
ratio
];
}
}
-
(
CGFloat
)
preferredCellWidthAtIndex
:
(
NSInteger
)
index
{
CGFloat
titleWidth
=
[
super
preferredCellWidthAtIndex
:
index
];
JXCategoryTitleImageType
type
=
[
self
.
imageTypes
[
index
]
integerValue
];
CGFloat
cellWidth
=
0
;
switch
(
type
)
{
case
JXCategoryTitleImageType_OnlyTitle
:
cellWidth
=
titleWidth
;
break
;
case
JXCategoryTitleImageType_OnlyImage
:
cellWidth
=
self
.
imageSize
.
width
;
break
;
case
JXCategoryTitleImageType_LeftImage
:
case
JXCategoryTitleImageType_RightImage
:
cellWidth
=
titleWidth
+
self
.
titleImageSpacing
+
self
.
imageSize
.
width
;
break
;
case
JXCategoryTitleImageType_TopImage
:
case
JXCategoryTitleImageType_BottomImage
:
cellWidth
=
MAX
(
titleWidth
,
self
.
imageSize
.
width
);
break
;
}
return
cellWidth
;
}
@end
GMBase/Classes/JXPagerView/JXPagerCollectionViewCell.h
0 → 100644
View file @
a4f39813
//
// JXPagerCollectionViewCell.h
// Gengmei
//
// Created by 卢悦明 on 2019/5/15.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface
JXPagerCollectionViewCell
:
UICollectionViewCell
@property
(
nonatomic
,
strong
)
UIView
*
backView
;
@end
NS_ASSUME_NONNULL_END
GMBase/Classes/JXPagerView/JXPagerCollectionViewCell.m
0 → 100644
View file @
a4f39813
//
// JXPagerCollectionViewCell.m
// Gengmei
//
// Created by 卢悦明 on 2019/5/15.
// Copyright © 2019 更美互动信息科技有限公司. All rights reserved.
//
#import "JXPagerCollectionViewCell.h"
@implementation
JXPagerCollectionViewCell
-
(
void
)
setBackView
:(
UIView
*
)
backView
{
if
(
backView
!=
_backView
)
{
[
_backView
removeFromSuperview
];
_backView
=
backView
;
[
self
addSubview
:
_backView
];
}
}
-
(
void
)
layoutSubviews
{
self
.
backView
.
frame
=
self
.
bounds
;
}
@end
GMBase/Classes/JXPagerView/JXPagerListContainerView.h
0 → 100755
View file @
a4f39813
//
// JXPagingListContainerView.h
// JXPagingView
//
// Created by jiaxin on 2018/8/27.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
@class
JXPagerMainTableView
;
@class
JXPagerListContainerView
;
@class
JXPagerListContainerCollectionView
;
@protocol
JXPagerListContainerCollectionViewGestureDelegate
<
NSObject
>
-
(
BOOL
)
pagerListContainerCollectionViewGestureRecognizerShouldBegin
:
(
JXPagerListContainerCollectionView
*
)
collectionView
gestureRecognizer
:
(
UIGestureRecognizer
*
)
gestureRecognizer
;
@end
@interface
JXPagerListContainerCollectionView
:
UICollectionView
<
UIGestureRecognizerDelegate
>
@property
(
nonatomic
,
assign
)
BOOL
isNestEnabled
;
@property
(
nonatomic
,
weak
)
id
<
JXPagerListContainerCollectionViewGestureDelegate
>
gestureDelegate
;
@end
@protocol
JXPagerListContainerViewDelegate
<
NSObject
>
-
(
NSInteger
)
numberOfRowsInListContainerView
:
(
JXPagerListContainerView
*
)
listContainerView
;
-
(
UIView
*
)
listContainerView
:(
JXPagerListContainerView
*
)
listContainerView
listViewInRow
:(
NSInteger
)
row
;
-
(
void
)
listContainerView
:(
JXPagerListContainerView
*
)
listContainerView
willDisplayCellAtRow
:(
NSInteger
)
row
;
-
(
void
)
listContainerView
:(
JXPagerListContainerView
*
)
listContainerView
didScroll
:(
NSInteger
)
row
;
@end
@interface
JXPagerListContainerView
:
UIView
@property
(
nonatomic
,
strong
,
readonly
)
JXPagerListContainerCollectionView
*
collectionView
;
@property
(
nonatomic
,
weak
)
id
<
JXPagerListContainerViewDelegate
>
delegate
;
@property
(
nonatomic
,
weak
)
JXPagerMainTableView
*
mainTableView
;
-
(
instancetype
)
initWithDelegate
:(
id
<
JXPagerListContainerViewDelegate
>
)
delegate
NS_DESIGNATED_INITIALIZER
;
-
(
instancetype
)
init
NS_UNAVAILABLE
;
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
NS_UNAVAILABLE
;
-
(
instancetype
)
initWithCoder
:(
NSCoder
*
)
aDecoder
NS_UNAVAILABLE
;
-
(
void
)
reloadData
;
@end
GMBase/Classes/JXPagerView/JXPagerListContainerView.m
0 → 100755
View file @
a4f39813
//
// JXPagerListContainerView.m
// JXPagerView
//
// Created by jiaxin on 2018/8/27.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXPagerListContainerView.h"
#import "JXPagerMainTableView.h"
@import
GMKit
;
@interface
JXPagerListContainerView
()
<
UICollectionViewDataSource
,
UICollectionViewDelegate
,
UICollectionViewDelegateFlowLayout
>
@property
(
nonatomic
,
strong
)
JXPagerListContainerCollectionView
*
collectionView
;
@property
(
nonatomic
,
strong
)
UICollectionViewFlowLayout
*
layout
;
@end
@implementation
JXPagerListContainerView
-
(
instancetype
)
initWithDelegate
:(
id
<
JXPagerListContainerViewDelegate
>
)
delegate
{
self
=
[
super
initWithFrame
:
CGRectZero
];
if
(
self
)
{
_delegate
=
delegate
;
[
self
initializeViews
];
}
return
self
;
}
-
(
void
)
initializeViews
{
UICollectionViewFlowLayout
*
layout
=
[[
UICollectionViewFlowLayout
alloc
]
init
];
layout
.
minimumLineSpacing
=
0
;
layout
.
minimumInteritemSpacing
=
0
;
layout
.
scrollDirection
=
UICollectionViewScrollDirectionHorizontal
;
self
.
layout
=
layout
;
_collectionView
=
[[
JXPagerListContainerCollectionView
alloc
]
initWithFrame
:
CGRectZero
collectionViewLayout
:
self
.
layout
];
self
.
collectionView
.
showsHorizontalScrollIndicator
=
NO
;
self
.
collectionView
.
showsVerticalScrollIndicator
=
NO
;
self
.
collectionView
.
pagingEnabled
=
YES
;
self
.
collectionView
.
scrollsToTop
=
NO
;
self
.
collectionView
.
bounces
=
NO
;
self
.
collectionView
.
delegate
=
self
;
self
.
collectionView
.
dataSource
=
self
;
[
self
.
collectionView
registerClass
:[
UICollectionViewCell
class
]
forCellWithReuseIdentifier
:
@"cell"
];
if
(
@available
(
iOS
10
.
0
,
*
))
{
self
.
collectionView
.
prefetchingEnabled
=
NO
;
}
if
(
@available
(
iOS
11
.
0
,
*
))
{
self
.
collectionView
.
contentInsetAdjustmentBehavior
=
UIScrollViewContentInsetAdjustmentNever
;
}
[
self
addSubview
:
self
.
collectionView
];
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
self
.
collectionView
.
frame
=
self
.
bounds
;
self
.
layout
.
itemSize
=
self
.
bounds
.
size
;
}
-
(
void
)
reloadData
{
[
self
.
collectionView
reloadData
];
}
#pragma mark - UICollectionViewDataSource, UICollectionViewDelegate
-
(
NSInteger
)
collectionView
:
(
UICollectionView
*
)
collectionView
numberOfItemsInSection
:
(
NSInteger
)
section
{
return
[
self
.
delegate
numberOfRowsInListContainerView
:
self
];
}
-
(
UICollectionViewCell
*
)
collectionView
:
(
UICollectionView
*
)
collectionView
cellForItemAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
UICollectionViewCell
*
cell
=
[
collectionView
dequeueReusableCellWithReuseIdentifier
:
@"cell"
forIndexPath
:
indexPath
];
for
(
UIView
*
view
in
cell
.
contentView
.
subviews
)
{
[
view
removeFromSuperview
];
}
UIView
*
listView
=
[
self
.
delegate
listContainerView
:
self
listViewInRow
:
indexPath
.
item
];
listView
.
frame
=
cell
.
contentView
.
bounds
;
[
cell
.
contentView
addSubview
:
listView
];
return
cell
;
}
-
(
void
)
collectionView
:
(
UICollectionView
*
)
collectionView
willDisplayCell
:
(
UICollectionViewCell
*
)
cell
forItemAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
[
self
.
delegate
listContainerView
:
self
willDisplayCellAtRow
:
indexPath
.
item
];
}
-
(
BOOL
)
collectionView
:
(
UICollectionView
*
)
collectionView
shouldHighlightItemAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
return
false
;
}
-
(
void
)
scrollViewDidEndDecelerating
:
(
UIScrollView
*
)
scrollView
{
self
.
mainTableView
.
scrollEnabled
=
YES
;
if
([
self
.
delegate
respondsToSelector
:
@selector
(
listContainerView
:
didScroll
:
)])
{
NSInteger
index
=
(
self
.
collectionView
.
contentOffset
.
x
/
MAINSCREEN_WIDTH
+
0
.
5
);
[
self
.
delegate
listContainerView
:
self
didScroll
:
index
];
}
}
-
(
void
)
scrollViewDidEndDragging
:
(
UIScrollView
*
)
scrollView
willDecelerate
:
(
BOOL
)
decelerate
{
if
([
self
.
delegate
respondsToSelector
:
@selector
(
listContainerView
:
didScroll
:
)])
{
NSInteger
index
=
(
self
.
collectionView
.
contentOffset
.
x
/
MAINSCREEN_WIDTH
+
0
.
5
);
[
self
.
delegate
listContainerView
:
self
didScroll
:
index
];
}
self
.
mainTableView
.
scrollEnabled
=
YES
;
}
-
(
void
)
scrollViewDidEndScrollingAnimation
:
(
UIScrollView
*
)
scrollView
{
self
.
mainTableView
.
scrollEnabled
=
YES
;
}
-
(
void
)
scrollViewDidScroll
:
(
UIScrollView
*
)
scrollView
{
if
(
scrollView
.
isTracking
||
scrollView
.
isDecelerating
)
{
self
.
mainTableView
.
scrollEnabled
=
NO
;
}
}
@end
@interface
JXPagerListContainerCollectionView
()
@end
@implementation
JXPagerListContainerCollectionView
-
(
BOOL
)
gestureRecognizerShouldBegin
:(
UIGestureRecognizer
*
)
gestureRecognizer
{
if
(
self
.
gestureDelegate
)
{
return
[
self
.
gestureDelegate
pagerListContainerCollectionViewGestureRecognizerShouldBegin
:
self
gestureRecognizer
:
gestureRecognizer
];
}
else
{
if
(
self
.
isNestEnabled
)
{
if
([
gestureRecognizer
isMemberOfClass
:
NSClassFromString
(
@"UIScrollViewPanGestureRecognizer"
)])
{
CGFloat
velocityX
=
[(
UIPanGestureRecognizer
*
)
gestureRecognizer
velocityInView
:
gestureRecognizer
.
view
].
x
;
//x大于0就是往右滑
if
(
velocityX
>
0
)
{
if
(
self
.
contentOffset
.
x
==
0
)
{
return
NO
;
}
}
else
if
(
velocityX
<
0
)
{
//x小于0就是往左滑
if
(
self
.
contentOffset
.
x
+
self
.
bounds
.
size
.
width
==
self
.
contentSize
.
width
)
{
return
NO
;
}
}
}
}
}
return
YES
;
}
@end
GMBase/Classes/JXPagerView/JXPagerListRefreshView.h
0 → 100755
View file @
a4f39813
//
// JXPagingListRefreshView.h
// JXPagingView
//
// Created by jiaxin on 2018/8/28.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "JXPagerView.h"
@interface
JXPagerListRefreshView
:
JXPagerView
@end
GMBase/Classes/JXPagerView/JXPagerListRefreshView.m
0 → 100755
View file @
a4f39813
//
// JXPagerListRefreshView.m
// JXPagerView
//
// Created by jiaxin on 2018/8/28.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXPagerListRefreshView.h"
@interface
JXPagerListRefreshView
()
@property
(
nonatomic
,
assign
)
CGFloat
lastScrollingListViewContentOffsetY
;
@end
@implementation
JXPagerListRefreshView
-
(
void
)
initializeViews
{
[
super
initializeViews
];
self
.
mainTableView
.
bounces
=
NO
;
}
-
(
void
)
preferredProcessListViewDidScroll
:
(
UIScrollView
*
)
scrollView
{
BOOL
shouldProcess
=
YES
;
if
(
self
.
currentScrollingListView
.
contentOffset
.
y
>
self
.
lastScrollingListViewContentOffsetY
)
{
//往上滚动
}
else
{
//往下滚动
if
(
self
.
mainTableView
.
contentOffset
.
y
==
0
)
{
shouldProcess
=
NO
;
}
else
{
if
(
self
.
mainTableView
.
contentOffset
.
y
<
[
self
.
delegate
tableHeaderViewHeightInPagerView
:
self
])
{
//mainTableView的header还没有消失,让listScrollView一直为0
if
(
self
.
currentList
&&
[
self
.
currentList
respondsToSelector
:
@selector
(
listScrollViewWillResetContentOffset
)])
{
[
self
.
currentList
listScrollViewWillResetContentOffset
];
}
self
.
currentScrollingListView
.
contentOffset
=
CGPointZero
;
self
.
currentScrollingListView
.
showsVerticalScrollIndicator
=
false
;
}
}
}
if
(
shouldProcess
)
{
if
(
self
.
mainTableView
.
contentOffset
.
y
<
[
self
.
delegate
tableHeaderViewHeightInPagerView
:
self
])
{
//处于下拉刷新的状态,scrollView.contentOffset.y为负数,就重置为0
if
(
self
.
currentScrollingListView
.
contentOffset
.
y
>
0
)
{
//mainTableView的header还没有消失,让listScrollView一直为0
if
(
self
.
currentList
&&
[
self
.
currentList
respondsToSelector
:
@selector
(
listScrollViewWillResetContentOffset
)])
{
[
self
.
currentList
listScrollViewWillResetContentOffset
];
}
self
.
currentScrollingListView
.
contentOffset
=
CGPointZero
;
self
.
currentScrollingListView
.
showsVerticalScrollIndicator
=
false
;
}
}
else
{
//mainTableView的header刚好消失,固定mainTableView的位置,显示listScrollView的滚动条
self
.
mainTableView
.
contentOffset
=
CGPointMake
(
0
,
[
self
.
delegate
tableHeaderViewHeightInPagerView
:
self
]);
self
.
currentScrollingListView
.
showsVerticalScrollIndicator
=
true
;
}
}
self
.
lastScrollingListViewContentOffsetY
=
self
.
currentScrollingListView
.
contentOffset
.
y
;
}
-
(
void
)
preferredProcessMainTableViewDidScroll
:
(
UIScrollView
*
)
scrollView
{
if
(
self
.
currentScrollingListView
!=
nil
&&
self
.
currentScrollingListView
.
contentOffset
.
y
>
0
)
{
//mainTableView的header已经滚动不见,开始滚动某一个listView,那么固定mainTableView的contentOffset,让其不动
self
.
mainTableView
.
contentOffset
=
CGPointMake
(
0
,
[
self
.
delegate
tableHeaderViewHeightInPagerView
:
self
]);
}
if
(
scrollView
.
contentOffset
.
y
<
[
self
.
delegate
tableHeaderViewHeightInPagerView
:
self
])
{
//mainTableView已经显示了header,listView的contentOffset需要重置
for
(
id
<
JXPagerViewListViewDelegate
>
list
in
self
.
validListDict
.
allValues
)
{
//正在下拉刷新时,不需要重置
UIScrollView
*
listScrollView
=
[
list
listScrollView
];
if
(
listScrollView
.
contentOffset
.
y
>
0
)
{
if
([
list
respondsToSelector
:
@selector
(
listScrollViewWillResetContentOffset
)])
{
[
list
listScrollViewWillResetContentOffset
];
}
listScrollView
.
contentOffset
=
CGPointZero
;
}
}
}
}
@end
GMBase/Classes/JXPagerView/JXPagerMainTableView.h
0 → 100755
View file @
a4f39813
//
// JXPagingMainTableView.h
// JXPagingView
//
// Created by jiaxin on 2018/8/27.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
@protocol
JXPagerMainTableViewGestureDelegate
<
NSObject
>
-
(
BOOL
)
mainTableViewGestureRecognizer
:
(
UIGestureRecognizer
*
)
gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer
:
(
UIGestureRecognizer
*
)
otherGestureRecognizer
;
@end
@interface
JXPagerMainTableView
:
UITableView
@property
(
nonatomic
,
weak
)
id
<
JXPagerMainTableViewGestureDelegate
>
gestureDelegate
;
@end
GMBase/Classes/JXPagerView/JXPagerMainTableView.m
0 → 100755
View file @
a4f39813
//
// JXPagerMainTableView.m
// JXPagerView
//
// Created by jiaxin on 2018/8/27.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXPagerMainTableView.h"
@interface
JXPagerMainTableView
()
<
UIGestureRecognizerDelegate
>
@end
@implementation
JXPagerMainTableView
-
(
BOOL
)
gestureRecognizer
:(
UIGestureRecognizer
*
)
gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer
:(
UIGestureRecognizer
*
)
otherGestureRecognizer
{
if
(
self
.
gestureDelegate
&&
[
self
.
gestureDelegate
respondsToSelector
:
@selector
(
mainTableViewGestureRecognizer
:
shouldRecognizeSimultaneouslyWithGestureRecognizer
:
)])
{
return
[
self
.
gestureDelegate
mainTableViewGestureRecognizer
:
gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer
:
otherGestureRecognizer
];
}
else
{
return
[
gestureRecognizer
isKindOfClass
:[
UIPanGestureRecognizer
class
]]
&&
[
otherGestureRecognizer
isKindOfClass
:[
UIPanGestureRecognizer
class
]];
}
}
@end
GMBase/Classes/JXPagerView/JXPagerView.h
0 → 100755
View file @
a4f39813
//
// JXPagerView.h
// JXPagerView
//
// Created by jiaxin on 2018/8/27.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "JXPagerMainTableView.h"
#import "JXPagerListContainerView.h"
@class
JXPagerView
;
/**
该协议主要用于mainTableView已经显示了header,listView的contentOffset需要重置时,内部需要访问到外部传入进来的listView内的scrollView
*/
@protocol
JXPagerViewListViewDelegate
<
NSObject
>
/**
返回listView。如果是vc包裹的就是vc.view;如果是自定义view包裹的,就是自定义view自己。
@return UIView
*/
-
(
UIView
*
)
listView
;
/**
返回listView内部持有的UIScrollView或UITableView或UICollectionView
主要用于mainTableView已经显示了header,listView的contentOffset需要重置时,内部需要访问到外部传入进来的listView内的scrollView
@return listView内部持有的UIScrollView或UITableView或UICollectionView
*/
-
(
UIScrollView
*
)
listScrollView
;
/**
当listView内部持有的UIScrollView或UITableView或UICollectionView的代理方法`scrollViewDidScroll`回调时,需要调用该代理方法传入的callback
@param callback `scrollViewDidScroll`回调时调用的callback
*/
-
(
void
)
listViewDidScrollCallback
:(
void
(
^
)(
UIScrollView
*
scrollView
))
callback
;
@optional
/**
将要重置listScrollView的contentOffset
*/
-
(
void
)
listScrollViewWillResetContentOffset
;
@end
@protocol
JXPagerViewDelegate
<
NSObject
>
/**
返回tableHeaderView的高度,因为内部需要比对判断,只能是整型数
@param pagerView pagerView description
@return return tableHeaderView的高度
*/
-
(
NSUInteger
)
tableHeaderViewHeightInPagerView
:
(
JXPagerView
*
)
pagerView
;
/**
返回tableHeaderView
@param pagerView pagerView description
@return tableHeaderView
*/
-
(
UIView
*
)
tableHeaderViewInPagerView
:(
JXPagerView
*
)
pagerView
;
/**
返回悬浮HeaderView的高度,因为内部需要比对判断,只能是整型数
@param pagerView pagerView description
@return 悬浮HeaderView的高度
*/
-
(
NSUInteger
)
heightForPinSectionHeaderInPagerView
:(
JXPagerView
*
)
pagerView
;
/**
返回悬浮HeaderView。我用的是自己封装的JXCategoryView(Github:https://github.com/pujiaxin33/JXCategoryView),你也可以选择其他的三方库或者自己写
@param pagerView pagerView description
@return 悬浮HeaderView
*/
-
(
UIView
*
)
viewForPinSectionHeaderInPagerView
:(
JXPagerView
*
)
pagerView
;
/**
返回列表的数量
@param pagerView pagerView description
@return 列表的数量
*/
-
(
NSInteger
)
numberOfListsInPagerView
:(
JXPagerView
*
)
pagerView
;
/**
根据index初始化一个对应列表实例。注意:一定要是新生成的实例!!!
只要遵循JXPagerViewListViewDelegate即可,无论你返回的是UIView还是UIViewController都可以。
@param pagerView pagerView description
@param index index description
@return 新生成的列表实例
*/
-
(
id
<
JXPagerViewListViewDelegate
>
)
pagerView
:(
JXPagerView
*
)
pagerView
initListAtIndex
:(
NSInteger
)
index
;
-
(
void
)
pagerView
:(
JXPagerView
*
)
pagerView
didScroll
:(
NSInteger
)
row
;
@optional
/**
返回tableHeaderView 距离pagerView顶部的距离 默认为 0
*/
-
(
CGFloat
)
tableViewSectionHeaderViewContentYInPagerView
:
(
JXPagerView
*
)
pagerView
;
/**
mainTableView的滚动回调,用于实现头图跟随缩放
@param scrollView mainTableView
*/
-
(
void
)
mainTableViewDidScroll
:(
UIScrollView
*
)
scrollView
;
-
(
void
)
mainTableViewDidEndDecelerating
:(
UIScrollView
*
)
scrollView
;
-
(
void
)
mainTableViewDidEndDragging
:(
UIScrollView
*
)
scrollView
willDecelerate
:(
BOOL
)
decelerate
;
-
(
void
)
mainTableViewWillBeginDragging
:(
UIScrollView
*
)
scrollView
;
/**
@param 由于 mainTableViewDidScroll 滚动偏移量返回的最大值为headerView的高度, 这个偏移量加上子ScrollView的偏移量。
*/
-
(
void
)
listAndMainScrollViewDidScroll
:(
CGFloat
)
contentOffsetY
;
@end
@interface
JXPagerView
:
UIView
@property
(
nonatomic
,
weak
)
id
<
JXPagerViewDelegate
>
delegate
;
@property
(
nonatomic
,
strong
)
JXPagerMainTableView
*
mainTableView
;
@property
(
nonatomic
,
strong
,
readonly
)
JXPagerListContainerView
*
listContainerView
;
-
(
instancetype
)
initWithDelegate
:(
id
<
JXPagerViewDelegate
>
)
delegate
NS_DESIGNATED_INITIALIZER
;
@property
(
nonatomic
,
assign
)
BOOL
isListHorizontalScrollEnabled
;
//是否允许列表左右滑动。默认:YES
@property
(
nonatomic
,
assign
,
readonly
)
CGFloat
mainViewScrollOffsetY
;
@property
(
nonatomic
,
assign
,
readonly
)
BOOL
isListScroll
;
-
(
instancetype
)
init
NS_UNAVAILABLE
;
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
NS_UNAVAILABLE
;
-
(
instancetype
)
initWithCoder
:(
NSCoder
*
)
aDecoder
NS_UNAVAILABLE
;
-
(
void
)
initializeViews
NS_REQUIRES_SUPER
;
-
(
void
)
reloadData
;
-
(
void
)
refreshTableHeaderView
;
#pragma mark - Subclass
@property
(
nonatomic
,
strong
,
readonly
)
UIScrollView
*
currentScrollingListView
;
//暴露给子类使用,请勿直接使用该属性!
@property
(
nonatomic
,
weak
,
readonly
)
id
<
JXPagerViewListViewDelegate
>
currentList
;
//暴露给子类使用,请勿直接使用该属性!
@property
(
nonatomic
,
strong
,
readonly
)
NSDictionary
<
NSNumber
*
,
id
<
JXPagerViewListViewDelegate
>>
*
validListDict
;
//暴露给子类使用,请勿直接使用该属性!当前已经加载过可用的列表字典,key就是index值,value是对应的列表。
-
(
void
)
preferredProcessListViewDidScroll
:(
UIScrollView
*
)
scrollView
;
-
(
void
)
preferredProcessMainTableViewDidScroll
:(
UIScrollView
*
)
scrollView
;
@end
GMBase/Classes/JXPagerView/JXPagerView.m
0 → 100755
View file @
a4f39813
//
// JXPagerView.m
// JXPagerView
//
// Created by jiaxin on 2018/8/27.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXPagerView.h"
@import
GMRefresh
;
@interface
JXPagerView
()
<
UITableViewDataSource
,
UITableViewDelegate
,
JXPagerListContainerViewDelegate
>
//@property (nonatomic, strong) JXPagerMainTableView *mainTableView;
@property
(
nonatomic
,
strong
)
JXPagerListContainerView
*
listContainerView
;
@property
(
nonatomic
,
strong
)
UIScrollView
*
currentScrollingListView
;
@property
(
nonatomic
,
weak
)
id
<
JXPagerViewListViewDelegate
>
currentList
;
@property
(
nonatomic
,
strong
)
NSMutableDictionary
<
NSNumber
*
,
id
<
JXPagerViewListViewDelegate
>>
*
validListDict
;
@property
(
nonatomic
,
assign
)
CGFloat
mainViewScrollOffsetY
;
@property
(
nonatomic
,
assign
)
BOOL
isListScroll
;
@end
@implementation
JXPagerView
-
(
instancetype
)
initWithDelegate
:(
id
<
JXPagerViewDelegate
>
)
delegate
{
self
=
[
super
initWithFrame
:
CGRectZero
];
if
(
self
)
{
_delegate
=
delegate
;
_validListDict
=
[
NSMutableDictionary
dictionary
];
[
self
initializeViews
];
}
return
self
;
}
-
(
void
)
initializeViews
{
_mainTableView
=
[[
JXPagerMainTableView
alloc
]
initWithFrame
:
CGRectZero
style
:
UITableViewStylePlain
];
self
.
mainTableView
.
showsVerticalScrollIndicator
=
NO
;
self
.
mainTableView
.
showsHorizontalScrollIndicator
=
NO
;
self
.
mainTableView
.
separatorStyle
=
UITableViewCellSeparatorStyleNone
;
self
.
mainTableView
.
scrollsToTop
=
NO
;
self
.
mainTableView
.
dataSource
=
self
;
self
.
mainTableView
.
delegate
=
self
;
[
self
refreshTableHeaderView
];
[
self
.
mainTableView
registerClass
:[
UITableViewCell
class
]
forCellReuseIdentifier
:
@"cell"
];
if
(
@available
(
iOS
11
.
0
,
*
))
{
self
.
mainTableView
.
contentInsetAdjustmentBehavior
=
UIScrollViewContentInsetAdjustmentNever
;
}
[
self
addSubview
:
self
.
mainTableView
];
_listContainerView
=
[[
JXPagerListContainerView
alloc
]
initWithDelegate
:
self
];
self
.
listContainerView
.
mainTableView
=
self
.
mainTableView
;
self
.
isListHorizontalScrollEnabled
=
YES
;
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
self
.
mainTableView
.
frame
=
self
.
bounds
;
}
-
(
void
)
setIsListHorizontalScrollEnabled
:
(
BOOL
)
isListHorizontalScrollEnabled
{
_isListHorizontalScrollEnabled
=
isListHorizontalScrollEnabled
;
self
.
listContainerView
.
collectionView
.
scrollEnabled
=
isListHorizontalScrollEnabled
;
}
-
(
void
)
reloadData
{
self
.
currentList
=
nil
;
self
.
currentScrollingListView
=
nil
;
for
(
id
<
JXPagerViewListViewDelegate
>
list
in
self
.
validListDict
.
allValues
)
{
[
list
.
listView
removeFromSuperview
];
}
[
_validListDict
removeAllObjects
];
[
self
refreshTableHeaderView
];
[
self
.
mainTableView
reloadData
];
[
self
.
listContainerView
reloadData
];
}
-
(
void
)
refreshTableHeaderView
{
UIView
*
tableHeaderView
=
[
self
.
delegate
tableHeaderViewInPagerView
:
self
];
// UIView *containerView = [[UIView alloc] initWithFrame:tableHeaderView.bounds];
// [containerView addSubview:tableHeaderView];
self
.
mainTableView
.
tableHeaderView
=
tableHeaderView
;
}
-
(
void
)
preferredProcessListViewDidScroll
:
(
UIScrollView
*
)
scrollView
{
CGFloat
listScrollOffsetY
=
scrollView
.
contentOffset
.
y
;
if
([
self
.
delegate
respondsToSelector
:
@selector
(
listAndMainScrollViewDidScroll
:)])
{
[
self
.
delegate
listAndMainScrollViewDidScroll
:(
listScrollOffsetY
+
self
.
mainViewScrollOffsetY
)];
}
if
(
self
.
mainTableView
.
contentOffset
.
y
<
[
self
.
delegate
tableHeaderViewHeightInPagerView
:
self
])
{
//mainTableView的header还没有消失,让listScrollView一直为0
if
(
self
.
currentList
&&
[
self
.
currentList
respondsToSelector
:
@selector
(
listScrollViewWillResetContentOffset
)])
{
[
self
.
currentList
listScrollViewWillResetContentOffset
];
}
scrollView
.
contentOffset
=
CGPointZero
;
scrollView
.
showsVerticalScrollIndicator
=
NO
;
}
else
{
//mainTableView的header刚好消失,固定mainTableView的位置,显示listScrollView的滚动条
self
.
mainTableView
.
contentOffset
=
CGPointMake
(
0
,
[
self
.
delegate
tableHeaderViewHeightInPagerView
:
self
]);
scrollView
.
showsVerticalScrollIndicator
=
YES
;
}
}
-
(
void
)
preferredProcessMainTableViewDidScroll
:
(
UIScrollView
*
)
scrollView
{
if
(
self
.
currentScrollingListView
!=
nil
&&
self
.
currentScrollingListView
.
contentOffset
.
y
>
0
)
{
//mainTableView的header已经滚动不见,开始滚动某一个listView,那么固定mainTableView的contentOffset,让其不动
self
.
mainTableView
.
contentOffset
=
CGPointMake
(
0
,
[
self
.
delegate
tableHeaderViewHeightInPagerView
:
self
]);
}
if
(
scrollView
.
contentOffset
.
y
<
[
self
.
delegate
tableHeaderViewHeightInPagerView
:
self
])
{
//mainTableView已经显示了header,listView的contentOffset需要重置
for
(
id
<
JXPagerViewListViewDelegate
>
list
in
self
.
validListDict
.
allValues
)
{
if
([
list
respondsToSelector
:
@selector
(
listScrollViewWillResetContentOffset
)])
{
[
list
listScrollViewWillResetContentOffset
];
}
[
list
listScrollView
].
contentOffset
=
CGPointZero
;
}
}
if
(
scrollView
.
contentOffset
.
y
>
[
self
.
delegate
tableHeaderViewHeightInPagerView
:
self
]
&&
self
.
currentScrollingListView
.
contentOffset
.
y
==
0
)
{
//当往上滚动mainTableView的headerView时,滚动到底时,修复listView往上小幅度滚动
self
.
mainTableView
.
contentOffset
=
CGPointMake
(
0
,
[
self
.
delegate
tableHeaderViewHeightInPagerView
:
self
]);
}
}
#pragma mark - Private
-
(
void
)
listViewDidScroll
:
(
UIScrollView
*
)
scrollView
{
self
.
currentScrollingListView
=
scrollView
;
[
self
preferredProcessListViewDidScroll
:
scrollView
];
}
#pragma mark - UITableViewDataSource, UITableViewDelegate
-
(
NSInteger
)
numberOfSectionsInTableView
:
(
UITableView
*
)
tableView
{
return
1
;
}
-
(
NSInteger
)
tableView
:
(
UITableView
*
)
tableView
numberOfRowsInSection
:
(
NSInteger
)
section
{
return
1
;
}
-
(
CGFloat
)
tableView
:
(
UITableView
*
)
tableView
heightForRowAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
return
self
.
bounds
.
size
.
height
-
[
self
.
delegate
heightForPinSectionHeaderInPagerView
:
self
];
}
-
(
UITableViewCell
*
)
tableView
:
(
UITableView
*
)
tableView
cellForRowAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
UITableViewCell
*
cell
=
[
tableView
dequeueReusableCellWithIdentifier
:
@"cell"
forIndexPath
:
indexPath
];
for
(
UIView
*
view
in
cell
.
contentView
.
subviews
)
{
[
view
removeFromSuperview
];
}
self
.
listContainerView
.
frame
=
cell
.
contentView
.
bounds
;
[
cell
.
contentView
addSubview
:
self
.
listContainerView
];
return
cell
;
}
-
(
CGFloat
)
tableView
:
(
UITableView
*
)
tableView
heightForHeaderInSection
:
(
NSInteger
)
section
{
return
[
self
.
delegate
heightForPinSectionHeaderInPagerView
:
self
];
}
-
(
UIView
*
)
tableView
:
(
UITableView
*
)
tableView
viewForHeaderInSection
:
(
NSInteger
)
section
{
return
[
self
.
delegate
viewForPinSectionHeaderInPagerView
:
self
];
}
-
(
CGFloat
)
tableView
:
(
UITableView
*
)
tableView
heightForFooterInSection
:
(
NSInteger
)
section
{
return
1
;
}
-
(
UIView
*
)
tableView
:
(
UITableView
*
)
tableView
viewForFooterInSection
:
(
NSInteger
)
section
{
UIView
*
footer
=
[[
UIView
alloc
]
initWithFrame
:
CGRectZero
];
footer
.
backgroundColor
=
[
UIColor
clearColor
];
return
footer
;
}
-
(
void
)
scrollViewDidScroll
:
(
UIScrollView
*
)
scrollView
{
if
(
self
.
mainTableView
.
mj_header
.
refreshing
)
{
return
;
}
CGFloat
sectionHeaderHeight
=
[
self
.
delegate
heightForPinSectionHeaderInPagerView
:
self
];
CGFloat
sectionHeaderContentY
=
0
;
if
([
self
.
delegate
respondsToSelector
:
@selector
(
tableViewSectionHeaderViewContentYInPagerView
:)])
{
sectionHeaderContentY
=
[
self
.
delegate
tableViewSectionHeaderViewContentYInPagerView
:
self
];
}
CGFloat
ceilPositon
=
[
self
.
delegate
tableHeaderViewHeightInPagerView
:
self
]
-
sectionHeaderHeight
-
sectionHeaderContentY
;
if
(
scrollView
.
contentOffset
.
y
<
sectionHeaderHeight
)
{
scrollView
.
contentInset
=
UIEdgeInsetsMake
(
0
,
0
,
0
,
0
);
}
if
(
scrollView
.
contentOffset
.
y
>=
ceilPositon
&&
scrollView
.
contentOffset
.
y
>=
sectionHeaderHeight
)
{
scrollView
.
contentInset
=
UIEdgeInsetsMake
(
sectionHeaderContentY
,
0
,
0
,
0
);
}
CGFloat
offsetY
=
scrollView
.
contentOffset
.
y
;
self
.
mainViewScrollOffsetY
=
offsetY
;
if
([
self
.
delegate
respondsToSelector
:
@selector
(
mainTableViewDidScroll
:)])
{
[
self
.
delegate
mainTableViewDidScroll
:
scrollView
];
}
if
(
scrollView
.
isTracking
&&
self
.
isListHorizontalScrollEnabled
)
{
self
.
listContainerView
.
collectionView
.
scrollEnabled
=
NO
;
}
[
self
preferredProcessMainTableViewDidScroll
:
scrollView
];
}
-
(
void
)
scrollViewDidEndDecelerating
:
(
UIScrollView
*
)
scrollView
{
if
(
self
.
isListHorizontalScrollEnabled
)
{
self
.
listContainerView
.
collectionView
.
scrollEnabled
=
YES
;
}
if
([
self
.
delegate
respondsToSelector
:
@selector
(
mainTableViewDidEndDecelerating
:)])
{
if
(
_isListScroll
)
{
[
self
.
delegate
mainTableViewDidEndDecelerating
:
self
.
currentScrollingListView
];
}
else
{
[
self
.
delegate
mainTableViewDidEndDecelerating
:
scrollView
];
}
}
}
-
(
void
)
scrollViewDidEndDragging
:
(
UIScrollView
*
)
scrollView
willDecelerate
:
(
BOOL
)
decelerate
{
if
(
self
.
isListHorizontalScrollEnabled
)
{
self
.
listContainerView
.
collectionView
.
scrollEnabled
=
YES
;
}
if
([
self
.
delegate
respondsToSelector
:
@selector
(
mainTableViewDidEndDragging
:
willDecelerate
:
)])
{
if
(
_isListScroll
)
{
[
self
.
delegate
mainTableViewDidEndDragging
:
self
.
currentScrollingListView
willDecelerate
:
decelerate
];
}
else
{
[
self
.
delegate
mainTableViewDidEndDragging
:
scrollView
willDecelerate
:
decelerate
];
}
}
}
-
(
void
)
scrollViewWillBeginDragging
:
(
UIScrollView
*
)
scrollView
{
if
([
self
.
delegate
respondsToSelector
:
@selector
(
mainTableViewWillBeginDragging
:)])
{
if
(
self
.
currentScrollingListView
!=
nil
&&
self
.
currentScrollingListView
.
contentOffset
.
y
>
0
)
{
_isListScroll
=
YES
;
// 为了前后判断滑动的view是否一致
[
self
.
delegate
mainTableViewWillBeginDragging
:
self
.
currentScrollingListView
];
}
else
{
_isListScroll
=
NO
;
[
self
.
delegate
mainTableViewWillBeginDragging
:
scrollView
];
}
}
}
-
(
void
)
scrollViewDidEndScrollingAnimation
:
(
UIScrollView
*
)
scrollView
{
if
(
self
.
isListHorizontalScrollEnabled
)
{
self
.
listContainerView
.
collectionView
.
scrollEnabled
=
YES
;
}
}
#pragma mark - JXPagingListContainerViewDelegate
-
(
NSInteger
)
numberOfRowsInListContainerView
:
(
JXPagerListContainerView
*
)
listContainerView
{
return
[
self
.
delegate
numberOfListsInPagerView
:
self
];
}
-
(
UIView
*
)
listContainerView
:
(
JXPagerListContainerView
*
)
listContainerView
listViewInRow
:
(
NSInteger
)
row
{
id
<
JXPagerViewListViewDelegate
>
list
=
self
.
validListDict
[
@
(
row
)];
if
(
list
==
nil
)
{
list
=
[
self
.
delegate
pagerView
:
self
initListAtIndex
:
row
];
__weak
typeof
(
self
)
weakSelf
=
self
;
__weak
typeof
(
id
<
JXPagerViewListViewDelegate
>
)
weakList
=
list
;
[
list
listViewDidScrollCallback
:
^
(
UIScrollView
*
scrollView
)
{
weakSelf
.
currentList
=
weakList
;
[
weakSelf
listViewDidScroll
:
scrollView
];
}];
_validListDict
[
@
(
row
)]
=
list
;
}
return
[
list
listView
];
}
-
(
void
)
listContainerView
:
(
JXPagerListContainerView
*
)
listContainerView
willDisplayCellAtRow
:
(
NSInteger
)
row
{
self
.
currentScrollingListView
=
[
self
.
validListDict
[
@
(
row
)]
listScrollView
];
}
-
(
void
)
listContainerView
:
(
JXPagerListContainerView
*
)
listContainerView
didScroll
:
(
NSInteger
)
row
{
if
([
self
.
delegate
respondsToSelector
:
@selector
(
pagerView
:
didScroll
:
)])
{
[
self
.
delegate
pagerView
:
self
didScroll
:
row
];
}
}
@end
GMBase/Classes/JXPagerView/PageListView/JXPageListContainerView.h
0 → 100755
View file @
a4f39813
//
// JXPagingListContainerView.h
// JXPagingView
//
// Created by jiaxin on 2018/8/27.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
@class
JXPageListMainTableView
;
@class
JXPageListContainerView
;
@protocol
JXPageListContainerViewDelegate
<
NSObject
>
-
(
NSInteger
)
numberOfRowsInListContainerView
:
(
JXPageListContainerView
*
)
listContainerView
;
-
(
UIView
*
)
listContainerView
:(
JXPageListContainerView
*
)
listContainerView
listViewInRow
:(
NSInteger
)
row
;
-
(
void
)
listContainerView
:(
JXPageListContainerView
*
)
listContainerView
willDisplayCellAtRow
:(
NSInteger
)
row
;
@end
@interface
JXPageListContainerView
:
UIView
@property
(
nonatomic
,
strong
,
readonly
)
UICollectionView
*
collectionView
;
@property
(
nonatomic
,
weak
)
id
<
JXPageListContainerViewDelegate
>
delegate
;
@property
(
nonatomic
,
weak
)
JXPageListMainTableView
*
mainTableView
;
-
(
instancetype
)
initWithDelegate
:(
id
<
JXPageListContainerViewDelegate
>
)
delegate
NS_DESIGNATED_INITIALIZER
;
-
(
instancetype
)
init
NS_UNAVAILABLE
;
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
NS_UNAVAILABLE
;
-
(
instancetype
)
initWithCoder
:(
NSCoder
*
)
aDecoder
NS_UNAVAILABLE
;
-
(
void
)
reloadData
;
@end
GMBase/Classes/JXPagerView/PageListView/JXPageListContainerView.m
0 → 100755
View file @
a4f39813
//
// JXPagerListContainerView.m
//
// Created by jiaxin on 2018/8/27.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXPageListContainerView.h"
#import "JXPageListMainTableView.h"
@interface
JXPageListContainerView
()
<
UICollectionViewDataSource
,
UICollectionViewDelegate
,
UICollectionViewDelegateFlowLayout
>
@property
(
nonatomic
,
strong
)
UICollectionView
*
collectionView
;
@end
@implementation
JXPageListContainerView
-
(
instancetype
)
initWithDelegate
:(
id
<
JXPageListContainerViewDelegate
>
)
delegate
{
self
=
[
super
initWithFrame
:
CGRectZero
];
if
(
self
)
{
_delegate
=
delegate
;
[
self
initializeViews
];
}
return
self
;
}
-
(
void
)
initializeViews
{
UICollectionViewFlowLayout
*
layout
=
[[
UICollectionViewFlowLayout
alloc
]
init
];
layout
.
minimumLineSpacing
=
0
;
layout
.
minimumInteritemSpacing
=
0
;
layout
.
scrollDirection
=
UICollectionViewScrollDirectionHorizontal
;
_collectionView
=
[[
UICollectionView
alloc
]
initWithFrame
:
CGRectZero
collectionViewLayout
:
layout
];
self
.
collectionView
.
showsHorizontalScrollIndicator
=
NO
;
self
.
collectionView
.
showsVerticalScrollIndicator
=
NO
;
self
.
collectionView
.
pagingEnabled
=
YES
;
self
.
collectionView
.
bounces
=
NO
;
self
.
collectionView
.
delegate
=
self
;
self
.
collectionView
.
dataSource
=
self
;
[
self
.
collectionView
registerClass
:[
UICollectionViewCell
class
]
forCellWithReuseIdentifier
:
@"cell"
];
[
self
addSubview
:
self
.
collectionView
];
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
self
.
collectionView
.
frame
=
self
.
bounds
;
}
-
(
void
)
reloadData
{
[
self
.
collectionView
reloadData
];
}
#pragma mark - UICollectionViewDataSource, UICollectionViewDelegate
-
(
NSInteger
)
collectionView
:
(
UICollectionView
*
)
collectionView
numberOfItemsInSection
:
(
NSInteger
)
section
{
return
[
self
.
delegate
numberOfRowsInListContainerView
:
self
];
}
-
(
UICollectionViewCell
*
)
collectionView
:
(
UICollectionView
*
)
collectionView
cellForItemAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
UICollectionViewCell
*
cell
=
[
collectionView
dequeueReusableCellWithReuseIdentifier
:
@"cell"
forIndexPath
:
indexPath
];
for
(
UIView
*
view
in
cell
.
contentView
.
subviews
)
{
[
view
removeFromSuperview
];
}
UIView
*
listView
=
[
self
.
delegate
listContainerView
:
self
listViewInRow
:
indexPath
.
item
];
listView
.
frame
=
cell
.
contentView
.
bounds
;
[
cell
.
contentView
addSubview
:
listView
];
return
cell
;
}
-
(
void
)
collectionView
:
(
UICollectionView
*
)
collectionView
willDisplayCell
:
(
UICollectionViewCell
*
)
cell
forItemAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
[
self
.
delegate
listContainerView
:
self
willDisplayCellAtRow
:
indexPath
.
item
];
}
-
(
void
)
scrollViewDidEndDecelerating
:
(
UIScrollView
*
)
scrollView
{
self
.
mainTableView
.
scrollEnabled
=
YES
;
}
-
(
void
)
scrollViewDidEndDragging
:
(
UIScrollView
*
)
scrollView
willDecelerate
:
(
BOOL
)
decelerate
{
self
.
mainTableView
.
scrollEnabled
=
YES
;
}
-
(
void
)
scrollViewDidEndScrollingAnimation
:
(
UIScrollView
*
)
scrollView
{
self
.
mainTableView
.
scrollEnabled
=
YES
;
}
-
(
void
)
scrollViewDidScroll
:
(
UIScrollView
*
)
scrollView
{
if
(
scrollView
.
isTracking
||
scrollView
.
isDecelerating
)
{
self
.
mainTableView
.
scrollEnabled
=
NO
;
}
}
#pragma mark - UICollectionViewDelegateFlowLayout
-
(
CGSize
)
collectionView
:
(
UICollectionView
*
)
collectionView
layout
:
(
UICollectionViewLayout
*
)
collectionViewLayout
sizeForItemAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
return
self
.
bounds
.
size
;
}
@end
GMBase/Classes/JXPagerView/PageListView/JXPageListMainTableView.h
0 → 100755
View file @
a4f39813
//
// JXPagingMainTableView.h
// JXPagingView
//
// Created by jiaxin on 2018/8/27.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface
JXPageListMainTableView
:
UITableView
@end
GMBase/Classes/JXPagerView/PageListView/JXPageListMainTableView.m
0 → 100755
View file @
a4f39813
//
// JXPagerMainTableView.m
//
// Created by jiaxin on 2018/8/27.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXPageListMainTableView.h"
@interface
JXPageListMainTableView
()
<
UIGestureRecognizerDelegate
>
@end
@implementation
JXPageListMainTableView
-
(
BOOL
)
gestureRecognizer
:(
UIGestureRecognizer
*
)
gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer
:(
UIGestureRecognizer
*
)
otherGestureRecognizer
{
return
[
gestureRecognizer
isKindOfClass
:[
UIPanGestureRecognizer
class
]]
&&
[
otherGestureRecognizer
isKindOfClass
:[
UIPanGestureRecognizer
class
]];
}
@end
GMBase/Classes/JXPagerView/PageListView/JXPageListView.h
0 → 100755
View file @
a4f39813
//
// JXPageView.h
//
// Created by jiaxin on 2018/9/13.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "JXPageListMainTableView.h"
#import "JXPageListContainerView.h"
#import "JXCategoryView.h"
@class
JXPageListView
;
@protocol
JXPageListViewListDelegate
<
NSObject
>
/**
返回listView内部持有的UIScrollView或UITableView或UICollectionView
主要用于mainTableView已经显示了顶部内容,listView的contentOffset需要重置时,内部需要访问到外部传入进来的listView内的scrollView
@return listView内部持有的UIScrollView或UITableView或UICollectionView
*/
-
(
UIScrollView
*
)
listScrollView
;
/**
当listView内部持有的UIScrollView或UITableView或UICollectionView的代理方法`scrollViewDidScroll`回调时,需要调用该代理方法传入的callback
@param callback `scrollViewDidScroll`回调时调用的callback
*/
-
(
void
)
listViewDidScrollCallback
:(
void
(
^
)(
UIScrollView
*
scrollView
))
callback
;
/**
选中listView之后触发数据加载。会多次回调,所以listView内部要做个标志,第一次才触发数据加载。
*/
-
(
void
)
listViewLoadDataIfNeeded
;
@end
@protocol
JXPageListViewDelegate
<
NSObject
>
/**
返回listViews,数组的item需要是UIView的子类,且要遵循JXPageListViewListDelegate。
数组item要求返回一个UIView而不是一个UIScrollView,因为列表的UIScrollView一般是被包装到一个view里面,里面会处理数据源和其他逻辑。
@param pageListView pageListView description
@return listViews
*/
-
(
NSArray
<
UIView
<
JXPageListViewListDelegate
>*>*
)
listViewsInPageListView
:
(
JXPageListView
*
)
pageListView
;
@optional
/**
悬浮分类视图选中某个index的回调
@param pinCategoryView 悬浮分类视图
@param index index
*/
-
(
void
)
pinCategoryView
:
(
JXCategoryBaseView
*
)
pinCategoryView
didSelectedItemAtIndex
:
(
NSInteger
)
index
;
@end
/**
按照demo工程PageViewController里面的tips使用,把最后一个section留给listContainerCell。其余的,你就把mainTableView当做普通的tableView来处理就行。上面想添加多少cell都随你。
*/
@interface
JXPageListView
:
UIView
@property
(
nonatomic
,
strong
,
readonly
)
JXCategoryTitleView
*
pinCategoryView
;
@property
(
nonatomic
,
strong
,
readonly
)
JXPageListMainTableView
*
mainTableView
;
@property
(
nonatomic
,
assign
,
getter
=
isListViewScrollStateSaveEnabled
)
BOOL
listViewScrollStateSaveEnabled
;
//是否保存底部滚动列表视图的滚动状态,默认YES。设置为YES,表示A列表被滚动一定距离后,切换到B列表,当B列表往上滚动到最顶部的时候,再切换到A列表,A列表保存了它之前的滚动距离;设置为NO,表示A列表被滚动一定距离后,切换到B列表,当B列表往上滚动到最顶部的时候,再切换到A列表,A列表也同步被滚动到最顶部了;具体可以参考demo效果。
@property
(
nonatomic
,
assign
)
CGFloat
pinCategoryViewHeight
;
//顶部固定悬浮categoryView的高度
@property
(
nonatomic
,
assign
)
CGFloat
pinCategoryViewVerticalOffset
;
//顶部固定sectionHeader的垂直偏移量。数值越大越往下沉。
-
(
instancetype
)
initWithDelegate
:(
id
<
JXPageListViewDelegate
>
)
delegate
NS_DESIGNATED_INITIALIZER
;
-
(
instancetype
)
init
NS_UNAVAILABLE
;
-
(
instancetype
)
initWithFrame
:(
CGRect
)
frame
NS_UNAVAILABLE
;
-
(
instancetype
)
initWithCoder
:(
NSCoder
*
)
aDecoder
NS_UNAVAILABLE
;
/**
通过服务器获取到数据之后,再调用reloadData方法刷新
*/
-
(
void
)
reloadData
;
/**
返回列表容器cell的高度
*/
-
(
CGFloat
)
listContainerCellHeight
;
/**
返回列表容器cell
*/
-
(
UITableViewCell
*
)
listContainerCellForRowAtIndexPath
:(
NSIndexPath
*
)
indexPath
;
/**
mainTableView的代理方法`scrollViewDidScroll`回调时需要调用该方法
*/
-
(
void
)
mainTableViewDidScroll
:(
UIScrollView
*
)
scrollView
;
@end
GMBase/Classes/JXPagerView/PageListView/JXPageListView.m
0 → 100755
View file @
a4f39813
//
// JXPageView.m
//
// Created by jiaxin on 2018/9/13.
// Copyright © 2018年 jiaxin. All rights reserved.
//
#import "JXPageListView.h"
#import "JXPageListContainerView.h"
static
NSString
*
const
kListContainerCellIdentifier
=
@"jx_kListContainerCellIdentifier"
;
@interface
JXPageListView
()
<
JXPageListContainerViewDelegate
,
JXCategoryViewDelegate
>
@property
(
nonatomic
,
strong
)
JXCategoryTitleView
*
pinCategoryView
;
@property
(
nonatomic
,
weak
)
id
<
JXPageListViewDelegate
>
delegate
;
@property
(
nonatomic
,
strong
)
JXPageListMainTableView
*
mainTableView
;
@property
(
nonatomic
,
strong
)
JXPageListContainerView
*
listContainerView
;
@property
(
nonatomic
,
strong
)
UIScrollView
*
currentScrollingListView
;
@property
(
nonatomic
,
strong
)
UITableViewCell
*
listContainerCell
;
@property
(
nonatomic
,
strong
)
NSArray
*
originalListViews
;
@end
@implementation
JXPageListView
-
(
instancetype
)
initWithDelegate
:(
id
<
JXPageListViewDelegate
>
)
delegate
{
self
=
[
super
initWithFrame
:
CGRectZero
];
if
(
self
)
{
_delegate
=
delegate
;
[
self
initializeViews
];
}
return
self
;
}
-
(
void
)
initializeViews
{
_listViewScrollStateSaveEnabled
=
YES
;
_pinCategoryViewVerticalOffset
=
0
;
self
.
pinCategoryView
=
[[
JXCategoryTitleView
alloc
]
initWithFrame
:
CGRectZero
];
self
.
pinCategoryView
.
backgroundColor
=
[
UIColor
whiteColor
];
self
.
pinCategoryView
.
delegate
=
self
;
self
.
pinCategoryView
.
titleSelectedColor
=
[
UIColor
colorWithRed
:
105
/
255
.
0
green
:
144
/
255
.
0
blue
:
239
/
255
.
0
alpha
:
1
];
self
.
pinCategoryView
.
titleColor
=
[
UIColor
blackColor
];
self
.
pinCategoryView
.
titleColorGradientEnabled
=
YES
;
self
.
pinCategoryView
.
titleLabelZoomEnabled
=
YES
;
JXCategoryIndicatorLineView
*
lineView
=
[[
JXCategoryIndicatorLineView
alloc
]
init
];
lineView
.
indicatorColor
=
[
UIColor
colorWithRed
:
105
/
255
.
0
green
:
144
/
255
.
0
blue
:
239
/
255
.
0
alpha
:
1
];
lineView
.
indicatorWidth
=
30
;
self
.
pinCategoryView
.
indicators
=
@[
lineView
];
_mainTableView
=
[[
JXPageListMainTableView
alloc
]
initWithFrame
:
CGRectZero
style
:
UITableViewStylePlain
];
self
.
mainTableView
.
showsVerticalScrollIndicator
=
NO
;
self
.
mainTableView
.
tableFooterView
=
[
UIView
new
];
[
self
.
mainTableView
registerClass
:[
UITableViewCell
class
]
forCellReuseIdentifier
:
kListContainerCellIdentifier
];
if
(
@available
(
iOS
11
.
0
,
*
))
{
self
.
mainTableView
.
contentInsetAdjustmentBehavior
=
UIScrollViewContentInsetAdjustmentNever
;
}
[
self
addSubview
:
self
.
mainTableView
];
_listContainerView
=
[[
JXPageListContainerView
alloc
]
initWithDelegate
:
self
];
self
.
listContainerView
.
mainTableView
=
self
.
mainTableView
;
self
.
pinCategoryView
.
contentScrollView
=
self
.
listContainerView
.
collectionView
;
[
self
configListViewDidScrollCallback
];
}
-
(
void
)
layoutSubviews
{
[
super
layoutSubviews
];
self
.
mainTableView
.
frame
=
self
.
bounds
;
}
-
(
void
)
reloadData
{
//先移除以前的listView
for
(
UIView
*
listView
in
self
.
originalListViews
)
{
[
listView
removeFromSuperview
];
}
[
self
configListViewDidScrollCallback
];
[
self
.
mainTableView
reloadData
];
[
self
.
listContainerView
reloadData
];
[
self
.
pinCategoryView
reloadData
];
}
-
(
CGFloat
)
listContainerCellHeight
{
return
self
.
bounds
.
size
.
height
-
self
.
pinCategoryViewVerticalOffset
;
}
-
(
UITableViewCell
*
)
listContainerCellForRowAtIndexPath
:
(
NSIndexPath
*
)
indexPath
{
dispatch_after
(
dispatch_time
(
DISPATCH_TIME_NOW
,
(
int64_t
)(
0
.
25
*
NSEC_PER_SEC
)),
dispatch_get_main_queue
(),
^
{
//触发第一个列表的下拉刷新
NSArray
*
listViews
=
[
self
.
delegate
listViewsInPageListView
:
self
];
if
(
listViews
.
count
>
0
)
{
[
listViews
[
self
.
pinCategoryView
.
selectedIndex
]
listViewLoadDataIfNeeded
];
}
});
UITableViewCell
*
cell
=
[
self
.
mainTableView
dequeueReusableCellWithIdentifier
:
kListContainerCellIdentifier
forIndexPath
:
indexPath
];
cell
.
selectionStyle
=
UITableViewCellSelectionStyleNone
;
self
.
listContainerCell
=
cell
;
for
(
UIView
*
view
in
cell
.
contentView
.
subviews
)
{
[
view
removeFromSuperview
];
}
self
.
pinCategoryView
.
frame
=
CGRectMake
(
0
,
0
,
cell
.
contentView
.
bounds
.
size
.
width
,
self
.
pinCategoryViewHeight
);
if
(
self
.
pinCategoryView
.
superview
!=
cell
.
contentView
)
{
//首次使用pinCategoryView的时候,把pinCategoryView添加到它上面。
[
cell
.
contentView
addSubview
:
self
.
pinCategoryView
];
}
self
.
listContainerView
.
frame
=
CGRectMake
(
0
,
self
.
pinCategoryViewHeight
,
cell
.
contentView
.
bounds
.
size
.
width
,
cell
.
contentView
.
bounds
.
size
.
height
-
self
.
pinCategoryViewHeight
);
[
cell
.
contentView
addSubview
:
self
.
listContainerView
];
return
cell
;
}
-
(
void
)
mainTableViewDidScroll
:
(
UIScrollView
*
)
scrollView
{
//处理当页面滚动在最底部pageView的时候,页面需要立即停住,没有回弹效果。给用户一种切换到pageView浏览模式了
if
(
scrollView
.
contentOffset
.
y
>
10
)
{
scrollView
.
bounces
=
NO
;
}
else
{
scrollView
.
bounces
=
YES
;
}
CGFloat
topContentY
=
[
self
mainTableViewMaxContentOffsetY
];
if
(
scrollView
.
contentOffset
.
y
>=
topContentY
)
{
//当滚动的contentOffset.y大于了指定sectionHeader的y值,且还没有被添加到self.view上的时候,就需要切换superView
if
(
self
.
pinCategoryView
.
superview
!=
self
)
{
CGRect
frame
=
self
.
pinCategoryView
.
frame
;
frame
.
origin
.
y
=
self
.
pinCategoryViewVerticalOffset
;
self
.
pinCategoryView
.
frame
=
frame
;
[
self
addSubview
:
self
.
pinCategoryView
];
}
}
else
if
(
self
.
pinCategoryView
.
superview
!=
self
.
listContainerCell
.
contentView
)
{
//当滚动的contentOffset.y小于了指定sectionHeader的y值,且还没有被添加到sectionCategoryHeaderView上的时候,就需要切换superView
CGRect
frame
=
self
.
pinCategoryView
.
frame
;
frame
.
origin
.
y
=
0
;
self
.
pinCategoryView
.
frame
=
frame
;
[
self
.
listContainerCell
.
contentView
addSubview
:
self
.
pinCategoryView
];
}
if
(
scrollView
.
isTracking
||
scrollView
.
isDecelerating
)
{
//用户滚动的才处理
if
(
self
.
currentScrollingListView
!=
nil
&&
self
.
currentScrollingListView
.
contentOffset
.
y
>
0
)
{
self
.
mainTableView
.
contentOffset
=
CGPointMake
(
self
.
mainTableView
.
contentOffset
.
x
,
topContentY
);
}
}
if
(
!
self
.
isListViewScrollStateSaveEnabled
)
{
if
(
scrollView
.
contentOffset
.
y
<
topContentY
)
{
//mainTableView已经显示了header,listView的contentOffset需要重置
NSArray
*
listViews
=
[
self
.
delegate
listViewsInPageListView
:
self
];
CGFloat
insetTop
=
scrollView
.
contentInset
.
top
;
if
(
@available
(
iOS
11
.
0
,
*
))
{
insetTop
=
scrollView
.
adjustedContentInset
.
top
;
}
for
(
UIView
<
JXPageListViewListDelegate
>*
listView
in
listViews
)
{
[
listView
listScrollView
].
contentOffset
=
CGPointMake
(
self
.
mainTableView
.
contentOffset
.
x
,
-
insetTop
);
}
}
}
}
#pragma mark - Private
-
(
void
)
configListViewDidScrollCallback
{
NSArray
*
listViews
=
[
self
.
delegate
listViewsInPageListView
:
self
];
self
.
originalListViews
=
listViews
;
for
(
UIView
<
JXPageListViewListDelegate
>*
listView
in
listViews
)
{
__weak
typeof
(
self
)
weakSelf
=
self
;
[
listView
listViewDidScrollCallback
:
^
(
UIScrollView
*
scrollView
)
{
[
weakSelf
listViewDidScroll
:
scrollView
];
}];
}
}
-
(
void
)
listViewDidSelectedAtIndex
:
(
NSInteger
)
index
{
UIView
<
JXPageListViewListDelegate
>
*
listContainerView
=
[
self
.
delegate
listViewsInPageListView
:
self
][
index
];
if
([
listContainerView
listScrollView
].
contentOffset
.
y
>
0
)
{
//当前列表视图已经滚动显示了内容
[
self
.
mainTableView
setContentOffset
:
CGPointMake
(
self
.
mainTableView
.
contentOffset
.
x
,
[
self
mainTableViewMaxContentOffsetY
])
animated
:
YES
];
}
}
-
(
CGFloat
)
mainTableViewMaxContentOffsetY
{
return
floor
(
self
.
mainTableView
.
contentSize
.
height
)
-
self
.
bounds
.
size
.
height
;
}
-
(
void
)
listViewDidScroll
:
(
UIScrollView
*
)
scrollView
{
self
.
currentScrollingListView
=
scrollView
;
if
(
scrollView
.
isTracking
==
NO
&&
scrollView
.
isDecelerating
==
NO
)
{
return
;
}
CGFloat
topContentHeight
=
[
self
mainTableViewMaxContentOffsetY
];
if
(
self
.
mainTableView
.
contentOffset
.
y
<
topContentHeight
)
{
//mainTableView的header还没有消失,让listScrollView固定
CGFloat
insetTop
=
scrollView
.
contentInset
.
top
;
if
(
@available
(
iOS
11
.
0
,
*
))
{
insetTop
=
scrollView
.
adjustedContentInset
.
top
;
}
scrollView
.
contentOffset
=
CGPointMake
(
scrollView
.
contentOffset
.
x
,
-
insetTop
);
}
else
{
//mainTableView的header刚好消失,固定mainTableView的位置,显示listScrollView的滚动条
self
.
mainTableView
.
contentOffset
=
CGPointMake
(
self
.
mainTableView
.
contentOffset
.
x
,
topContentHeight
);
}
}
#pragma mark - JXPagingListContainerViewDelegate
-
(
NSInteger
)
numberOfRowsInListContainerView
:
(
JXPageListContainerView
*
)
listContainerView
{
NSArray
*
listViews
=
[
self
.
delegate
listViewsInPageListView
:
self
];
return
listViews
.
count
;
}
-
(
UIView
*
)
listContainerView
:
(
JXPageListContainerView
*
)
listContainerView
listViewInRow
:
(
NSInteger
)
row
{
NSArray
*
listViews
=
[
self
.
delegate
listViewsInPageListView
:
self
];
return
listViews
[
row
];
}
-
(
void
)
listContainerView
:
(
JXPageListContainerView
*
)
listContainerView
willDisplayCellAtRow
:
(
NSInteger
)
row
{
NSArray
*
listViews
=
[
self
.
delegate
listViewsInPageListView
:
self
];
self
.
currentScrollingListView
=
[
listViews
[
row
]
listScrollView
];
}
#pragma mark - JXCategoryViewDelegate
-
(
void
)
categoryView
:
(
JXCategoryBaseView
*
)
categoryView
didSelectedItemAtIndex
:
(
NSInteger
)
index
{
if
([
self
.
delegate
respondsToSelector
:
@selector
(
pinCategoryView
:
didSelectedItemAtIndex
:
)])
{
[
self
.
delegate
pinCategoryView
:
categoryView
didSelectedItemAtIndex
:
index
];
}
NSArray
*
listViews
=
[
self
.
delegate
listViewsInPageListView
:
self
];
[
listViews
[
index
]
listViewLoadDataIfNeeded
];
}
-
(
void
)
categoryView
:
(
JXCategoryBaseView
*
)
categoryView
didClickSelectedItemAtIndex
:
(
NSInteger
)
index
{
//点击选中,会立马回调该方法。但是page还在左右切换。所以延迟0.25秒等左右切换结束再处理。
dispatch_after
(
dispatch_time
(
DISPATCH_TIME_NOW
,
(
int64_t
)(
0
.
25
*
NSEC_PER_SEC
)),
dispatch_get_main_queue
(),
^
{
[
self
listViewDidSelectedAtIndex
:
index
];
});
}
-
(
void
)
categoryView
:
(
JXCategoryBaseView
*
)
categoryView
didScrollSelectedItemAtIndex
:
(
NSInteger
)
index
{
[
self
listViewDidSelectedAtIndex
:
index
];
}
@end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment