修改UI
This commit is contained in:
14
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorBackgroundView.h
generated
Normal file
14
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorBackgroundView.h
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// JXCategoryIndicatorBackgroundView.h
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/8/17.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryIndicatorComponentView.h"
|
||||
|
||||
/// BackgroundView 样式的指示器
|
||||
@interface JXCategoryIndicatorBackgroundView : JXCategoryIndicatorComponentView
|
||||
|
||||
@end
|
||||
101
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorBackgroundView.m
generated
Normal file
101
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorBackgroundView.m
generated
Normal file
@@ -0,0 +1,101 @@
|
||||
//
|
||||
// JXCategoryIndicatorBackgroundView.m
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/8/17.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryIndicatorBackgroundView.h"
|
||||
#import "JXCategoryFactory.h"
|
||||
|
||||
@implementation JXCategoryIndicatorBackgroundView
|
||||
|
||||
#pragma mark - Initialize
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self configureDefaulteValue];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
self = [super initWithCoder:coder];
|
||||
if (self) {
|
||||
[self configureDefaulteValue];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)configureDefaulteValue {
|
||||
self.indicatorWidth = JXCategoryViewAutomaticDimension;
|
||||
self.indicatorHeight = JXCategoryViewAutomaticDimension;
|
||||
self.indicatorCornerRadius = JXCategoryViewAutomaticDimension;
|
||||
self.indicatorColor = [UIColor lightGrayColor];
|
||||
self.indicatorWidthIncrement = 10;
|
||||
}
|
||||
|
||||
#pragma mark - JXCategoryIndicatorProtocol
|
||||
|
||||
- (void)jx_refreshState:(JXCategoryIndicatorParamsModel *)model {
|
||||
self.layer.cornerRadius = [self indicatorCornerRadiusValue:model.selectedCellFrame];
|
||||
self.backgroundColor = self.indicatorColor;
|
||||
|
||||
CGFloat width = [self indicatorWidthValue:model.selectedCellFrame];
|
||||
CGFloat height = [self indicatorHeightValue:model.selectedCellFrame];
|
||||
CGFloat x = model.selectedCellFrame.origin.x + (model.selectedCellFrame.size.width - width)/2;
|
||||
CGFloat y = (model.selectedCellFrame.size.height - height)/2 - self.verticalMargin;
|
||||
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 indicatorWidthValue:leftCellFrame];
|
||||
|
||||
if (percent == 0) {
|
||||
targetX = leftCellFrame.origin.x + (leftCellFrame.size.width - targetWidth)/2.0;
|
||||
}else {
|
||||
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;
|
||||
|
||||
targetX = [JXCategoryFactory interpolationFrom:leftX to:rightX percent:percent];
|
||||
|
||||
if (self.indicatorWidth == JXCategoryViewAutomaticDimension) {
|
||||
targetWidth = [JXCategoryFactory interpolationFrom:leftWidth to:rightWidth percent:percent];
|
||||
}
|
||||
}
|
||||
|
||||
//允许变动frame的情况:1、允许滚动;2、不允许滚动,但是已经通过手势滚动切换一页内容了;
|
||||
if (self.isScrollEnabled == YES || (self.isScrollEnabled == NO && percent == 0)) {
|
||||
CGRect toFrame = self.frame;
|
||||
toFrame.origin.x = targetX;
|
||||
toFrame.size.width = targetWidth;
|
||||
self.frame = toFrame;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)jx_selectedCell:(JXCategoryIndicatorParamsModel *)model {
|
||||
CGFloat width = [self indicatorWidthValue:model.selectedCellFrame];
|
||||
CGRect toFrame = self.frame;
|
||||
toFrame.origin.x = model.selectedCellFrame.origin.x + (model.selectedCellFrame.size.width - width)/2;
|
||||
toFrame.size.width = width;
|
||||
|
||||
if (self.isScrollEnabled) {
|
||||
[UIView animateWithDuration:self.scrollAnimationDuration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
|
||||
self.frame = toFrame;
|
||||
} completion:^(BOOL finished) {
|
||||
}];
|
||||
}else {
|
||||
self.frame = toFrame;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
17
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorBallView.h
generated
Normal file
17
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorBallView.h
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// JXCategoryIndicatorBallView.h
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/8/21.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryIndicatorComponentView.h"
|
||||
|
||||
/// QQ 小红点样式的指示器
|
||||
@interface JXCategoryIndicatorBallView : JXCategoryIndicatorComponentView
|
||||
|
||||
// 球沿的 X 轴方向上的偏移量。默认值为 20
|
||||
@property (nonatomic, assign) CGFloat ballScrollOffsetX;
|
||||
|
||||
@end
|
||||
199
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorBallView.m
generated
Normal file
199
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorBallView.m
generated
Normal file
@@ -0,0 +1,199 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
#pragma mark - Initialize
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self configureIndicatorBall];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
self = [super initWithCoder:coder];
|
||||
if (self) {
|
||||
[self configureIndicatorBall];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)configureIndicatorBall {
|
||||
self.indicatorWidth = 15;
|
||||
self.indicatorHeight = 15;
|
||||
_ballScrollOffsetX = 20;
|
||||
|
||||
_smallBall = [[UIView alloc] init];
|
||||
[self addSubview:self.smallBall];
|
||||
|
||||
_bigBall = [[UIView alloc] init];
|
||||
[self addSubview:self.bigBall];
|
||||
|
||||
_shapeLayer = [CAShapeLayer layer];
|
||||
[self.layer addSublayer:self.shapeLayer];
|
||||
}
|
||||
|
||||
#pragma mark - JXCategoryIndicatorProtocol
|
||||
|
||||
- (void)jx_refreshState:(JXCategoryIndicatorParamsModel *)model {
|
||||
CGFloat ballWidth = [self indicatorWidthValue:model.selectedCellFrame];
|
||||
CGFloat ballHeight = [self indicatorHeightValue:model.selectedCellFrame];
|
||||
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
self.shapeLayer.fillColor = self.indicatorColor.CGColor;
|
||||
[CATransaction commit];
|
||||
|
||||
self.smallBall.backgroundColor = self.indicatorColor;
|
||||
self.smallBall.layer.cornerRadius = ballHeight/2;
|
||||
self.bigBall.backgroundColor = self.indicatorColor;
|
||||
self.bigBall.layer.cornerRadius = ballHeight/2;
|
||||
|
||||
CGFloat x = model.selectedCellFrame.origin.x + (model.selectedCellFrame.size.width - ballWidth)/2;
|
||||
CGFloat y = self.superview.bounds.size.height - ballHeight - self.verticalMargin;
|
||||
if (self.componentPosition == JXCategoryComponentPosition_Top) {
|
||||
y = self.verticalMargin;
|
||||
}
|
||||
self.smallBall.frame = CGRectMake(x, y, ballWidth, ballHeight);
|
||||
self.bigBall.frame = CGRectMake(x, y, ballWidth, ballHeight);
|
||||
}
|
||||
|
||||
- (void)jx_contentScrollViewDidScroll:(JXCategoryIndicatorParamsModel *)model {
|
||||
CGFloat ballWidth = [self indicatorWidthValue:model.leftCellFrame];
|
||||
CGFloat ballHeight = [self indicatorHeightValue:model.leftCellFrame];
|
||||
CGRect rightCellFrame = model.rightCellFrame;
|
||||
CGRect leftCellFrame = model.leftCellFrame;
|
||||
CGFloat percent = model.percent;
|
||||
CGFloat targetXOfBigBall = 0;
|
||||
CGFloat targetXOfSmallBall = leftCellFrame.origin.x + (leftCellFrame.size.width - ballWidth)/2;
|
||||
CGFloat targetWidthOfSmallBall = ballWidth;
|
||||
|
||||
if (percent == 0) {
|
||||
targetXOfBigBall = leftCellFrame.origin.x + (leftCellFrame.size.width - ballWidth)/2.0;
|
||||
targetXOfSmallBall = leftCellFrame.origin.x + (leftCellFrame.size.width - targetWidthOfSmallBall)/2.0;
|
||||
}else {
|
||||
CGFloat leftX = leftCellFrame.origin.x + (leftCellFrame.size.width - ballWidth)/2;
|
||||
CGFloat rightX = rightCellFrame.origin.x + (rightCellFrame.size.width - ballWidth)/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:ballWidth to:ballWidth/2 percent:percent*2];
|
||||
}else {
|
||||
targetXOfBigBall = [JXCategoryFactory interpolationFrom:(rightX - self.ballScrollOffsetX) to:rightX percent:(percent - 0.5)*2];
|
||||
targetWidthOfSmallBall = [JXCategoryFactory interpolationFrom:ballWidth/2 to:0 percent:(percent - 0.5)*2];
|
||||
targetXOfSmallBall = [JXCategoryFactory interpolationFrom:leftX to:rightX percent:(percent - 0.5)*2];
|
||||
}
|
||||
}
|
||||
|
||||
//允许变动frame的情况:1、允许滚动;2、不允许滚动,但是已经通过手势滚动切换一页内容了;
|
||||
if (self.isScrollEnabled == YES || (self.isScrollEnabled == 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 - ballHeight/2 - targetWidthOfSmallBall/2 - self.verticalMargin;
|
||||
if (self.componentPosition == JXCategoryComponentPosition_Top) {
|
||||
targetYOfSmallBall = ballHeight/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 ballWidth = [self indicatorWidthValue:model.selectedCellFrame];
|
||||
CGFloat ballHeight = [self indicatorHeightValue:model.selectedCellFrame];
|
||||
CGFloat x = model.selectedCellFrame.origin.x + (model.selectedCellFrame.size.width - ballWidth)/2;
|
||||
CGFloat y = self.superview.bounds.size.height - ballHeight - self.verticalMargin;
|
||||
if (self.componentPosition == JXCategoryComponentPosition_Top) {
|
||||
y = self.verticalMargin;
|
||||
}
|
||||
CGRect toFrame = CGRectMake(x, y, ballWidth, ballHeight);
|
||||
|
||||
if (self.isScrollEnabled) {
|
||||
[UIView animateWithDuration:self.scrollAnimationDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
|
||||
self.smallBall.frame = toFrame;
|
||||
self.bigBall.frame = toFrame;
|
||||
self.smallBall.layer.cornerRadius = ballHeight/2;
|
||||
self.bigBall.layer.cornerRadius = ballHeight/2;
|
||||
} completion:^(BOOL finished) {
|
||||
|
||||
}];
|
||||
}else {
|
||||
self.smallBall.frame = toFrame;
|
||||
self.bigBall.frame = toFrame;
|
||||
self.smallBall.layer.cornerRadius = ballHeight/2;
|
||||
self.bigBall.layer.cornerRadius = ballHeight/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
|
||||
113
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorComponentView.h
generated
Normal file
113
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorComponentView.h
generated
Normal file
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// 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>
|
||||
|
||||
/**
|
||||
指示器的位置
|
||||
|
||||
可设置的枚举类型:
|
||||
- 底部:JXCategoryComponentPosition_Bottom
|
||||
- 顶部:JXCategoryComponentPosition_Top
|
||||
*/
|
||||
@property (nonatomic, assign) JXCategoryComponentPosition componentPosition;
|
||||
|
||||
/**
|
||||
指示器的宽度
|
||||
|
||||
默认值为 JXCategoryViewAutomaticDimension(表示与 cell 的宽度相等)。
|
||||
内部通过 `- (CGFloat)indicatorWidthValue:(CGRect)cellFrame` 方法获取实际的值。
|
||||
*/
|
||||
@property (nonatomic, assign) CGFloat indicatorWidth;
|
||||
|
||||
/**
|
||||
指示器的宽度增量
|
||||
|
||||
例如:需求是指示器宽度比 cell 宽度多 10pt。就可以将该属性赋值为 10。
|
||||
最终指示器的宽度 = indicatorWidth + indicatorWidthIncrement。
|
||||
*/
|
||||
@property (nonatomic, assign) CGFloat indicatorWidthIncrement;
|
||||
|
||||
/**
|
||||
指示器的高度
|
||||
|
||||
默认值为 3。
|
||||
内部通过 `- (CGFloat)indicatorHeightValue:(CGRect)cellFrame` 方法获取实际的值。
|
||||
*/
|
||||
@property (nonatomic, assign) CGFloat indicatorHeight;
|
||||
|
||||
/**
|
||||
指示器的 CornerRadius 圆角半径
|
||||
|
||||
默认值为 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.25s
|
||||
*/
|
||||
@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
|
||||
81
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorComponentView.m
generated
Normal file
81
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorComponentView.m
generated
Normal file
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// JXCategoryComponentBaseView.m
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/8/17.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryIndicatorComponentView.h"
|
||||
|
||||
@implementation JXCategoryIndicatorComponentView
|
||||
|
||||
#pragma mark - Initialize
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self configureDefaultValue];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
self = [super initWithCoder:coder];
|
||||
if (self) {
|
||||
[self configureDefaultValue];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)configureDefaultValue {
|
||||
_componentPosition = JXCategoryComponentPosition_Bottom;
|
||||
_scrollEnabled = YES;
|
||||
_verticalMargin = 0;
|
||||
_scrollAnimationDuration = 0.25;
|
||||
_indicatorWidth = JXCategoryViewAutomaticDimension;
|
||||
_indicatorWidthIncrement = 0;
|
||||
_indicatorHeight = 3;
|
||||
_indicatorCornerRadius = JXCategoryViewAutomaticDimension;
|
||||
_indicatorColor = [UIColor redColor];
|
||||
_scrollStyle = JXCategoryIndicatorScrollStyleSimple;
|
||||
}
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
- (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
|
||||
17
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorDotLineView.h
generated
Normal file
17
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorDotLineView.h
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// JXCategoryIndicatorDotLineView.h
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/8/22.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryIndicatorComponentView.h"
|
||||
|
||||
/// 点线效果的指示器
|
||||
@interface JXCategoryIndicatorDotLineView : JXCategoryIndicatorComponentView
|
||||
|
||||
// 线状态的最大宽度,默认值为 50
|
||||
@property (nonatomic, assign) CGFloat lineWidth;
|
||||
|
||||
@end
|
||||
148
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorDotLineView.m
generated
Normal file
148
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorDotLineView.m
generated
Normal file
@@ -0,0 +1,148 @@
|
||||
//
|
||||
// JXCategoryIndicatorDotLineView.m
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/8/22.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryIndicatorDotLineView.h"
|
||||
#import "JXCategoryFactory.h"
|
||||
#import "JXCategoryViewAnimator.h"
|
||||
|
||||
@interface JXCategoryIndicatorDotLineView ()
|
||||
@property (nonatomic, strong) JXCategoryViewAnimator *animator;
|
||||
@end
|
||||
|
||||
@implementation JXCategoryIndicatorDotLineView
|
||||
|
||||
#pragma mark - Initialize
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self configureDefaulteValue];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
self = [super initWithCoder:coder];
|
||||
if (self) {
|
||||
[self configureDefaulteValue];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)configureDefaulteValue {
|
||||
self.indicatorWidth = 10;
|
||||
self.indicatorHeight = 10;
|
||||
_lineWidth = 50;
|
||||
}
|
||||
|
||||
#pragma mark - JXCategoryIndicatorProtocol
|
||||
|
||||
- (void)jx_refreshState:(JXCategoryIndicatorParamsModel *)model {
|
||||
CGFloat dotWidth = [self indicatorWidthValue:model.selectedCellFrame];
|
||||
CGFloat dotHeight = [self indicatorHeightValue:model.selectedCellFrame];
|
||||
self.backgroundColor = self.indicatorColor;
|
||||
self.layer.cornerRadius = [self indicatorHeightValue:model.selectedCellFrame]/2;
|
||||
|
||||
CGFloat x = model.selectedCellFrame.origin.x + (model.selectedCellFrame.size.width - dotWidth)/2;
|
||||
CGFloat y = self.superview.bounds.size.height - dotHeight - self.verticalMargin;
|
||||
if (self.componentPosition == JXCategoryComponentPosition_Top) {
|
||||
y = self.verticalMargin;
|
||||
}
|
||||
self.frame = CGRectMake(x, y, dotWidth, dotHeight);
|
||||
}
|
||||
|
||||
- (void)jx_contentScrollViewDidScroll:(JXCategoryIndicatorParamsModel *)model {
|
||||
if (self.animator.isExecuting) {
|
||||
[self.animator invalid];
|
||||
self.animator = nil;
|
||||
}
|
||||
CGFloat dotWidth = [self indicatorWidthValue:model.selectedCellFrame];
|
||||
CGRect rightCellFrame = model.rightCellFrame;
|
||||
CGRect leftCellFrame = model.leftCellFrame;
|
||||
CGFloat percent = model.percent;
|
||||
CGFloat targetX = 0;
|
||||
CGFloat targetWidth = dotWidth;
|
||||
CGFloat leftWidth = dotWidth;
|
||||
CGFloat rightWidth = dotWidth;
|
||||
CGFloat leftX = leftCellFrame.origin.x + (leftCellFrame.size.width - leftWidth)/2;
|
||||
CGFloat rightX = rightCellFrame.origin.x + (rightCellFrame.size.width - rightWidth)/2;
|
||||
CGFloat centerX = leftX + (rightX - leftX - self.lineWidth)/2;
|
||||
|
||||
//前50%,移动x,增加宽度;后50%,移动x并减小width
|
||||
if (percent <= 0.5) {
|
||||
targetX = [JXCategoryFactory interpolationFrom:leftX to:centerX percent:percent*2];
|
||||
targetWidth = [JXCategoryFactory interpolationFrom:dotWidth to:self.lineWidth percent:percent*2];
|
||||
}else {
|
||||
targetX = [JXCategoryFactory interpolationFrom:centerX to:rightX percent:(percent - 0.5)*2];
|
||||
targetWidth = [JXCategoryFactory interpolationFrom:self.lineWidth to:dotWidth 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 {
|
||||
CGFloat dotWidth = [self indicatorWidthValue:model.selectedCellFrame];
|
||||
CGFloat x = model.selectedCellFrame.origin.x + (model.selectedCellFrame.size.width - dotWidth)/2;
|
||||
CGRect targetIndicatorFrame = self.frame;
|
||||
targetIndicatorFrame.origin.x = x;
|
||||
if (self.isScrollEnabled) {
|
||||
if (self.scrollStyle == JXCategoryIndicatorScrollStyleSameAsUserScroll && (model.selectedType == JXCategoryCellSelectedTypeClick | model.selectedType == JXCategoryCellSelectedTypeCode)) {
|
||||
if (self.animator.isExecuting) {
|
||||
[self.animator invalid];
|
||||
self.animator = nil;
|
||||
}
|
||||
CGFloat leftX = 0;
|
||||
CGFloat rightX = 0;
|
||||
BOOL isNeedReversePercent = NO;
|
||||
if (self.frame.origin.x > model.selectedCellFrame.origin.x) {
|
||||
leftX = model.selectedCellFrame.origin.x + (model.selectedCellFrame.size.width - dotWidth)/2;;
|
||||
rightX = self.frame.origin.x;
|
||||
isNeedReversePercent = YES;
|
||||
}else {
|
||||
leftX = self.frame.origin.x;
|
||||
rightX = model.selectedCellFrame.origin.x + (model.selectedCellFrame.size.width - dotWidth)/2;
|
||||
}
|
||||
CGFloat centerX = leftX + (rightX - leftX - self.lineWidth)/2;
|
||||
__weak typeof(self) weakSelf = self;
|
||||
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:centerX percent:percent*2];
|
||||
targetWidth = [JXCategoryFactory interpolationFrom:dotWidth to:self.lineWidth percent:percent*2];
|
||||
}else {
|
||||
targetX = [JXCategoryFactory interpolationFrom:centerX to:rightX percent:(percent - 0.5)*2];
|
||||
targetWidth = [JXCategoryFactory interpolationFrom:self.lineWidth to:dotWidth 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
|
||||
20
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorImageView.h
generated
Normal file
20
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorImageView.h
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// 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;
|
||||
// 图片是否开启滚动,默认值为 NO
|
||||
@property (nonatomic, assign) BOOL indicatorImageViewRollEnabled;
|
||||
// 图片的尺寸,默认值为 CGSizeMake(30, 20)
|
||||
@property (nonatomic, assign) CGSize indicatorImageViewSize;
|
||||
|
||||
@end
|
||||
117
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorImageView.m
generated
Normal file
117
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorImageView.m
generated
Normal file
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// JXCategoryIndicatorImageView.m
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/8/17.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryIndicatorImageView.h"
|
||||
#import "JXCategoryFactory.h"
|
||||
|
||||
@implementation JXCategoryIndicatorImageView
|
||||
|
||||
#pragma mark - Initialize
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self setupIndicatorImageView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
self = [super initWithCoder:coder];
|
||||
if (self) {
|
||||
[self setupIndicatorImageView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setupIndicatorImageView {
|
||||
_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];
|
||||
}
|
||||
|
||||
#pragma mark - Custom Accessors
|
||||
|
||||
- (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.isScrollEnabled == YES || (self.isScrollEnabled == 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.isScrollEnabled) {
|
||||
[UIView animateWithDuration:self.scrollAnimationDuration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
|
||||
self.frame = toFrame;
|
||||
} completion:^(BOOL finished) {
|
||||
}];
|
||||
if (self.indicatorImageViewRollEnabled && (model.selectedType == JXCategoryCellSelectedTypeCode || model.selectedType == JXCategoryCellSelectedTypeClick)) {
|
||||
[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
|
||||
28
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorLineView.h
generated
Normal file
28
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorLineView.h
generated
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// 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
|
||||
202
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorLineView.m
generated
Normal file
202
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorLineView.m
generated
Normal file
@@ -0,0 +1,202 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
#pragma mark - Initialize
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self configureDefaulteValue];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
self = [super initWithCoder:coder];
|
||||
if (self) {
|
||||
[self configureDefaulteValue];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)configureDefaulteValue {
|
||||
_lineStyle = JXCategoryIndicatorLineStyle_Normal;
|
||||
_lineScrollOffsetX = 10;
|
||||
self.indicatorHeight = 3;
|
||||
}
|
||||
|
||||
#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:percent];
|
||||
if (self.indicatorWidth == JXCategoryViewAutomaticDimension) {
|
||||
targetWidth = [JXCategoryFactory interpolationFrom:leftWidth to:rightWidth percent:percent];
|
||||
}
|
||||
}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];
|
||||
targetWidth = [JXCategoryFactory interpolationFrom:maxWidth to:rightWidth percent:(percent - 0.5)*2];
|
||||
}
|
||||
}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 && (model.selectedType == JXCategoryCellSelectedTypeClick | model.selectedType == JXCategoryCellSelectedTypeCode)) {
|
||||
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
|
||||
30
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorRainbowLineView.h
generated
Normal file
30
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorRainbowLineView.h
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// JXCategoryIndicatorRainbowLineView.h
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/12/13.
|
||||
// Copyright © 2018 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryIndicatorLineView.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
彩虹效果的指示器
|
||||
|
||||
!!!: 会无视 JXCategoryIndicatorLineView 的 indicatorColor 属性,以 indicatorColors 为准。
|
||||
*/
|
||||
@interface JXCategoryIndicatorRainbowLineView : JXCategoryIndicatorLineView
|
||||
|
||||
/**
|
||||
指示器颜色数组
|
||||
|
||||
数量需要与 cell 的数量相等。没有提供默认值,必须要赋值该属性。
|
||||
categoryView 在 reloadData 的时候,也要一并更新该属性,不然会出现数组越界。
|
||||
*/
|
||||
@property (nonatomic, strong) NSArray <UIColor *> *indicatorColors;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
38
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorRainbowLineView.m
generated
Normal file
38
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorRainbowLineView.m
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// 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
|
||||
14
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorTriangleView.h
generated
Normal file
14
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorTriangleView.h
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// JXCategoryIndicatorTriangleView.h
|
||||
// JXCategoryView
|
||||
//
|
||||
// Created by jiaxin on 2018/8/17.
|
||||
// Copyright © 2018年 jiaxin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryIndicatorComponentView.h"
|
||||
|
||||
/// 三角形样式的指示器
|
||||
@interface JXCategoryIndicatorTriangleView : JXCategoryIndicatorComponentView
|
||||
|
||||
@end
|
||||
109
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorTriangleView.m
generated
Normal file
109
Pods/JXCategoryView/Sources/Indicator/IndicatorViews/JXCategoryIndicatorTriangleView.m
generated
Normal file
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
#pragma mark - Initialize
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self configureDefaulteValue];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
self = [super initWithCoder:coder];
|
||||
if (self) {
|
||||
[self configureDefaulteValue];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)configureDefaulteValue {
|
||||
self.indicatorWidth = 14;
|
||||
self.indicatorHeight = 10;
|
||||
|
||||
_triangleLayer = [CAShapeLayer layer];
|
||||
[self.layer addSublayer:self.triangleLayer];
|
||||
}
|
||||
|
||||
#pragma mark - JXCategoryIndicatorProtocol
|
||||
|
||||
- (void)jx_refreshState:(JXCategoryIndicatorParamsModel *)model {
|
||||
CGFloat x = model.selectedCellFrame.origin.x + (model.selectedCellFrame.size.width - [self indicatorWidthValue:model.selectedCellFrame])/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, [self indicatorWidthValue:model.selectedCellFrame], [self indicatorHeightValue:model.selectedCellFrame]);
|
||||
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:NO];
|
||||
self.triangleLayer.fillColor = self.indicatorColor.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 indicatorWidthValue:model.leftCellFrame];
|
||||
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.isScrollEnabled == YES || (self.isScrollEnabled == 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 indicatorWidthValue:model.selectedCellFrame])/2;
|
||||
if (self.isScrollEnabled) {
|
||||
[UIView animateWithDuration:self.scrollAnimationDuration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
|
||||
self.frame = toFrame;
|
||||
} completion:^(BOOL finished) {
|
||||
}];
|
||||
} else {
|
||||
self.frame = toFrame;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
13
Pods/JXCategoryView/Sources/Indicator/JXCategoryIndicatorCell.h
generated
Normal file
13
Pods/JXCategoryView/Sources/Indicator/JXCategoryIndicatorCell.h
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// JXCategoryComponetCell.h
|
||||
// DQGuess
|
||||
//
|
||||
// Created by jiaxin on 2018/7/25.
|
||||
// Copyright © 2018年 jingbo. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryBaseCell.h"
|
||||
|
||||
@interface JXCategoryIndicatorCell : JXCategoryBaseCell
|
||||
|
||||
@end
|
||||
52
Pods/JXCategoryView/Sources/Indicator/JXCategoryIndicatorCell.m
generated
Normal file
52
Pods/JXCategoryView/Sources/Indicator/JXCategoryIndicatorCell.m
generated
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// 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.isSepratorLineShowEnabled;
|
||||
|
||||
if (model.isCellBackgroundColorGradientEnabled) {
|
||||
if (model.isSelected) {
|
||||
self.contentView.backgroundColor = model.cellBackgroundSelectedColor;
|
||||
}else {
|
||||
self.contentView.backgroundColor = model.cellBackgroundUnselectedColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
24
Pods/JXCategoryView/Sources/Indicator/JXCategoryIndicatorCellModel.h
generated
Normal file
24
Pods/JXCategoryView/Sources/Indicator/JXCategoryIndicatorCellModel.h
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// 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, getter=isSepratorLineShowEnabled) BOOL sepratorLineShowEnabled;
|
||||
@property (nonatomic, strong) UIColor *separatorLineColor;
|
||||
@property (nonatomic, assign) CGSize separatorLineSize;
|
||||
|
||||
@property (nonatomic, assign) CGRect backgroundViewMaskFrame; // 底部指示器的 frame 转换到 cell 的 frame
|
||||
|
||||
@property (nonatomic, assign, getter=isCellBackgroundColorGradientEnabled) BOOL cellBackgroundColorGradientEnabled;
|
||||
@property (nonatomic, strong) UIColor *cellBackgroundSelectedColor;
|
||||
@property (nonatomic, strong) UIColor *cellBackgroundUnselectedColor;
|
||||
|
||||
@end
|
||||
13
Pods/JXCategoryView/Sources/Indicator/JXCategoryIndicatorCellModel.m
generated
Normal file
13
Pods/JXCategoryView/Sources/Indicator/JXCategoryIndicatorCellModel.m
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// JXCategoryComponentCellModel.m
|
||||
// DQGuess
|
||||
//
|
||||
// Created by jiaxin on 2018/7/25.
|
||||
// Copyright © 2018年 jingbo. All rights reserved.
|
||||
//
|
||||
|
||||
#import "JXCategoryIndicatorCellModel.h"
|
||||
|
||||
@implementation JXCategoryIndicatorCellModel
|
||||
|
||||
@end
|
||||
48
Pods/JXCategoryView/Sources/Indicator/JXCategoryIndicatorView.h
generated
Normal file
48
Pods/JXCategoryView/Sources/Indicator/JXCategoryIndicatorView.h
generated
Normal file
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// 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-----------------------//
|
||||
//cell的背景色是否渐变。默认:NO
|
||||
@property (nonatomic, assign, getter=isCellBackgroundColorGradientEnabled) BOOL cellBackgroundColorGradientEnabled;
|
||||
//cell普通状态的背景色。默认:[UIColor clearColor]
|
||||
@property (nonatomic, strong) UIColor *cellBackgroundUnselectedColor;
|
||||
//cell选中状态的背景色。默认:[UIColor grayColor]
|
||||
@property (nonatomic, strong) UIColor *cellBackgroundSelectedColor;
|
||||
|
||||
//----------------------separatorLine-----------------------//
|
||||
//是否显示分割线。默认为NO
|
||||
@property (nonatomic, assign, getter=isSeparatorLineShowEnabled) BOOL separatorLineShowEnabled;
|
||||
//分割线颜色。默认为[UIColor lightGrayColor]
|
||||
@property (nonatomic, strong) UIColor *separatorLineColor;
|
||||
//分割线的size。默认为CGSizeMake(1/[UIScreen mainScreen].scale, 20)
|
||||
@property (nonatomic, assign) CGSize separatorLineSize;
|
||||
|
||||
@end
|
||||
|
||||
@interface JXCategoryIndicatorView (UISubclassingIndicatorHooks)
|
||||
|
||||
/**
|
||||
当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
|
||||
209
Pods/JXCategoryView/Sources/Indicator/JXCategoryIndicatorView.m
generated
Normal file
209
Pods/JXCategoryView/Sources/Indicator/JXCategoryIndicatorView.m
generated
Normal file
@@ -0,0 +1,209 @@
|
||||
//
|
||||
// JXCategoryIndicatorView.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()
|
||||
|
||||
@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 {
|
||||
_indicators = indicators;
|
||||
|
||||
self.collectionView.indicators = indicators;
|
||||
}
|
||||
|
||||
- (void)refreshState {
|
||||
[super refreshState];
|
||||
|
||||
CGRect selectedCellFrame = CGRectZero;
|
||||
JXCategoryIndicatorCellModel *selectedCellModel;
|
||||
for (int i = 0; i < self.dataSource.count; i++) {
|
||||
JXCategoryIndicatorCellModel *cellModel = (JXCategoryIndicatorCellModel *)self.dataSource[i];
|
||||
cellModel.sepratorLineShowEnabled = self.isSeparatorLineShowEnabled;
|
||||
cellModel.separatorLineColor = self.separatorLineColor;
|
||||
cellModel.separatorLineSize = self.separatorLineSize;
|
||||
cellModel.backgroundViewMaskFrame = CGRectZero;
|
||||
cellModel.cellBackgroundColorGradientEnabled = self.isCellBackgroundColorGradientEnabled;
|
||||
cellModel.cellBackgroundSelectedColor = self.cellBackgroundSelectedColor;
|
||||
cellModel.cellBackgroundUnselectedColor = self.cellBackgroundUnselectedColor;
|
||||
if (i == self.dataSource.count - 1) {
|
||||
cellModel.sepratorLineShowEnabled = NO;
|
||||
}
|
||||
if (i == self.selectedIndex) {
|
||||
selectedCellModel = cellModel;
|
||||
selectedCellFrame = [self getTargetCellFrame:i];
|
||||
}
|
||||
}
|
||||
|
||||
for (UIView<JXCategoryIndicatorProtocol> *indicator in self.indicators) {
|
||||
if (self.dataSource.count <= 0) {
|
||||
indicator.hidden = YES;
|
||||
} else {
|
||||
indicator.hidden = NO;
|
||||
JXCategoryIndicatorParamsModel *indicatorParamsModel = [[JXCategoryIndicatorParamsModel alloc] init];
|
||||
indicatorParamsModel.selectedIndex = self.selectedIndex;
|
||||
indicatorParamsModel.selectedCellFrame = selectedCellFrame;
|
||||
[indicator jx_refreshState:indicatorParamsModel];
|
||||
|
||||
if ([indicator isKindOfClass:[JXCategoryIndicatorBackgroundView class]]) {
|
||||
CGRect maskFrame = indicator.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> *indicator in self.indicators) {
|
||||
[indicator jx_contentScrollViewDidScroll:indicatorParamsModel];
|
||||
}
|
||||
} else {
|
||||
JXCategoryIndicatorCellModel *leftCellModel = (JXCategoryIndicatorCellModel *)self.dataSource[baseIndex];
|
||||
leftCellModel.selectedType = JXCategoryCellSelectedTypeUnknown;
|
||||
JXCategoryIndicatorCellModel *rightCellModel = (JXCategoryIndicatorCellModel *)self.dataSource[baseIndex + 1];
|
||||
rightCellModel.selectedType = JXCategoryCellSelectedTypeUnknown;
|
||||
[self refreshLeftCellModel:leftCellModel rightCellModel:rightCellModel ratio:remainderRatio];
|
||||
|
||||
for (UIView<JXCategoryIndicatorProtocol> *indicator in self.indicators) {
|
||||
[indicator jx_contentScrollViewDidScroll:indicatorParamsModel];
|
||||
if ([indicator isKindOfClass:[JXCategoryIndicatorBackgroundView class]]) {
|
||||
CGRect leftMaskFrame = indicator.frame;
|
||||
leftMaskFrame.origin.x = leftMaskFrame.origin.x - leftCellFrame.origin.x;
|
||||
leftCellModel.backgroundViewMaskFrame = leftMaskFrame;
|
||||
|
||||
CGRect rightMaskFrame = indicator.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 selectedType:(JXCategoryCellSelectedType)selectedType {
|
||||
NSInteger lastSelectedIndex = self.selectedIndex;
|
||||
BOOL result = [super selectCellAtIndex:index selectedType:selectedType];
|
||||
if (!result) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
CGRect clickedCellFrame = [self getTargetSelectedCellFrame:index selectedType:selectedType];
|
||||
|
||||
JXCategoryIndicatorCellModel *selectedCellModel = (JXCategoryIndicatorCellModel *)self.dataSource[index];
|
||||
selectedCellModel.selectedType = selectedType;
|
||||
for (UIView<JXCategoryIndicatorProtocol> *indicator in self.indicators) {
|
||||
JXCategoryIndicatorParamsModel *indicatorParamsModel = [[JXCategoryIndicatorParamsModel alloc] init];
|
||||
indicatorParamsModel.lastSelectedIndex = lastSelectedIndex;
|
||||
indicatorParamsModel.selectedIndex = index;
|
||||
indicatorParamsModel.selectedCellFrame = clickedCellFrame;
|
||||
indicatorParamsModel.selectedType = selectedType;
|
||||
[indicator jx_selectedCell:indicatorParamsModel];
|
||||
if ([indicator isKindOfClass:[JXCategoryIndicatorBackgroundView class]]) {
|
||||
CGRect maskFrame = indicator.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;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation JXCategoryIndicatorView (UISubclassingIndicatorHooks)
|
||||
|
||||
- (void)refreshLeftCellModel:(JXCategoryBaseCellModel *)leftCellModel rightCellModel:(JXCategoryBaseCellModel *)rightCellModel ratio:(CGFloat)ratio {
|
||||
if (self.isCellBackgroundColorGradientEnabled) {
|
||||
//处理cell背景色渐变
|
||||
JXCategoryIndicatorCellModel *leftModel = (JXCategoryIndicatorCellModel *)leftCellModel;
|
||||
JXCategoryIndicatorCellModel *rightModel = (JXCategoryIndicatorCellModel *)rightCellModel;
|
||||
if (leftModel.isSelected) {
|
||||
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.isSelected) {
|
||||
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
|
||||
Reference in New Issue
Block a user