1
Podfile
|
|
@ -46,6 +46,7 @@ target 'QuickLocation' do
|
|||
pod 'SDCycleScrollView'
|
||||
pod 'lottie-ios'
|
||||
pod 'TagListView', '~> 1.0'
|
||||
pod 'BRPickerView'
|
||||
|
||||
#第三方SDk
|
||||
pod 'GYSDK' #个推一键登录
|
||||
|
|
|
|||
15
Podfile.lock
|
|
@ -6,6 +6,16 @@ PODS:
|
|||
- AMapFoundation-NO-IDFA (>= 1.9.0)
|
||||
- AMapNavi-NO-IDFA (11.2.000):
|
||||
- AMapFoundation-NO-IDFA (>= 1.9.0)
|
||||
- BRPickerView (3.0.0):
|
||||
- BRPickerView/Default (= 3.0.0)
|
||||
- BRPickerView/Core (3.0.0)
|
||||
- BRPickerView/DatePicker (3.0.0):
|
||||
- BRPickerView/Core
|
||||
- BRPickerView/Default (3.0.0):
|
||||
- BRPickerView/DatePicker
|
||||
- BRPickerView/TextPicker
|
||||
- BRPickerView/TextPicker (3.0.0):
|
||||
- BRPickerView/Core
|
||||
- CocoaLumberjack/Core (3.9.1)
|
||||
- CocoaLumberjack/Swift (3.9.1):
|
||||
- CocoaLumberjack/Core
|
||||
|
|
@ -178,6 +188,7 @@ DEPENDENCIES:
|
|||
- AlipaySDK-iOS
|
||||
- AMapLocation-NO-IDFA
|
||||
- AMapNavi-NO-IDFA
|
||||
- BRPickerView
|
||||
- CocoaLumberjack/Swift
|
||||
- CocoaMQTT
|
||||
- GYSDK
|
||||
|
|
@ -220,6 +231,7 @@ SPEC REPOS:
|
|||
- AMapFoundation-NO-IDFA
|
||||
- AMapLocation-NO-IDFA
|
||||
- AMapNavi-NO-IDFA
|
||||
- BRPickerView
|
||||
- CocoaLumberjack
|
||||
- CocoaMQTT
|
||||
- Differentiator
|
||||
|
|
@ -284,6 +296,7 @@ SPEC CHECKSUMS:
|
|||
AMapFoundation-NO-IDFA: a2e3c895398d7ee757278e1a0a8f9359da4b146e
|
||||
AMapLocation-NO-IDFA: 7cd8fc837ea41edfbf4d937cd20572e277b77d18
|
||||
AMapNavi-NO-IDFA: d55b9b138c6e540f737c689975cae2c9dbd1026a
|
||||
BRPickerView: cd2e0e3aa87af062bc7a1b6f78d3dfd5f04f04bb
|
||||
CocoaLumberjack: e4ba3b414dfca8c1916c6303d37f63b3a95134c6
|
||||
CocoaMQTT: 1e2fa493d57045d66fb1eba2bb5ffb8d77039c60
|
||||
Differentiator: e8497ceab83c1b10ca233716d547b9af21b9344d
|
||||
|
|
@ -334,6 +347,6 @@ SPEC CHECKSUMS:
|
|||
YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54
|
||||
ZXSDK: 786338c0a18e98e03eda00699c3bfd2700b97117
|
||||
|
||||
PODFILE CHECKSUM: 4d254b7f0c48f2a2100703f9ac600d5d826b586a
|
||||
PODFILE CHECKSUM: 848cd9ba02b2f1c209ac9eef708dd2c43b005385
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// BRPickerView.h
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2017/8/11.
|
||||
// Copyright © 2017 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#ifndef BRPickerView_h
|
||||
#define BRPickerView_h
|
||||
|
||||
#import "BRDatePickerView.h"
|
||||
#import "BRTextPickerView.h"
|
||||
|
||||
#endif /* BRPickerView_h */
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// BRPickerAlertView.h
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2017/8/11.
|
||||
// Copyright © 2017 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "BRPickerStyle.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void(^BRPickerAlertCancelBlock)(void);
|
||||
typedef void(^BRPickerAlertDoneBlock)(void);
|
||||
|
||||
@interface BRPickerAlertView : UIView
|
||||
|
||||
/** 选择器标题 */
|
||||
@property (nullable, nonatomic, copy) NSString *title;
|
||||
|
||||
/** 自定义UI样式(不传或为nil时,是默认样式) */
|
||||
@property (nullable, nonatomic, strong) BRPickerStyle *pickerStyle;
|
||||
|
||||
/** accessory view for above picker view. default is nil */
|
||||
@property (nullable, nonatomic, strong) UIView *pickerHeaderView;
|
||||
|
||||
/** accessory view below picker view. default is nil */
|
||||
@property (nullable, nonatomic, strong) UIView *pickerFooterView;
|
||||
|
||||
/** 取消选择的回调 */
|
||||
@property (nullable, nonatomic, copy) BRPickerAlertCancelBlock cancelBlock;
|
||||
|
||||
/// 确定按钮点击事件的回调
|
||||
/// 应用场景:如果是自定义确定按钮,需要在该按钮点击事件方法里,执行一下 doneBlock 回调。目的是触发组件内部执行 resultBlock 回调,回调选择的值
|
||||
@property (nullable, nonatomic, copy) BRPickerAlertDoneBlock doneBlock;
|
||||
|
||||
/** 弹框视图(使用场景:可以在 alertView 上添加选择器的自定义背景视图) */
|
||||
@property (nullable, nonatomic, strong) UIView *alertView;
|
||||
|
||||
/** 组件的父视图:可以传 自己获取的 keyWindow,或页面的 view */
|
||||
@property (nullable, nonatomic, strong) UIView *keyView;
|
||||
|
||||
|
||||
/// 刷新选择器数据
|
||||
/// 应用场景:动态更新数据源、动态更新选择的值、选择器类型切换等
|
||||
- (void)reloadData;
|
||||
|
||||
/// 扩展一:添加选择器到指定容器视图上
|
||||
/// 应用场景:可将中间的滚轮选择器 pickerView 视图(不包含蒙层及标题栏)添加到任何自定义视图上(会自动填满容器视图),也方便自定义更多的弹框样式
|
||||
/// 补充说明:如果是自定义确定按钮,需要回调默认选择的值:只需在自定义确定按钮的点击事件方法里执行一下 doneBlock 回调(目的是去触发组件内部执行 resultBlock 回调,进而回调默认选择的值)
|
||||
/// @param view 容器视图
|
||||
- (void)addPickerToView:(nullable UIView *)view NS_REQUIRES_SUPER;
|
||||
|
||||
/// 从指定容器视图上移除选择器
|
||||
/// @param view 容器视图
|
||||
- (void)removePickerFromView:(nullable UIView *)view;
|
||||
|
||||
/// 扩展二:添加自定义视图到选择器(pickerView)上
|
||||
/// 应用场景:可以添加一些固定的标题、单位等到选择器中间
|
||||
/// @param customView 自定义视图
|
||||
- (void)addSubViewToPicker:(UIView *)customView;
|
||||
|
||||
/// 扩展三:添加自定义视图到标题栏(titleBarView)上
|
||||
/// 应用场景:可以添加一些子控件到标题栏
|
||||
/// @param customView 自定义视图
|
||||
- (void)addSubViewToTitleBar:(UIView *)customView;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
@ -0,0 +1,398 @@
|
|||
//
|
||||
// BRPickerAlertView.m
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2017/8/11.
|
||||
// Copyright © 2017 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import "BRPickerAlertView.h"
|
||||
|
||||
@interface BRPickerAlertView ()
|
||||
// 蒙层视图
|
||||
@property (nonatomic, strong) UIView *maskBgView;
|
||||
// 标题栏背景视图
|
||||
@property (nonatomic, strong) UIView *titleBarView;
|
||||
// 左边取消按钮
|
||||
@property (nonatomic, strong) UIButton *cancelBtn;
|
||||
// 右边确定按钮
|
||||
@property (nonatomic, strong) UIButton *doneBtn;
|
||||
// 中间标题
|
||||
@property (nonatomic, strong) UILabel *titleLabel;
|
||||
|
||||
// 取消按钮离屏幕边缘的距离
|
||||
@property (nonatomic, assign) CGFloat cancelBtnMargin;
|
||||
// 确定按钮离屏幕边缘的距离
|
||||
@property (nonatomic, assign) CGFloat doneBtnMargin;
|
||||
|
||||
@end
|
||||
|
||||
@implementation BRPickerAlertView
|
||||
|
||||
- (void)initUI {
|
||||
self.frame = self.keyView.bounds;
|
||||
// 设置子视图的宽度随着父视图变化
|
||||
self.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
|
||||
if (!self.pickerStyle.hiddenMaskView) {
|
||||
[self addSubview:self.maskBgView];
|
||||
}
|
||||
|
||||
[self addSubview:self.alertView];
|
||||
|
||||
// 是否隐藏标题栏
|
||||
if (!self.pickerStyle.hiddenTitleBarView) {
|
||||
[self.alertView addSubview:self.titleBarView];
|
||||
[self.alertView sendSubviewToBack:self.titleBarView];
|
||||
|
||||
if (!self.pickerStyle.hiddenTitleLabel) {
|
||||
[self.titleBarView addSubview:self.titleLabel];
|
||||
}
|
||||
if (!self.pickerStyle.hiddenCancelBtn) {
|
||||
[self.titleBarView addSubview:self.cancelBtn];
|
||||
// 获取边距
|
||||
if (self.pickerStyle.cancelBtnFrame.origin.x < self.bounds.size.width / 2) {
|
||||
self.cancelBtnMargin = self.pickerStyle.cancelBtnFrame.origin.x;
|
||||
} else {
|
||||
self.cancelBtnMargin = self.bounds.size.width - self.pickerStyle.cancelBtnFrame.origin.x - self.pickerStyle.cancelBtnFrame.size.width;
|
||||
}
|
||||
}
|
||||
if (!self.pickerStyle.hiddenDoneBtn) {
|
||||
[self.titleBarView addSubview:self.doneBtn];
|
||||
// 获取边距
|
||||
if (self.pickerStyle.doneBtnFrame.origin.x < self.bounds.size.width / 2) {
|
||||
self.doneBtnMargin = self.pickerStyle.doneBtnFrame.origin.x;
|
||||
} else {
|
||||
self.doneBtnMargin = self.bounds.size.width - self.pickerStyle.doneBtnFrame.origin.x - self.pickerStyle.doneBtnFrame.size.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 适配横屏安全区域,更新子视图布局
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
if (_cancelBtn || _doneBtn) {
|
||||
if (@available(iOS 11.0, *)) {
|
||||
UIEdgeInsets safeInsets = self.safeAreaInsets;
|
||||
if (_cancelBtn) {
|
||||
CGRect cancelBtnFrame = self.pickerStyle.cancelBtnFrame;
|
||||
if (cancelBtnFrame.origin.x < MIN(self.bounds.size.width / 2, self.bounds.size.height / 2)) {
|
||||
cancelBtnFrame.origin.x += safeInsets.left;
|
||||
} else {
|
||||
cancelBtnFrame.origin.x = self.bounds.size.width - cancelBtnFrame.size.width - safeInsets.right - self.cancelBtnMargin;
|
||||
}
|
||||
self.cancelBtn.frame = cancelBtnFrame;
|
||||
}
|
||||
if (_doneBtn) {
|
||||
CGRect doneBtnFrame = self.pickerStyle.doneBtnFrame;
|
||||
if (doneBtnFrame.origin.x < MIN(self.bounds.size.width / 2, self.bounds.size.height / 2)) {
|
||||
doneBtnFrame.origin.x += safeInsets.left;
|
||||
} else {
|
||||
doneBtnFrame.origin.x = self.bounds.size.width - doneBtnFrame.size.width - safeInsets.right - self.doneBtnMargin;
|
||||
}
|
||||
self.doneBtn.frame = doneBtnFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_alertView && self.pickerStyle.topCornerRadius > 0) {
|
||||
// 设置顶部圆角
|
||||
[BRPickerStyle br_setView:_alertView roundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight withRadius:self.pickerStyle.topCornerRadius];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 蒙层视图
|
||||
- (UIView *)maskBgView {
|
||||
if (!_maskBgView) {
|
||||
_maskBgView = [[UIView alloc]initWithFrame:self.keyView.bounds];
|
||||
_maskBgView.backgroundColor = self.pickerStyle.maskColor;
|
||||
// 设置子视图的大小随着父视图变化
|
||||
_maskBgView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
_maskBgView.userInteractionEnabled = YES;
|
||||
UITapGestureRecognizer *myTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(didTapMaskBgView:)];
|
||||
[_maskBgView addGestureRecognizer:myTap];
|
||||
}
|
||||
return _maskBgView;
|
||||
}
|
||||
|
||||
#pragma mark - 弹框视图
|
||||
- (UIView *)alertView {
|
||||
if (!_alertView) {
|
||||
CGFloat accessoryViewHeight = 0;
|
||||
if (self.pickerHeaderView) {
|
||||
accessoryViewHeight += self.pickerHeaderView.bounds.size.height;
|
||||
}
|
||||
if (self.pickerFooterView) {
|
||||
accessoryViewHeight += self.pickerFooterView.bounds.size.height;
|
||||
}
|
||||
CGFloat height = self.pickerStyle.titleBarHeight + self.pickerStyle.pickerHeight + self.pickerStyle.paddingBottom + accessoryViewHeight;
|
||||
_alertView = [[UIView alloc]initWithFrame:CGRectMake(0, self.keyView.bounds.size.height - height, self.keyView.bounds.size.width, height)];
|
||||
_alertView.backgroundColor = self.pickerStyle.alertViewColor ? self.pickerStyle.alertViewColor : self.pickerStyle.pickerColor;
|
||||
if (!self.pickerStyle.topCornerRadius && !self.pickerStyle.hiddenShadowLine) {
|
||||
// 设置弹框视图顶部边框线
|
||||
UIView *shadowLineView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, _alertView.frame.size.width, self.pickerStyle.shadowLineHeight)];
|
||||
shadowLineView.backgroundColor = self.pickerStyle.shadowLineColor;
|
||||
shadowLineView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
[_alertView addSubview:shadowLineView];
|
||||
}
|
||||
_alertView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
|
||||
}
|
||||
return _alertView;
|
||||
}
|
||||
|
||||
#pragma mark - 标题栏视图
|
||||
- (UIView *)titleBarView {
|
||||
if (!_titleBarView) {
|
||||
_titleBarView =[[UIView alloc]initWithFrame:CGRectMake(0, 0, self.keyView.bounds.size.width, self.pickerStyle.titleBarHeight)];
|
||||
_titleBarView.backgroundColor = self.pickerStyle.titleBarColor;
|
||||
_titleBarView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
if (!self.pickerStyle.hiddenTitleLine) {
|
||||
// 设置标题栏底部分割线
|
||||
UIView *titleLineView = [[UIView alloc]initWithFrame:CGRectMake(self.pickerStyle.titleLineLeftSpace, _titleBarView.frame.size.height - self.pickerStyle.titleLineHeight, _titleBarView.frame.size.width - self.pickerStyle.titleLineLeftSpace - self.pickerStyle.titleLineRightSpace, self.pickerStyle.titleLineHeight)];
|
||||
titleLineView.backgroundColor = self.pickerStyle.titleLineColor;
|
||||
titleLineView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
[_titleBarView addSubview:titleLineView];
|
||||
}
|
||||
}
|
||||
return _titleBarView;
|
||||
}
|
||||
|
||||
#pragma mark - 取消按钮
|
||||
- (UIButton *)cancelBtn {
|
||||
if (!_cancelBtn) {
|
||||
_cancelBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_cancelBtn.frame = self.pickerStyle.cancelBtnFrame;
|
||||
_cancelBtn.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
|
||||
_cancelBtn.backgroundColor = self.pickerStyle.cancelColor;;
|
||||
_cancelBtn.titleLabel.font = self.pickerStyle.cancelTextFont;
|
||||
[_cancelBtn setTitleColor:self.pickerStyle.cancelTextColor forState:UIControlStateNormal];
|
||||
if (self.pickerStyle.cancelBtnImage) {
|
||||
[_cancelBtn setImage:self.pickerStyle.cancelBtnImage forState:UIControlStateNormal];
|
||||
}
|
||||
if (self.pickerStyle.cancelBtnTitle) {
|
||||
[_cancelBtn setTitle:self.pickerStyle.cancelBtnTitle forState:UIControlStateNormal];
|
||||
}
|
||||
[_cancelBtn addTarget:self action:@selector(clickCancelBtn) forControlEvents:UIControlEventTouchUpInside];
|
||||
// 设置按钮圆角或边框
|
||||
if (self.pickerStyle.cancelBorderStyle == BRBorderStyleSolid) {
|
||||
_cancelBtn.layer.cornerRadius = self.pickerStyle.cancelCornerRadius > 0 ? self.pickerStyle.cancelCornerRadius : 6.0f;
|
||||
_cancelBtn.layer.borderColor = self.pickerStyle.cancelTextColor.CGColor;
|
||||
_cancelBtn.layer.borderWidth = self.pickerStyle.cancelBorderWidth > 0 ? self.pickerStyle.cancelBorderWidth : 1.0f;
|
||||
_cancelBtn.layer.masksToBounds = YES;
|
||||
} else if (self.pickerStyle.cancelBorderStyle == BRBorderStyleFill) {
|
||||
_cancelBtn.layer.cornerRadius = self.pickerStyle.cancelCornerRadius > 0 ? self.pickerStyle.cancelCornerRadius : 6.0f;
|
||||
_cancelBtn.layer.masksToBounds = YES;
|
||||
}
|
||||
}
|
||||
return _cancelBtn;
|
||||
}
|
||||
|
||||
#pragma mark - 确定按钮
|
||||
- (UIButton *)doneBtn {
|
||||
if (!_doneBtn) {
|
||||
_doneBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_doneBtn.frame = self.pickerStyle.doneBtnFrame;
|
||||
_doneBtn.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
|
||||
_doneBtn.backgroundColor = self.pickerStyle.doneColor;
|
||||
if (self.pickerStyle.doneBtnImage) {
|
||||
[_doneBtn setImage:self.pickerStyle.doneBtnImage forState:UIControlStateNormal];
|
||||
}
|
||||
if (self.pickerStyle.doneBtnTitle) {
|
||||
_doneBtn.titleLabel.font = self.pickerStyle.doneTextFont;
|
||||
[_doneBtn setTitleColor:self.pickerStyle.doneTextColor forState:UIControlStateNormal];
|
||||
[_doneBtn setTitle:self.pickerStyle.doneBtnTitle forState:UIControlStateNormal];
|
||||
}
|
||||
[_doneBtn addTarget:self action:@selector(clickDoneBtn) forControlEvents:UIControlEventTouchUpInside];
|
||||
// 设置按钮圆角或边框
|
||||
if (self.pickerStyle.doneBorderStyle == BRBorderStyleSolid) {
|
||||
_doneBtn.layer.cornerRadius = self.pickerStyle.doneCornerRadius > 0 ? self.pickerStyle.doneCornerRadius : 6.0f;
|
||||
_doneBtn.layer.borderColor = self.pickerStyle.doneTextColor.CGColor;
|
||||
_doneBtn.layer.borderWidth = self.pickerStyle.doneBorderWidth > 0 ? self.pickerStyle.doneBorderWidth : 1.0f;
|
||||
_doneBtn.layer.masksToBounds = YES;
|
||||
} else if (self.pickerStyle.doneBorderStyle == BRBorderStyleFill) {
|
||||
_doneBtn.layer.cornerRadius = self.pickerStyle.doneCornerRadius > 0 ? self.pickerStyle.doneCornerRadius : 6.0f;
|
||||
_doneBtn.layer.masksToBounds = YES;
|
||||
}
|
||||
}
|
||||
return _doneBtn;
|
||||
}
|
||||
|
||||
#pragma mark - 中间标题label
|
||||
- (UILabel *)titleLabel {
|
||||
if (!_titleLabel) {
|
||||
_titleLabel = [[UILabel alloc]initWithFrame:self.pickerStyle.titleLabelFrame];
|
||||
_titleLabel.backgroundColor = self.pickerStyle.titleLabelColor;
|
||||
_titleLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
|
||||
_titleLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_titleLabel.font = self.pickerStyle.titleTextFont;
|
||||
_titleLabel.textColor = self.pickerStyle.titleTextColor;
|
||||
_titleLabel.text = self.title;
|
||||
}
|
||||
return _titleLabel;
|
||||
}
|
||||
|
||||
#pragma mark - 点击蒙层视图事件
|
||||
- (void)didTapMaskBgView:(UITapGestureRecognizer *)sender {
|
||||
[self removePickerFromView:nil];
|
||||
if (self.cancelBlock) {
|
||||
self.cancelBlock();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 取消按钮的点击事件
|
||||
- (void)clickCancelBtn {
|
||||
if (self.cancelBlock) {
|
||||
self.cancelBlock();
|
||||
}
|
||||
[self removePickerFromView:nil];
|
||||
}
|
||||
|
||||
#pragma mark - 确定按钮的点击事件
|
||||
- (void)clickDoneBtn {
|
||||
if (self.doneBlock) {
|
||||
self.doneBlock();
|
||||
}
|
||||
[self removePickerFromView:nil];
|
||||
}
|
||||
|
||||
#pragma mark - 添加视图方法
|
||||
- (void)addPickerToView:(UIView *)view {
|
||||
if (view) {
|
||||
self.frame = view.bounds;
|
||||
self.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
|
||||
CGFloat accessoryViewHeight = 0;
|
||||
if (self.pickerHeaderView) {
|
||||
CGRect rect = self.pickerHeaderView.frame;
|
||||
self.pickerHeaderView.frame = CGRectMake(0, 0, view.bounds.size.width, rect.size.height);
|
||||
self.pickerHeaderView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
[self addSubview:self.pickerHeaderView];
|
||||
|
||||
accessoryViewHeight += self.pickerHeaderView.bounds.size.height;
|
||||
}
|
||||
if (self.pickerFooterView) {
|
||||
CGRect rect = self.pickerFooterView.frame;
|
||||
self.pickerFooterView.frame = CGRectMake(0, view.bounds.size.height - rect.size.height, view.bounds.size.width, rect.size.height);
|
||||
self.pickerFooterView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
[self addSubview:self.pickerFooterView];
|
||||
|
||||
accessoryViewHeight += self.pickerFooterView.bounds.size.height;
|
||||
}
|
||||
|
||||
[view addSubview:self];
|
||||
} else {
|
||||
[self initUI];
|
||||
|
||||
if (self.pickerHeaderView) {
|
||||
CGRect rect = self.pickerHeaderView.frame;
|
||||
CGFloat titleBarHeight = self.pickerStyle.hiddenTitleBarView ? 0 : self.pickerStyle.titleBarHeight;
|
||||
self.pickerHeaderView.frame = CGRectMake(0, titleBarHeight, self.alertView.bounds.size.width, rect.size.height);
|
||||
self.pickerHeaderView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
[self.alertView addSubview:self.pickerHeaderView];
|
||||
}
|
||||
if (self.pickerFooterView) {
|
||||
CGRect rect = self.pickerFooterView.frame;
|
||||
self.pickerFooterView.frame = CGRectMake(0, self.alertView.bounds.size.height - self.pickerStyle.paddingBottom - rect.size.height, self.alertView.bounds.size.width, rect.size.height);
|
||||
self.pickerFooterView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
[self.alertView addSubview:self.pickerFooterView];
|
||||
}
|
||||
|
||||
[self.keyView addSubview:self];
|
||||
|
||||
// iOS16:重新设置 alertView 高度(解决懒加载设置frame不生效问题)
|
||||
CGFloat accessoryViewHeight = 0;
|
||||
if (self.pickerHeaderView) {
|
||||
accessoryViewHeight += self.pickerHeaderView.bounds.size.height;
|
||||
}
|
||||
if (self.pickerFooterView) {
|
||||
accessoryViewHeight += self.pickerFooterView.bounds.size.height;
|
||||
}
|
||||
CGFloat height = self.pickerStyle.titleBarHeight + self.pickerStyle.pickerHeight + self.pickerStyle.paddingBottom + accessoryViewHeight;
|
||||
self.alertView.frame = CGRectMake(0, self.keyView.bounds.size.height - height, self.keyView.bounds.size.width, height);
|
||||
|
||||
// 动画前初始位置
|
||||
CGRect rect = self.alertView.frame;
|
||||
rect.origin.y = self.bounds.size.height;
|
||||
self.alertView.frame = rect;
|
||||
// 弹出动画
|
||||
if (!self.pickerStyle.hiddenMaskView) {
|
||||
self.maskBgView.alpha = 0;
|
||||
}
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
if (!self.pickerStyle.hiddenMaskView) {
|
||||
self.maskBgView.alpha = 1;
|
||||
}
|
||||
CGFloat alertViewHeight = self.alertView.bounds.size.height;
|
||||
CGRect rect = self.alertView.frame;
|
||||
rect.origin.y -= alertViewHeight;
|
||||
self.alertView.frame = rect;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 移除视图方法
|
||||
- (void)removePickerFromView:(UIView *)view {
|
||||
if (view) {
|
||||
[self removeFromSuperview];
|
||||
} else {
|
||||
// 关闭动画
|
||||
[UIView animateWithDuration:0.2f animations:^{
|
||||
CGFloat alertViewHeight = self.alertView.bounds.size.height;
|
||||
CGRect rect = self.alertView.frame;
|
||||
rect.origin.y += alertViewHeight;
|
||||
self.alertView.frame = rect;
|
||||
if (!self.pickerStyle.hiddenMaskView) {
|
||||
self.maskBgView.alpha = 0;
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
[self removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 刷新选择器数据
|
||||
- (void)reloadData {
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - 添加自定义视图到选择器(picker)上
|
||||
- (void)addSubViewToPicker:(UIView *)customView {
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - 添加自定义视图到标题栏(titleBar)上
|
||||
- (void)addSubViewToTitleBar:(UIView *)customView {
|
||||
if (!self.pickerStyle.hiddenTitleBarView) {
|
||||
[self.titleBarView addSubview:customView];
|
||||
}
|
||||
}
|
||||
|
||||
- (BRPickerStyle *)pickerStyle {
|
||||
if (!_pickerStyle) {
|
||||
_pickerStyle = [[BRPickerStyle alloc]init];
|
||||
}
|
||||
return _pickerStyle;
|
||||
}
|
||||
|
||||
- (UIView *)keyView {
|
||||
if (!_keyView) {
|
||||
_keyView = BRGetKeyWindow();
|
||||
}
|
||||
return _keyView;
|
||||
}
|
||||
|
||||
#pragma mark - setter 方法(支持动态设置标题)
|
||||
- (void)setTitle:(NSString *)title {
|
||||
_title = title;
|
||||
if (_titleLabel) {
|
||||
_titleLabel.text = title;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
NSLog(@"%@ dealloc", NSStringFromClass([self class]));
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
//
|
||||
// BRPickerStyle.h
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2019/10/2.
|
||||
// Copyright © 2019 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "BRPickerViewMacro.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// 边框样式(左边取消按钮/右边确定按钮)
|
||||
typedef NS_ENUM(NSInteger, BRBorderStyle) {
|
||||
/** 无边框(默认) */
|
||||
BRBorderStyleNone = 0,
|
||||
/** 有圆角和边框 */
|
||||
BRBorderStyleSolid,
|
||||
/** 仅有圆角 */
|
||||
BRBorderStyleFill
|
||||
};
|
||||
|
||||
@interface BRPickerStyle : NSObject
|
||||
|
||||
|
||||
/////////////////////////////// 蒙层视图(maskView)///////////////////////////////
|
||||
|
||||
/** 设置背景颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *maskColor;
|
||||
|
||||
/** 隐藏 maskView,默认为 NO */
|
||||
@property (nonatomic, assign) BOOL hiddenMaskView;
|
||||
|
||||
|
||||
////////////////////////////// 弹框视图(alertView)///////////////////////////////
|
||||
|
||||
/** 设置 alertView 弹框视图的背景颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *alertViewColor;
|
||||
|
||||
/** 设置 alertView 弹框视图左上和右上的圆角半径 */
|
||||
@property (nonatomic, assign) NSInteger topCornerRadius;
|
||||
|
||||
/** 设置 alertView 弹框视图顶部边框线颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *shadowLineColor;
|
||||
|
||||
/** 设置 alertView 弹框视图顶部边框线高度 */
|
||||
@property (nonatomic, assign) CGFloat shadowLineHeight;
|
||||
|
||||
/** 隐藏 alertView 弹框视图顶部边框线,默认为 NO */
|
||||
@property (nonatomic, assign) BOOL hiddenShadowLine;
|
||||
|
||||
/** 设置 alertView 弹框视图底部内边距,默认为安全区域底部距屏幕底部的高度 */
|
||||
@property (nonatomic, assign) CGFloat paddingBottom;
|
||||
|
||||
|
||||
//////////////////////////// 标题栏视图(titleBarView) ////////////////////////////
|
||||
|
||||
/** 设置 titleBarView 标题栏的背景颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *titleBarColor;
|
||||
|
||||
/** 设置 titleBarView 标题栏的高度 */
|
||||
@property (nonatomic, assign) CGFloat titleBarHeight;
|
||||
|
||||
/** 设置 titleBarView 标题栏底部分割线颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *titleLineColor;
|
||||
|
||||
/** 设置 titleBarView 标题栏底部分割线左边间距 */
|
||||
@property (nonatomic, assign) CGFloat titleLineLeftSpace;
|
||||
|
||||
/** 设置 titleBarView 标题栏底部分割线左边间距 */
|
||||
@property (nonatomic, assign) CGFloat titleLineRightSpace;
|
||||
|
||||
/** 设置 titleBarView 标题栏底部分割线高度 */
|
||||
@property (nonatomic, assign) CGFloat titleLineHeight;
|
||||
|
||||
/** 隐藏 titleBarView 标题栏底部分割线,默认为 NO */
|
||||
@property (nonatomic, assign) BOOL hiddenTitleLine;
|
||||
|
||||
/** 隐藏 titleBarView,默认为 NO */
|
||||
@property (nonatomic, assign) BOOL hiddenTitleBarView;
|
||||
|
||||
|
||||
////////////////////////// 标题栏中间label(titleLabel)///////////////////////////
|
||||
|
||||
/** 设置 titleLabel 的背景颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *titleLabelColor;
|
||||
|
||||
/** 设置 titleLabel 文本颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *titleTextColor;
|
||||
|
||||
/** 设置 titleLabel 字体大小 */
|
||||
@property (nullable, nonatomic, strong) UIFont *titleTextFont;
|
||||
|
||||
/** 设置 titleLabel 的 frame */
|
||||
@property (nonatomic, assign) CGRect titleLabelFrame;
|
||||
|
||||
/** 隐藏 titleLabel,默认为 NO */
|
||||
@property (nonatomic, assign) BOOL hiddenTitleLabel;
|
||||
|
||||
|
||||
/////////////////////////////// 取消按钮(cancelBtn)//////////////////////////////
|
||||
|
||||
/** 设置 cancelBtn 的背景颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *cancelColor;
|
||||
|
||||
/** 设置 cancelBtn 标题的颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *cancelTextColor;
|
||||
|
||||
/** 设置 cancelBtn 标题的字体 */
|
||||
@property (nullable, nonatomic, strong) UIFont *cancelTextFont;
|
||||
|
||||
/** 设置 cancelBtn 的 frame */
|
||||
@property (nonatomic, assign) CGRect cancelBtnFrame;
|
||||
|
||||
/** 设置 cancelBtn 的边框样式 */
|
||||
@property (nonatomic, assign) BRBorderStyle cancelBorderStyle;
|
||||
|
||||
/** 设置 cancelBtn 的圆角大小 */
|
||||
@property (nonatomic, assign) CGFloat cancelCornerRadius;
|
||||
|
||||
/** 设置 cancelBtn 的边框宽度 */
|
||||
@property (nonatomic, assign) CGFloat cancelBorderWidth;
|
||||
|
||||
/** 设置 cancelBtn 的 image */
|
||||
@property (nullable, nonatomic, strong) UIImage *cancelBtnImage;
|
||||
|
||||
/** 设置 cancelBtn 的 title */
|
||||
@property (nullable, nonatomic, copy) NSString *cancelBtnTitle;
|
||||
|
||||
/** 隐藏 cancelBtn,默认为 NO */
|
||||
@property (nonatomic, assign) BOOL hiddenCancelBtn;
|
||||
|
||||
|
||||
/////////////////////////////// 确定按钮(doneBtn)////////////////////////////////
|
||||
|
||||
/** 设置 doneBtn 的背景颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *doneColor;
|
||||
|
||||
/** 设置 doneBtn 标题的颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *doneTextColor;
|
||||
|
||||
/** 设置 doneBtn 标题的字体 */
|
||||
@property (nullable, nonatomic, strong) UIFont *doneTextFont;
|
||||
|
||||
/** 设置 doneBtn 的 frame */
|
||||
@property (nonatomic, assign) CGRect doneBtnFrame;
|
||||
|
||||
/** 设置 doneBtn 的边框样式 */
|
||||
@property (nonatomic, assign) BRBorderStyle doneBorderStyle;
|
||||
|
||||
/** 设置 doneBtn 的圆角大小 */
|
||||
@property (nonatomic, assign) CGFloat doneCornerRadius;
|
||||
|
||||
/** 设置 doneBtn 的边框宽度 */
|
||||
@property (nonatomic, assign) CGFloat doneBorderWidth;
|
||||
|
||||
/** 设置 doneBtn 的 image */
|
||||
@property (nullable, nonatomic, strong) UIImage *doneBtnImage;
|
||||
|
||||
/** 设置 doneBtn 的 title */
|
||||
@property (nullable, nonatomic, copy) NSString *doneBtnTitle;
|
||||
|
||||
/** 隐藏 doneBtn,默认为 NO */
|
||||
@property (nonatomic, assign) BOOL hiddenDoneBtn;
|
||||
|
||||
|
||||
/////////////////////////////// 选择器(pickerView)///////////////////////////////
|
||||
|
||||
/** 设置 picker 的背景颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *pickerColor;
|
||||
|
||||
/** 设置 picker 中间两条分割线的背景颜色。暂不支持日期选择器前4种类型 */
|
||||
@property (nullable, nonatomic, strong) UIColor *separatorColor;
|
||||
|
||||
/** 设置 picker 中间两条分割线的高度。暂不支持日期选择器前4种类型 */
|
||||
@property (nonatomic, assign) CGFloat separatorHeight;
|
||||
|
||||
/** 设置 picker 中间两条分割线的左侧间距。暂不支持日期选择器前4种类型 */
|
||||
@property (nonatomic, assign) CGFloat separatorLeftSpace;
|
||||
|
||||
/** 设置 picker 中间两条分割线的右侧间距。暂不支持日期选择器前4种类型 */
|
||||
@property (nonatomic, assign) CGFloat separatorRightSpace;
|
||||
|
||||
/** 设置 picker 文本的颜色。暂不支持日期选择器前4种类型 */
|
||||
@property (nullable, nonatomic, strong) UIColor *pickerTextColor;
|
||||
|
||||
/** 设置 picker 文本的字体。暂不支持日期选择器前4种类型 */
|
||||
@property (nullable, nonatomic, strong) UIFont *pickerTextFont;
|
||||
|
||||
/** 设置 picker 中间选中行的背景颜色。暂不支持日期选择器前4种类型 */
|
||||
@property (nullable, nonatomic, strong) UIColor *selectRowColor;
|
||||
|
||||
/** 设置 picker 中间选中行文本的颜色。暂不支持日期选择器前4种类型 */
|
||||
@property (nullable, nonatomic, strong) UIColor *selectRowTextColor;
|
||||
|
||||
/** 设置 picker 中间选中行文本的字体。暂不支持日期选择器前4种类型 */
|
||||
@property (nullable, nonatomic, strong) UIFont *selectRowTextFont;
|
||||
|
||||
/** 设置 picker 的高度,系统默认高度为 216 */
|
||||
@property (nonatomic, assign) CGFloat pickerHeight;
|
||||
|
||||
/** 设置 picker 的行高,默认为 35 */
|
||||
@property (nonatomic, assign) CGFloat rowHeight;
|
||||
/** 设置 picker 的列宽 */
|
||||
@property (nonatomic, assign) CGFloat columnWidth;
|
||||
/** 设置 picker 的列间隔,仅支持`BRTextPickerView` */
|
||||
@property (nonatomic, assign) CGFloat columnSpacing;
|
||||
|
||||
/** 设置 picker 文本支持的最大行数,默认为 2 */
|
||||
@property (nonatomic, assign) NSUInteger maxTextLines;
|
||||
|
||||
/**
|
||||
* 清除iOS14之后选择器默认自带的新样式。暂不支持日期选择器前4种类型
|
||||
* 主要是:①隐藏中间选择行的背景样式,②清除默认的内边距,③新增中间选择行的两条分割线;与iOS14之前的样式保持一致),默认为 YES
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL clearPickerNewStyle;
|
||||
|
||||
|
||||
/**
|
||||
* 设置语言(不设置或为nil时,将随系统的语言自动改变)
|
||||
* language: zh-Hans(简体中文)、zh-Hant(繁体中文)、en(英语 )
|
||||
*/
|
||||
@property(nullable, nonatomic, copy) NSString *language;
|
||||
|
||||
|
||||
/////// 日期选择器单位样式(showUnitType == BRShowUnitTypeOnlyCenter 时生效。暂不支持日期选择器前4种类型 )///////
|
||||
|
||||
/** 设置日期选择器单位文本的颜色 */
|
||||
@property (nullable, nonatomic, strong) UIColor *dateUnitTextColor;
|
||||
|
||||
/** 设置日期选择器单位文本的字体 */
|
||||
@property (nullable, nonatomic, strong) UIFont *dateUnitTextFont;
|
||||
|
||||
/** 设置日期选择器单位 label 的水平方向偏移量 */
|
||||
@property (nonatomic, assign) CGFloat dateUnitOffsetX;
|
||||
|
||||
/** 设置日期选择器单位 label 的竖直方向偏移量 */
|
||||
@property (nonatomic, assign) CGFloat dateUnitOffsetY;
|
||||
|
||||
|
||||
//////////////////////////////// 常用的几种模板样式 ////////////////////////////////
|
||||
|
||||
/// 弹框模板样式1 - 取消/确定按钮圆角样式
|
||||
/// @param themeColor 主题颜色
|
||||
+ (instancetype)pickerStyleWithThemeColor:(nullable UIColor *)themeColor;
|
||||
|
||||
/// 弹框模板样式2 - 顶部圆角样式 + 完成按钮
|
||||
/// @param doneTextColor 完成按钮标题的颜色
|
||||
+ (instancetype)pickerStyleWithDoneTextColor:(nullable UIColor *)doneTextColor;
|
||||
|
||||
/// 弹框模板样式3 - 顶部圆角样式 + 图标按钮
|
||||
/// @param doneBtnImage 完成按钮的 image
|
||||
+ (instancetype)pickerStyleWithDoneBtnImage:(nullable UIImage *)doneBtnImage;
|
||||
|
||||
|
||||
//////////////////////////////// 以下是组件内部使用的几个封装方法 ////////////////////////////////
|
||||
|
||||
/** 设置选择器中间选中行的样式 */
|
||||
- (void)setupPickerSelectRowStyle:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component;
|
||||
|
||||
/** 添加选择器中间行上下两条分割线(iOS14之后系统默认去掉,需要手动添加)*/
|
||||
- (void)addSeparatorLineView:(UIView *)pickerView;
|
||||
|
||||
/** 设置 view 的部分圆角 */
|
||||
// corners(枚举类型,可组合使用):UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomLeft | UIRectCornerBottomRight | UIRectCornerAllCorners
|
||||
+ (void)br_setView:(UIView *)view roundingCorners:(UIRectCorner)corners withRadius:(CGFloat)radius;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
@ -0,0 +1,508 @@
|
|||
//
|
||||
// BRPickerStyle.m
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2019/10/2.
|
||||
// Copyright © 2019 irenb. All dones reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import "BRPickerStyle.h"
|
||||
#import "NSBundle+BRPickerView.h"
|
||||
|
||||
// 标题颜色
|
||||
#define kBRDefaultTextColor BR_RGB_HEX(0x333333, 1.0f)
|
||||
|
||||
@implementation BRPickerStyle
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
self.clearPickerNewStyle = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/// 设置默认样式
|
||||
|
||||
- (UIColor *)maskColor {
|
||||
if (!_maskColor) {
|
||||
_maskColor = [self br_colorWithLightColor:BR_RGB_HEX(0x000000, 0.3f) darkColor:BR_RGB_HEX(0x666666, 0.3f)];
|
||||
}
|
||||
return _maskColor;
|
||||
}
|
||||
|
||||
- (UIColor *)shadowLineColor {
|
||||
if (!_shadowLineColor) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
// 边框线颜色,有透明度
|
||||
_shadowLineColor = [UIColor separatorColor];
|
||||
} else {
|
||||
_shadowLineColor = BR_RGB_HEX(0xc6c6c8, 1.0f);
|
||||
}
|
||||
}
|
||||
return _shadowLineColor;
|
||||
}
|
||||
|
||||
- (CGFloat)shadowLineHeight {
|
||||
if (_shadowLineHeight <= 0 || _shadowLineHeight > 5.0f) {
|
||||
_shadowLineHeight = 0.5f;
|
||||
}
|
||||
return _shadowLineHeight;
|
||||
}
|
||||
|
||||
- (CGFloat)paddingBottom {
|
||||
if (_paddingBottom <= 0) {
|
||||
_paddingBottom = BR_BOTTOM_MARGIN;
|
||||
}
|
||||
return _paddingBottom;
|
||||
}
|
||||
|
||||
- (UIColor *)titleBarColor {
|
||||
if (!_titleBarColor) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
// #ffffff(正常)、#1c1c1e(深色)
|
||||
_titleBarColor = [UIColor secondarySystemGroupedBackgroundColor];
|
||||
} else {
|
||||
_titleBarColor = [UIColor whiteColor];
|
||||
}
|
||||
}
|
||||
return _titleBarColor;
|
||||
}
|
||||
|
||||
- (CGFloat)titleBarHeight {
|
||||
if (!self.hiddenTitleBarView) {
|
||||
if (_titleBarHeight < 44.0f && (!self.hiddenCancelBtn || !self.hiddenDoneBtn || !self.hiddenTitleLabel)) {
|
||||
_titleBarHeight = 44.0f;
|
||||
}
|
||||
} else {
|
||||
_titleBarHeight = 0;
|
||||
}
|
||||
return _titleBarHeight;
|
||||
}
|
||||
|
||||
- (UIColor *)titleLineColor {
|
||||
if (!_titleLineColor) {
|
||||
_titleLineColor = [self br_colorWithLightColor:BR_RGB_HEX(0xededee, 1.0f) darkColor:BR_RGB_HEX(0x18181c, 1.0f)];
|
||||
}
|
||||
return _titleLineColor;
|
||||
}
|
||||
|
||||
- (CGFloat)titleLineHeight {
|
||||
if (_titleLineHeight <= 0) {
|
||||
return 0.5f;
|
||||
}
|
||||
return _titleLineHeight;
|
||||
}
|
||||
|
||||
- (UIColor *)cancelColor {
|
||||
if (!_cancelColor) {
|
||||
_cancelColor = [UIColor clearColor];
|
||||
}
|
||||
return _cancelColor;
|
||||
}
|
||||
|
||||
- (UIColor *)cancelTextColor {
|
||||
if (!_cancelTextColor) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
_cancelTextColor = [UIColor labelColor];
|
||||
} else {
|
||||
_cancelTextColor = kBRDefaultTextColor;
|
||||
}
|
||||
}
|
||||
return _cancelTextColor;
|
||||
}
|
||||
|
||||
- (UIFont *)cancelTextFont {
|
||||
if (!_cancelTextFont) {
|
||||
_cancelTextFont = [UIFont systemFontOfSize:16.0f];
|
||||
}
|
||||
return _cancelTextFont;
|
||||
}
|
||||
|
||||
- (NSString *)cancelBtnTitle {
|
||||
if (!_cancelBtnTitle && !_cancelBtnImage) {
|
||||
_cancelBtnTitle = [NSBundle br_localizedStringForKey:@"取消" language:self.language];
|
||||
}
|
||||
return _cancelBtnTitle;
|
||||
}
|
||||
|
||||
- (CGRect)cancelBtnFrame {
|
||||
if (CGRectEqualToRect(_cancelBtnFrame, CGRectZero) || _cancelBtnFrame.size.height == 0) {
|
||||
_cancelBtnFrame = CGRectMake(5, 8, 60, 28);
|
||||
}
|
||||
return _cancelBtnFrame;
|
||||
}
|
||||
|
||||
- (UIColor *)titleLabelColor {
|
||||
if (!_titleLabelColor) {
|
||||
_titleLabelColor = [UIColor clearColor];
|
||||
}
|
||||
return _titleLabelColor;
|
||||
}
|
||||
|
||||
- (UIColor *)titleTextColor {
|
||||
if (!_titleTextColor) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
_titleTextColor = [UIColor secondaryLabelColor];
|
||||
} else {
|
||||
_titleTextColor = BR_RGB_HEX(0x999999, 1.0f);
|
||||
}
|
||||
}
|
||||
return _titleTextColor;
|
||||
}
|
||||
|
||||
- (UIFont *)titleTextFont {
|
||||
if (!_titleTextFont) {
|
||||
_titleTextFont = [UIFont systemFontOfSize:15.0f];
|
||||
}
|
||||
return _titleTextFont;
|
||||
}
|
||||
|
||||
- (CGRect)titleLabelFrame {
|
||||
if (CGRectEqualToRect(_titleLabelFrame, CGRectZero) || _titleLabelFrame.size.height == 0) {
|
||||
_titleLabelFrame = CGRectMake(5 + 60 + 2, 0, BRGetKeyWindow().bounds.size.width - 2 * (5 + 60 + 2), 44);
|
||||
}
|
||||
return _titleLabelFrame;
|
||||
}
|
||||
|
||||
- (UIColor *)doneColor {
|
||||
if (!_doneColor) {
|
||||
_doneColor = [UIColor clearColor];
|
||||
}
|
||||
return _doneColor;
|
||||
}
|
||||
|
||||
- (UIColor *)doneTextColor {
|
||||
if (!_doneTextColor) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
_doneTextColor = [UIColor labelColor];
|
||||
} else {
|
||||
_doneTextColor = kBRDefaultTextColor;
|
||||
}
|
||||
}
|
||||
return _doneTextColor;
|
||||
}
|
||||
|
||||
- (UIFont *)doneTextFont {
|
||||
if (!_doneTextFont) {
|
||||
_doneTextFont = [UIFont systemFontOfSize:16.0f];
|
||||
}
|
||||
return _doneTextFont;
|
||||
}
|
||||
|
||||
- (NSString *)doneBtnTitle {
|
||||
if (!_doneBtnTitle && !_doneBtnImage) {
|
||||
_doneBtnTitle = [NSBundle br_localizedStringForKey:@"确定" language:self.language];
|
||||
}
|
||||
return _doneBtnTitle;
|
||||
}
|
||||
|
||||
- (CGRect)doneBtnFrame {
|
||||
if (CGRectEqualToRect(_doneBtnFrame, CGRectZero) || _doneBtnFrame.size.height == 0) {
|
||||
_doneBtnFrame = CGRectMake(BRGetKeyWindow().bounds.size.width - 60 - 5, 8, 60, 28);
|
||||
}
|
||||
return _doneBtnFrame;
|
||||
}
|
||||
|
||||
- (UIColor *)pickerColor {
|
||||
if (!_pickerColor) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
// #ffffff(正常)、#1c1c1e(深色)
|
||||
_pickerColor = [UIColor secondarySystemGroupedBackgroundColor];
|
||||
} else {
|
||||
_pickerColor = [UIColor whiteColor];
|
||||
}
|
||||
}
|
||||
return _pickerColor;
|
||||
}
|
||||
|
||||
- (UIColor *)separatorColor {
|
||||
if (!_separatorColor) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
// 分割线颜色,无透明度
|
||||
_separatorColor = [UIColor opaqueSeparatorColor];
|
||||
} else {
|
||||
_separatorColor = BR_RGB_HEX(0xc6c6c8, 1.0f);
|
||||
}
|
||||
}
|
||||
return _separatorColor;
|
||||
}
|
||||
|
||||
- (UIColor *)pickerTextColor {
|
||||
if (!_pickerTextColor) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
_pickerTextColor = [UIColor labelColor];
|
||||
} else {
|
||||
_pickerTextColor = kBRDefaultTextColor;
|
||||
}
|
||||
}
|
||||
return _pickerTextColor;
|
||||
}
|
||||
|
||||
- (UIFont *)pickerTextFont {
|
||||
if (!_pickerTextFont) {
|
||||
_pickerTextFont = [UIFont systemFontOfSize:18.0f];
|
||||
}
|
||||
return _pickerTextFont;
|
||||
}
|
||||
|
||||
- (CGFloat)pickerHeight {
|
||||
if (_pickerHeight < 40) {
|
||||
_pickerHeight = 216.0f;
|
||||
}
|
||||
return _pickerHeight;
|
||||
}
|
||||
|
||||
- (CGFloat)rowHeight {
|
||||
if (_rowHeight < 20) {
|
||||
_rowHeight = 35.0f;
|
||||
}
|
||||
return _rowHeight;
|
||||
}
|
||||
|
||||
- (NSUInteger)maxTextLines {
|
||||
if (_maxTextLines < 1) {
|
||||
_maxTextLines = 2;
|
||||
}
|
||||
return _maxTextLines;
|
||||
}
|
||||
|
||||
- (NSString *)language {
|
||||
if (!_language) {
|
||||
// 跟随系统的首选语言自动改变
|
||||
// zh-Hans-CN(简体中文)、zh-Hant-CN(繁体中文)、en-CN(美式英语)、en-GB(英式英语)
|
||||
// 其中`CN`是iOS9以后新增的地区代码,如:CN 代表中国,US 代表美国
|
||||
_language = [NSLocale preferredLanguages].firstObject;
|
||||
}
|
||||
return _language;
|
||||
}
|
||||
|
||||
- (UIColor *)dateUnitTextColor {
|
||||
if (!_dateUnitTextColor) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
_dateUnitTextColor = [UIColor labelColor];
|
||||
} else {
|
||||
_dateUnitTextColor = kBRDefaultTextColor;
|
||||
}
|
||||
}
|
||||
return _dateUnitTextColor;
|
||||
}
|
||||
|
||||
- (UIFont *)dateUnitTextFont {
|
||||
if (!_dateUnitTextFont) {
|
||||
_dateUnitTextFont = [UIFont systemFontOfSize:18.0f];
|
||||
}
|
||||
return _dateUnitTextFont;
|
||||
}
|
||||
|
||||
#pragma mark - 创建自定义动态颜色(适配深色模式)
|
||||
- (UIColor *)br_colorWithLightColor:(UIColor *)lightColor darkColor:(UIColor *)darkColor {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
UIColor *dyColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
|
||||
if ([traitCollection userInterfaceStyle] == UIUserInterfaceStyleLight) {
|
||||
return lightColor;
|
||||
} else {
|
||||
return darkColor;
|
||||
}
|
||||
}];
|
||||
return dyColor;
|
||||
} else {
|
||||
return lightColor;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 弹框模板样式1 - 取消/确定按钮圆角样式
|
||||
+ (instancetype)pickerStyleWithThemeColor:(UIColor *)themeColor {
|
||||
BRPickerStyle *customStyle = [[self alloc]init];
|
||||
if (themeColor) {
|
||||
customStyle.cancelTextColor = themeColor;
|
||||
customStyle.cancelBorderStyle = BRBorderStyleSolid;
|
||||
customStyle.doneColor = themeColor;
|
||||
customStyle.doneTextColor = [UIColor whiteColor];
|
||||
customStyle.doneBorderStyle = BRBorderStyleFill;
|
||||
}
|
||||
return customStyle;
|
||||
}
|
||||
|
||||
#pragma mark - 弹框模板样式2 - 顶部圆角样式 + 完成按钮
|
||||
+ (instancetype)pickerStyleWithDoneTextColor:(UIColor *)doneTextColor {
|
||||
BRPickerStyle *customStyle = [[self alloc]init];
|
||||
if (doneTextColor) {
|
||||
customStyle.topCornerRadius = 16.0f;
|
||||
customStyle.hiddenCancelBtn = YES;
|
||||
customStyle.hiddenTitleLine = YES;
|
||||
customStyle.titleLabelFrame = CGRectMake(20, 4, 100, 40);
|
||||
customStyle.doneTextColor = doneTextColor;
|
||||
customStyle.doneTextFont = [UIFont boldSystemFontOfSize:18.0f];
|
||||
customStyle.doneBtnFrame = CGRectMake(BRGetKeyWindow().bounds.size.width - 60, 4, 60, 40);
|
||||
customStyle.doneBtnTitle = [NSBundle br_localizedStringForKey:@"完成" language:customStyle.language];
|
||||
customStyle.selectRowTextColor = doneTextColor;
|
||||
customStyle.selectRowTextFont = [UIFont boldSystemFontOfSize:20.0f];
|
||||
}
|
||||
return customStyle;
|
||||
}
|
||||
|
||||
#pragma mark - 弹框模板样式3 - 顶部圆角样式 + 图标按钮
|
||||
+ (instancetype)pickerStyleWithDoneBtnImage:(UIImage *)doneBtnImage {
|
||||
BRPickerStyle *customStyle = [[self alloc]init];
|
||||
if (doneBtnImage) {
|
||||
customStyle.topCornerRadius = 16.0f;
|
||||
customStyle.hiddenTitleLine = YES;
|
||||
customStyle.hiddenCancelBtn = YES;
|
||||
customStyle.titleLabelFrame = CGRectMake(20, 4, 100, 40);
|
||||
customStyle.doneBtnImage = doneBtnImage;
|
||||
customStyle.doneBtnFrame = CGRectMake(BRGetKeyWindow().bounds.size.width - 44, 4, 40, 40);
|
||||
}
|
||||
return customStyle;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - 设置选择器中间选中行的样式
|
||||
- (void)setupPickerSelectRowStyle:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
|
||||
// 1.设置分割线的颜色
|
||||
NSString *systemVersion = [UIDevice currentDevice].systemVersion;
|
||||
if (systemVersion.doubleValue < 14.0) {
|
||||
for (UIView *subView in pickerView.subviews) {
|
||||
if (subView && [subView isKindOfClass:[UIView class]] && subView.frame.size.height <= 1) {
|
||||
subView.backgroundColor = self.separatorColor;
|
||||
// 设置分割线高度
|
||||
if (self.separatorHeight > 0) {
|
||||
CGRect rect = subView.frame;
|
||||
rect.size.height = self.separatorHeight;
|
||||
subView.frame = rect;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2.设置选择器中间选中行的背景颜色
|
||||
UIView *contentView = nil;
|
||||
NSArray *subviews = pickerView.subviews;
|
||||
if (subviews.count > 0) {
|
||||
id firstView = subviews.firstObject;
|
||||
if (firstView && [firstView isKindOfClass:[UIView class]]) {
|
||||
contentView = (UIView *)firstView;
|
||||
}
|
||||
}
|
||||
if (self.selectRowColor) {
|
||||
UIView *columnView = nil;
|
||||
if (contentView) {
|
||||
id obj = [contentView valueForKey:@"subviewCache"];
|
||||
if (obj && [obj isKindOfClass:[NSArray class]]) {
|
||||
NSArray *columnViews = (NSArray *)obj;
|
||||
if (columnViews.count > 0) {
|
||||
id columnObj = columnViews.firstObject;
|
||||
if (columnObj && [columnObj isKindOfClass:[UIView class]]) {
|
||||
columnView = (UIView *)columnObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (columnView) {
|
||||
id obj = [columnView valueForKey:@"middleContainerView"];
|
||||
if (obj && [obj isKindOfClass:[UIView class]]) {
|
||||
UIView *selectRowView = (UIView *)obj;
|
||||
// 中间选中行的背景颜色
|
||||
selectRowView.backgroundColor = self.selectRowColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (contentView && self.clearPickerNewStyle) {
|
||||
if (systemVersion.doubleValue >= 14.0) {
|
||||
// ①隐藏中间选择行的背景样式
|
||||
id lastView = subviews.lastObject;
|
||||
if (lastView && [lastView isKindOfClass:[UIView class]]) {
|
||||
UIView *rectBgView = (UIView *)lastView;
|
||||
rectBgView.hidden = YES;
|
||||
}
|
||||
|
||||
// ②清除iOS14上选择器默认的内边距
|
||||
if (systemVersion.doubleValue < 15.0f) {
|
||||
[self setPickerAllSubViewsStyle:contentView];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3.设置选择器中间选中行的字体颜色/字体大小
|
||||
if (self.selectRowTextColor || self.selectRowTextFont) {
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
// 当前选中的 label
|
||||
UILabel *selectLabel = (UILabel *)[pickerView viewForRow:row forComponent:component];
|
||||
if (selectLabel) {
|
||||
if (self.selectRowTextColor) {
|
||||
selectLabel.textColor = self.selectRowTextColor;
|
||||
}
|
||||
if (self.selectRowTextFont) {
|
||||
selectLabel.font = self.selectRowTextFont;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历子视图,重新设置 frame(清空在 iOS14 上 UIPickerView 出现的内边距)
|
||||
- (void)setPickerAllSubViewsStyle:(UIView *)view {
|
||||
NSArray *subViews = view.subviews;
|
||||
if (subViews.count == 0 || [view isKindOfClass:[UILabel class]]) return;
|
||||
for (UIView *subView in subViews) {
|
||||
NSString *className = NSStringFromClass([subView class]);
|
||||
if ([className isEqualToString:@"UIPickerColumnView"]) {
|
||||
CGRect rect = subView.frame;
|
||||
rect.origin.x = 0;
|
||||
rect.size.width = view.bounds.size.width;
|
||||
subView.frame = rect;
|
||||
}
|
||||
NSString *superClassName = NSStringFromClass([view class]);
|
||||
if ([superClassName isEqualToString:@"UIPickerColumnView"]) {
|
||||
CGRect rect = subView.frame;
|
||||
rect.size.width = view.bounds.size.width;
|
||||
subView.frame = rect;
|
||||
}
|
||||
if ([subView isKindOfClass:[UILabel class]]) {
|
||||
CGRect rect = subView.frame;
|
||||
rect.origin.x = 10;
|
||||
subView.frame = rect;
|
||||
}
|
||||
|
||||
[self setPickerAllSubViewsStyle:subView];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 添加选择器中间行上下两条分割线(iOS14之后系统默认去掉,需要手动添加)
|
||||
- (void)addSeparatorLineView:(UIView *)pickerView {
|
||||
if ([UIDevice currentDevice].systemVersion.doubleValue >= 14.0) {
|
||||
UIView *topLineView = [[UIView alloc]initWithFrame:CGRectMake(self.separatorLeftSpace, pickerView.bounds.size.height / 2 - self.rowHeight / 2, pickerView.bounds.size.width - self.separatorLeftSpace - self.separatorRightSpace, 0.5f)];
|
||||
topLineView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
|
||||
topLineView.backgroundColor = self.separatorColor;
|
||||
// 设置分割线高度
|
||||
if (self.separatorHeight > 0) {
|
||||
CGRect topRect = topLineView.frame;
|
||||
topRect.size.height = self.separatorHeight;
|
||||
topLineView.frame = topRect;
|
||||
}
|
||||
[pickerView addSubview:topLineView];
|
||||
|
||||
UIView *bottomLineView = [[UIView alloc]initWithFrame:CGRectMake(self.separatorLeftSpace, pickerView.bounds.size.height / 2 + self.rowHeight / 2, pickerView.bounds.size.width - self.separatorLeftSpace - self.separatorRightSpace, 0.5f)];
|
||||
bottomLineView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
|
||||
bottomLineView.backgroundColor = self.separatorColor;
|
||||
// 设置分割线高度
|
||||
if (self.separatorHeight > 0) {
|
||||
CGRect bottomRect = bottomLineView.frame;
|
||||
bottomRect.size.height = self.separatorHeight;
|
||||
bottomLineView.frame = bottomRect;
|
||||
}
|
||||
[pickerView addSubview:bottomLineView];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 设置 view 的部分圆角
|
||||
// corners(枚举类型,可组合使用):UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomLeft | UIRectCornerBottomRight | UIRectCornerAllCorners
|
||||
+ (void)br_setView:(UIView *)view roundingCorners:(UIRectCorner)corners withRadius:(CGFloat)radius {
|
||||
UIBezierPath *rounded = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:corners cornerRadii:CGSizeMake(radius, radius)];
|
||||
CAShapeLayer *shape = [[CAShapeLayer alloc]init];
|
||||
[shape setPath:rounded.CGPath];
|
||||
view.layer.mask = shape;
|
||||
}
|
||||
|
||||
@end
|
||||
35
Pods/BRPickerView/BRPickerView/Core/BRPickerView.bundle/en.lproj/Localizable.strings
generated
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Localizable.strings
|
||||
BRPickerViewDemo
|
||||
|
||||
Created by renbo on 2019/10/30.
|
||||
Copyright © 2019 irenb. All rights reserved.
|
||||
*/
|
||||
|
||||
"确定" = "OK";
|
||||
"取消" = "Cancel";
|
||||
"完成" = "Done";
|
||||
|
||||
"年" = " ";
|
||||
"月" = " ";
|
||||
"日" = " ";
|
||||
"时" = " ";
|
||||
"分" = " ";
|
||||
"秒" = " ";
|
||||
|
||||
"周" = " ";
|
||||
"季度" = " ";
|
||||
|
||||
"上午" = "AM";
|
||||
"下午" = "PM";
|
||||
|
||||
"至今" = " Now";
|
||||
"今天" = " Today";
|
||||
|
||||
"周一" = " Mon";
|
||||
"周二" = " Tue";
|
||||
"周三" = " Wed";
|
||||
"周四" = " Thu";
|
||||
"周五" = " Fri";
|
||||
"周六" = " Sat";
|
||||
"周日" = " Sun";
|
||||
35
Pods/BRPickerView/BRPickerView/Core/BRPickerView.bundle/zh-Hans.lproj/Localizable.strings
generated
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Localizable.strings
|
||||
BRPickerViewDemo
|
||||
|
||||
Created by renbo on 2019/10/30.
|
||||
Copyright © 2019 irenb. All rights reserved.
|
||||
*/
|
||||
|
||||
"确定" = "确定";
|
||||
"取消" = "取消";
|
||||
"完成" = "完成";
|
||||
|
||||
"年" = "年";
|
||||
"月" = "月";
|
||||
"日" = "日";
|
||||
"时" = "时";
|
||||
"分" = "分";
|
||||
"秒" = "秒";
|
||||
|
||||
"周" = "周";
|
||||
"季度" = "季度";
|
||||
|
||||
"上午" = "上午";
|
||||
"下午" = "下午";
|
||||
|
||||
"至今" = "至今";
|
||||
"今天" = "今天";
|
||||
|
||||
"周一" = "周一";
|
||||
"周二" = "周二";
|
||||
"周三" = "周三";
|
||||
"周四" = "周四";
|
||||
"周五" = "周五";
|
||||
"周六" = "周六";
|
||||
"周日" = "周日";
|
||||
35
Pods/BRPickerView/BRPickerView/Core/BRPickerView.bundle/zh-Hant.lproj/Localizable.strings
generated
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Localizable.strings
|
||||
BRPickerViewDemo
|
||||
|
||||
Created by renbo on 2019/10/30.
|
||||
Copyright © 2019 irenb. All rights reserved.
|
||||
*/
|
||||
|
||||
"确定" = "確定";
|
||||
"取消" = "取消";
|
||||
"完成" = "完成";
|
||||
|
||||
"年" = "年";
|
||||
"月" = "月";
|
||||
"日" = "日";
|
||||
"时" = "時";
|
||||
"分" = "分";
|
||||
"秒" = "秒";
|
||||
|
||||
"周" = "周";
|
||||
"季度" = "季度";
|
||||
|
||||
"上午" = "上午";
|
||||
"下午" = "下午";
|
||||
|
||||
"至今" = "至今";
|
||||
"今天" = "今天";
|
||||
|
||||
"周一" = "周壹";
|
||||
"周二" = "周二";
|
||||
"周三" = "周三";
|
||||
"周四" = "周四";
|
||||
"周五" = "周五";
|
||||
"周六" = "周六";
|
||||
"周日" = "周日";
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// BRPickerViewMacro.h
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2018/4/23.
|
||||
// Copyright © 2018 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#ifndef BRPickerViewMacro_h
|
||||
#define BRPickerViewMacro_h
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
;
|
||||
// 屏幕安全区域下边距
|
||||
#define BR_BOTTOM_MARGIN \
|
||||
({CGFloat safeBottomHeight = 0;\
|
||||
if (@available(iOS 11.0, *)) {\
|
||||
safeBottomHeight = BRGetKeyWindow().safeAreaInsets.bottom;\
|
||||
}\
|
||||
(safeBottomHeight);})
|
||||
|
||||
|
||||
// 静态库中编写 Category 时的便利宏,用于解决 Category 方法从静态库中加载需要特别设置的问题
|
||||
#ifndef BRSYNTH_DUMMY_CLASS
|
||||
|
||||
#define BRSYNTH_DUMMY_CLASS(_name_) \
|
||||
@interface BRSYNTH_DUMMY_CLASS_ ## _name_ : NSObject @end \
|
||||
@implementation BRSYNTH_DUMMY_CLASS_ ## _name_ @end
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// 打印错误日志
|
||||
#ifdef DEBUG
|
||||
#define BRErrorLog(...) NSLog(@"【BRPickerView】error log. reason: %@", [NSString stringWithFormat:__VA_ARGS__])
|
||||
#else
|
||||
#define BRErrorLog(...)
|
||||
#endif
|
||||
|
||||
|
||||
/** RGB颜色(16进制) */
|
||||
static inline UIColor *BR_RGB_HEX(uint32_t rgbValue, CGFloat alpha) {
|
||||
return [UIColor colorWithRed:((CGFloat)((rgbValue & 0xFF0000) >> 16)) / 255.0
|
||||
green:((CGFloat)((rgbValue & 0xFF00) >> 8)) / 255.0
|
||||
blue:((CGFloat)(rgbValue & 0xFF)) / 255.0
|
||||
alpha:(alpha)];
|
||||
}
|
||||
|
||||
|
||||
/** 获取 keyWindow */
|
||||
static inline UIWindow *BRGetKeyWindow(void) {
|
||||
UIWindow *keyWindow = nil;
|
||||
if (@available(iOS 13.0, *)) { // 运行时检查系统版本(兼容不同版本的系统,防止运行报错)
|
||||
NSSet<UIScene *> *connectedScenes = [UIApplication sharedApplication].connectedScenes;
|
||||
for (UIScene *scene in connectedScenes) {
|
||||
if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:[UIWindowScene class]]) {
|
||||
UIWindowScene *windowScene = (UIWindowScene *)scene;
|
||||
for (UIWindow *window in windowScene.windows) {
|
||||
if (window.isKeyWindow) {
|
||||
keyWindow = window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!keyWindow) {
|
||||
keyWindow = [UIApplication sharedApplication].windows.firstObject;
|
||||
if (!keyWindow.isKeyWindow) {
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED < 130000
|
||||
UIWindow *window = [UIApplication sharedApplication].keyWindow;
|
||||
if (CGRectEqualToRect(window.bounds, UIScreen.mainScreen.bounds)) {
|
||||
keyWindow = window;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return keyWindow;
|
||||
}
|
||||
|
||||
|
||||
#endif /* BRPickerViewMacro_h */
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// NSBundle+BRPickerView.h
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2019/10/30.
|
||||
// Copyright © 2019 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSBundle (BRPickerView)
|
||||
|
||||
/// 获取 BRPickerView 的资源包单例
|
||||
+ (instancetype)br_pickerBundle;
|
||||
|
||||
/// 获取本地化字符串(简化版本)
|
||||
/// @param key 本地化字符串的键(即 Localizable.strings 文件中 key-value 中的 key)
|
||||
/// @param language 目标语言代码,如果为 nil 则使用系统首选语言
|
||||
/// @return 返回对应语言的本地化字符串,如果找不到则返回空字符串
|
||||
+ (NSString *)br_localizedStringForKey:(NSString *)key language:(nullable NSString *)language;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
//
|
||||
// NSBundle+BRPickerView.m
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2019/10/30.
|
||||
// Copyright © 2019 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import "NSBundle+BRPickerView.h"
|
||||
#import "BRPickerAlertView.h"
|
||||
|
||||
BRSYNTH_DUMMY_CLASS(NSBundle_BRPickerView)
|
||||
|
||||
@implementation NSBundle (BRPickerView)
|
||||
|
||||
#pragma mark - 获取 BRPickerView.bundle
|
||||
/// 获取 BRPickerView 的资源包单例
|
||||
/// @discussion 该方法使用 dispatch_once 确保线程安全,首次调用时会查找并加载 BRPickerView.bundle
|
||||
/// @return 返回 BRPickerView.bundle 的 NSBundle 实例,如果找不到则返回主 bundle
|
||||
+ (instancetype)br_pickerBundle {
|
||||
static NSBundle *pickerBundle = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
// 使用 BRPickerAlertView 类来定位 bundle
|
||||
|
||||
// 注意:不同的包管理器有不同的资源路径结构,所以需要条件编译来适配。
|
||||
// 1.CocoaPods:资源在 Pods/BRPickerView/ 目录下
|
||||
// 2.SPM:资源在 .build/checkouts/BRPickerView/ 或其他特定目录
|
||||
// 3.手动集成:资源在项目目录中
|
||||
#ifdef SWIFT_PACKAGE
|
||||
// 方式1: Swift Package Manager
|
||||
NSBundle *bundle = SWIFTPM_MODULE_BUNDLE; // SPM 提供的特殊宏,指向 SPM 包中的正确资源路径
|
||||
#else
|
||||
// 方式2: CocoaPods 或手动集成
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[BRPickerAlertView class]];
|
||||
#endif
|
||||
// 在 bundle 中查找 BRPickerView.bundle
|
||||
NSString *bundlePath = [bundle pathForResource:@"BRPickerView" ofType:@"bundle"];
|
||||
if (bundlePath) {
|
||||
pickerBundle = [NSBundle bundleWithPath:bundlePath];
|
||||
}
|
||||
|
||||
// 如果找不到 BRPickerView.bundle,回退到主 bundle
|
||||
if (!pickerBundle) {
|
||||
pickerBundle = bundle;
|
||||
NSLog(@"⚠️ BRPickerView.bundle not found, using main bundle instead");
|
||||
}
|
||||
});
|
||||
return pickerBundle;
|
||||
}
|
||||
|
||||
#pragma mark - 国际化文本处理
|
||||
/// 获取本地化字符串(简化版本)
|
||||
/// @param key 本地化字符串的键(即 Localizable.strings 文件中 key-value 中的 key)
|
||||
/// @param language 目标语言代码,如果为 nil 则使用系统首选语言
|
||||
/// @return 返回对应语言的本地化字符串,如果找不到则返回空字符串
|
||||
+ (NSString *)br_localizedStringForKey:(NSString *)key language:(NSString *)language {
|
||||
return [self br_localizedStringForKey:key value:nil language:language];
|
||||
}
|
||||
|
||||
/// 获取本地化字符串(完整版本)
|
||||
/// @param key 本地化字符串的键(即 Localizable.strings 文件中 key-value 中的 key)
|
||||
/// @param value 默认值,当找不到对应键时的返回值
|
||||
/// @param language 目标语言代码,如果为 nil 则使用系统首选语言
|
||||
/// @return 返回对应语言的本地化字符串,如果找不到则返回默认值或空字符串
|
||||
+ (NSString *)br_localizedStringForKey:(NSString *)key value:(NSString *)value language:(NSString *)language {
|
||||
// 参数安全检查
|
||||
if (!key || key.length == 0) return @"";
|
||||
|
||||
// 确定使用哪种语言
|
||||
NSString *preferredLanguage = language ?: [NSLocale preferredLanguages].firstObject;
|
||||
NSString *standardizedLanguage = [self standardizeLanguageCode:preferredLanguage];
|
||||
|
||||
// 获取对应语言的 bundle
|
||||
NSBundle *languageBundle = [self bundleForLanguage:standardizedLanguage];
|
||||
|
||||
// 从语言包中获取本地化字符串
|
||||
NSString *localizedString = [languageBundle localizedStringForKey:key value:value table:nil];
|
||||
|
||||
// 检查是否需要回退到主 bundle
|
||||
BOOL needsFallback = !localizedString ||
|
||||
[localizedString isEqualToString:value] ||
|
||||
localizedString.length == 0;
|
||||
if (needsFallback) {
|
||||
// 回退到主 bundle 的本地化
|
||||
localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:value table:nil];
|
||||
}
|
||||
|
||||
|
||||
// 如果 BRPickerView 包中没有找到,或者值与传入的 value 相同,尝试从主包查找
|
||||
if (!localizedString || [localizedString isEqualToString:value] || localizedString.length == 0) {
|
||||
// 回退到主包的本地化
|
||||
localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:value table:nil];
|
||||
}
|
||||
|
||||
return localizedString ?: (value ?: @"");
|
||||
}
|
||||
|
||||
#pragma mark - 语言代码标准化
|
||||
/// 标准化语言代码
|
||||
/// @discussion 将各种语言代码格式统一为标准格式,支持中英文检测
|
||||
/// @param languageCode 原始语言代码
|
||||
/// @return 返回标准化后的语言代码
|
||||
+ (NSString *)standardizeLanguageCode:(NSString *)languageCode {
|
||||
if (!languageCode || languageCode.length == 0) {
|
||||
return @"en"; // 默认英文
|
||||
}
|
||||
|
||||
NSString *lowercaseCode = [languageCode lowercaseString]; // 转小写
|
||||
NSString *uppercaseCode = [languageCode uppercaseString]; // 转大写
|
||||
|
||||
// 英文检测
|
||||
if ([lowercaseCode hasPrefix:@"en"]) {
|
||||
return @"en";
|
||||
}
|
||||
// 中文检测
|
||||
if ([lowercaseCode hasPrefix:@"zh"]) {
|
||||
// 简体中文检测
|
||||
if ([uppercaseCode containsString:@"HANS"] ||
|
||||
[uppercaseCode containsString:@"CN"] ||
|
||||
[languageCode isEqualToString:@"zh_CN"] ||
|
||||
[lowercaseCode isEqualToString:@"zh"] ||
|
||||
[uppercaseCode containsString:@"SIMPLIFIED"]) {
|
||||
return @"zh-Hans"; // 简体中文
|
||||
}
|
||||
|
||||
// 繁体中文检测
|
||||
if ([uppercaseCode containsString:@"HANT"] ||
|
||||
[uppercaseCode containsString:@"TW"] ||
|
||||
[uppercaseCode containsString:@"HK"] ||
|
||||
[uppercaseCode containsString:@"MO"] ||
|
||||
[uppercaseCode containsString:@"TRADITIONAL"]) {
|
||||
return @"zh-Hant"; // 繁体中文
|
||||
}
|
||||
|
||||
// 默认简体中文
|
||||
return @"zh-Hans";
|
||||
}
|
||||
|
||||
// 可以在这里添加更多语言支持
|
||||
// 例如:日语、韩语、法语等
|
||||
|
||||
return @"en"; // 默认回退到英文
|
||||
}
|
||||
|
||||
#pragma mark - 语言包管理
|
||||
/// 获取指定语言的 bundle
|
||||
/// @param language 目标语言代码
|
||||
/// @return 返回对应语言的 lproj bundle,如果找不到则返回默认的英文 bundle
|
||||
+ (NSBundle *)bundleForLanguage:(NSString *)language {
|
||||
if (!language || language.length == 0) {
|
||||
language = @"en"; // 默认语言
|
||||
}
|
||||
|
||||
NSBundle *pickerBundle = [self br_pickerBundle];
|
||||
|
||||
// 1. 首先尝试精确匹配语言包
|
||||
NSString *path = [pickerBundle pathForResource:language ofType:@"lproj"];
|
||||
NSBundle *languageBundle = [NSBundle bundleWithPath:path];
|
||||
|
||||
if (languageBundle) {
|
||||
return languageBundle;
|
||||
}
|
||||
|
||||
// 2. 语言回退机制
|
||||
NSString *fallbackLanguage = nil;
|
||||
if ([language isEqualToString:@"zh-Hant"]) {
|
||||
// 繁体中文回退到简体中文
|
||||
fallbackLanguage = @"zh-Hans";
|
||||
} else if ([language hasPrefix:@"zh"]) {
|
||||
// 其他中文变体回退到简体中文
|
||||
fallbackLanguage = @"zh-Hans";
|
||||
} else {
|
||||
// 其他语言回退到英文
|
||||
fallbackLanguage = @"en";
|
||||
}
|
||||
|
||||
if (fallbackLanguage) {
|
||||
path = [pickerBundle pathForResource:fallbackLanguage ofType:@"lproj"];
|
||||
languageBundle = [NSBundle bundleWithPath:path];
|
||||
if (languageBundle) {
|
||||
return languageBundle;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 最终回退到 picker bundle 本身
|
||||
return pickerBundle;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
//
|
||||
// BRDatePickerView+BR.h
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2020/6/16.
|
||||
// Copyright © 2020 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import "BRDatePickerView.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface BRDatePickerView (BR)
|
||||
|
||||
/** 最小日期 */
|
||||
- (NSDate *)handlerMinDate:(nullable NSDate *)minDate;
|
||||
|
||||
/** 最大日期 */
|
||||
- (NSDate *)handlerMaxDate:(nullable NSDate *)maxDate;
|
||||
|
||||
/** 默认选中的日期 */
|
||||
- (NSDate *)handlerSelectDate:(nullable NSDate *)selectDate dateFormat:(NSString *)dateFormat;
|
||||
|
||||
/** NSDate 转 NSString */
|
||||
- (NSString *)br_stringFromDate:(NSDate *)date dateFormat:(NSString *)dateFormat;
|
||||
|
||||
/** NSString 转 NSDate */
|
||||
- (NSDate *)br_dateFromString:(NSString *)dateString dateFormat:(NSString *)dateFormat;
|
||||
|
||||
/** 比较两个日期大小(可以指定比较级数,即按指定格式进行比较) */
|
||||
- (NSComparisonResult)br_compareDate:(NSDate *)date targetDate:(NSDate *)targetDate dateFormat:(NSString *)dateFormat;
|
||||
|
||||
/** 获取 yearArr 数组 */
|
||||
- (NSArray *)getYearArr;
|
||||
|
||||
/** 获取 monthArr 数组 */
|
||||
- (NSArray *)getMonthArr:(NSInteger)year;
|
||||
|
||||
/** 获取 dayArr 数组 */
|
||||
- (NSArray *)getDayArr:(NSInteger)year month:(NSInteger)month;
|
||||
|
||||
/** 获取 hourArr 数组 */
|
||||
- (NSArray *)getHourArr:(NSInteger)year month:(NSInteger)month day:(NSInteger)day;
|
||||
|
||||
/** 获取 minuteArr 数组 */
|
||||
- (NSArray *)getMinuteArr:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour;
|
||||
|
||||
/** 获取 secondArr 数组 */
|
||||
- (NSArray *)getSecondArr:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute;
|
||||
|
||||
/** 获取 monthWeekArr 数组 */
|
||||
- (NSArray *)getMonthWeekArr:(NSInteger)year month:(NSInteger)month;
|
||||
|
||||
/** 获取 yearWeekArr 数组 */
|
||||
- (NSArray *)getYearWeekArr:(NSInteger)year;
|
||||
|
||||
/** 获取 quarterArr 数组 */
|
||||
- (NSArray *)getQuarterArr:(NSInteger)year;
|
||||
|
||||
/** 添加 pickerView */
|
||||
- (void)setupPickerView:(UIView *)pickerView toView:(UIView *)view;
|
||||
|
||||
/** 设置日期单位 */
|
||||
- (NSArray *)setupPickerUnitLabel:(UIPickerView *)pickerView unitArr:(NSArray *)unitArr;
|
||||
|
||||
- (NSString *)getYearNumber:(NSInteger)year;
|
||||
|
||||
- (NSString *)getMDHMSNumber:(NSInteger)number;
|
||||
|
||||
- (NSString *)getYearText:(NSArray *)yearArr row:(NSInteger)row;
|
||||
|
||||
- (NSString *)getMonthText:(NSArray *)monthArr row:(NSInteger)row;
|
||||
|
||||
- (NSString *)getDayText:(NSArray *)dayArr row:(NSInteger)row mSelectDate:(NSDate *)mSelectDate;
|
||||
|
||||
- (NSString *)getHourText:(NSArray *)hourArr row:(NSInteger)row;
|
||||
|
||||
- (NSString *)getMinuteText:(NSArray *)minuteArr row:(NSInteger)row;
|
||||
|
||||
- (NSString *)getSecondText:(NSArray *)secondArr row:(NSInteger)row;
|
||||
|
||||
- (NSString *)getWeekText:(NSArray *)weekArr row:(NSInteger)row;
|
||||
|
||||
- (NSString *)getQuarterText:(NSArray *)quarterArr row:(NSInteger)row;
|
||||
|
||||
- (NSString *)getAMText;
|
||||
|
||||
- (NSString *)getPMText;
|
||||
|
||||
- (NSString *)getYearUnit;
|
||||
|
||||
- (NSString *)getMonthUnit;
|
||||
|
||||
- (NSString *)getDayUnit;
|
||||
|
||||
- (NSString *)getHourUnit;
|
||||
|
||||
- (NSString *)getMinuteUnit;
|
||||
|
||||
- (NSString *)getSecondUnit;
|
||||
|
||||
- (NSString *)getWeekUnit;
|
||||
|
||||
- (NSString *)getQuarterUnit;
|
||||
|
||||
- (NSInteger)getIndexWithArray:(NSArray *)array object:(NSString *)obj;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
@ -0,0 +1,804 @@
|
|||
//
|
||||
// BRDatePickerView+BR.m
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2020/6/16.
|
||||
// Copyright © 2020 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import "BRDatePickerView+BR.h"
|
||||
#import "NSBundle+BRPickerView.h"
|
||||
|
||||
BRSYNTH_DUMMY_CLASS(BRDatePickerView_BR)
|
||||
|
||||
//////////////////////////////////////////
|
||||
/// 本分类主要是给 BRDatePickerView 文件瘦身
|
||||
//////////////////////////////////////////
|
||||
|
||||
@implementation BRDatePickerView (BR)
|
||||
|
||||
#pragma mark - 最小日期
|
||||
- (NSDate *)handlerMinDate:(NSDate *)minDate {
|
||||
if (!minDate) {
|
||||
if (self.pickerMode == BRDatePickerModeMDHM) {
|
||||
minDate = [NSDate br_setMonth:1 day:1 hour:0 minute:0];
|
||||
} else if (self.pickerMode == BRDatePickerModeMD) {
|
||||
minDate = [NSDate br_setMonth:1 day:1];
|
||||
} else if (self.pickerMode == BRDatePickerModeTime || self.pickerMode == BRDatePickerModeCountDownTimer || self.pickerMode == BRDatePickerModeHM) {
|
||||
minDate = [NSDate br_setHour:0 minute:0];
|
||||
} else if (self.pickerMode == BRDatePickerModeHMS) {
|
||||
minDate = [NSDate br_setHour:0 minute:0 second:0];
|
||||
} else if (self.pickerMode == BRDatePickerModeMS) {
|
||||
minDate = [NSDate br_setMinute:0 second:0];
|
||||
} else {
|
||||
minDate = [NSDate distantPast]; // 遥远的过去的一个时间点
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是12小时制,hour的最小值为1
|
||||
if (self.isTwelveHourMode) {
|
||||
minDate = [minDate br_setTwelveHour:1];
|
||||
}
|
||||
|
||||
return minDate;
|
||||
}
|
||||
|
||||
#pragma mark - 最大日期
|
||||
- (NSDate *)handlerMaxDate:(NSDate *)maxDate {
|
||||
if (!maxDate) {
|
||||
if (self.pickerMode == BRDatePickerModeMDHM) {
|
||||
maxDate = [NSDate br_setMonth:12 day:31 hour:23 minute:59];
|
||||
} else if (self.pickerMode == BRDatePickerModeMD) {
|
||||
maxDate = [NSDate br_setMonth:12 day:31];
|
||||
} else if (self.pickerMode == BRDatePickerModeTime || self.pickerMode == BRDatePickerModeCountDownTimer || self.pickerMode == BRDatePickerModeHM) {
|
||||
maxDate = [NSDate br_setHour:23 minute:59];
|
||||
} else if (self.pickerMode == BRDatePickerModeHMS) {
|
||||
maxDate = [NSDate br_setHour:23 minute:59 second:59];
|
||||
} else if (self.pickerMode == BRDatePickerModeMS) {
|
||||
maxDate = [NSDate br_setMinute:59 second:59];
|
||||
} else {
|
||||
maxDate = [NSDate distantFuture]; // 遥远的未来的一个时间点
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是12小时制,hour的最大值为12
|
||||
if (self.isTwelveHourMode) {
|
||||
maxDate = [maxDate br_setTwelveHour:12];
|
||||
}
|
||||
|
||||
return maxDate;
|
||||
}
|
||||
|
||||
#pragma mark - 默认选中的日期
|
||||
- (NSDate *)handlerSelectDate:(NSDate *)selectDate dateFormat:(NSString *)dateFormat {
|
||||
// selectDate 优先级高于 selectValue(推荐使用 selectDate 设置默认选中的日期)
|
||||
if (!selectDate) {
|
||||
if (self.selectValue && self.selectValue.length > 0) {
|
||||
if (self.pickerMode == BRDatePickerModeYMDH && self.isShowAMAndPM) {
|
||||
NSString *firstString = [[self.selectValue componentsSeparatedByString:@" "] firstObject];
|
||||
NSString *lastString = [[self.selectValue componentsSeparatedByString:@" "] lastObject];
|
||||
if ([lastString isEqualToString:[self getAMText]]) {
|
||||
self.selectValue = [NSString stringWithFormat:@"%@ 00", firstString];
|
||||
}
|
||||
if ([lastString isEqualToString:[self getPMText]]) {
|
||||
self.selectValue = [NSString stringWithFormat:@"%@ 12", firstString];
|
||||
}
|
||||
}
|
||||
|
||||
NSDate *date = nil;
|
||||
if ([self.selectValue isEqualToString:self.lastRowContent]) {
|
||||
date = self.addToNow ? [NSDate date] : nil;
|
||||
} else if ([self.selectValue isEqualToString:self.firstRowContent]) {
|
||||
date = nil;
|
||||
} else {
|
||||
date = [self br_dateFromString:self.selectValue dateFormat:dateFormat];
|
||||
if (!date) {
|
||||
BRErrorLog(@"参数异常!字符串 selectValue 的正确格式是:%@", dateFormat);
|
||||
date = [NSDate date]; // 默认值参数格式错误时,重置/忽略默认值,防止在 Release 环境下崩溃!
|
||||
}
|
||||
if (self.pickerMode == BRDatePickerModeMDHM) {
|
||||
selectDate = [NSDate br_setMonth:date.br_month day:date.br_day hour:date.br_hour minute:date.br_minute];
|
||||
} else if (self.pickerMode == BRDatePickerModeMD) {
|
||||
selectDate = [NSDate br_setMonth:date.br_month day:date.br_day];
|
||||
} else if (self.pickerMode == BRDatePickerModeTime || self.pickerMode == BRDatePickerModeCountDownTimer || self.pickerMode == BRDatePickerModeHM) {
|
||||
selectDate = [NSDate br_setHour:date.br_hour minute:date.br_minute];
|
||||
} else if (self.pickerMode == BRDatePickerModeHMS) {
|
||||
selectDate = [NSDate br_setHour:date.br_hour minute:date.br_minute second:date.br_second];
|
||||
} else if (self.pickerMode == BRDatePickerModeMS) {
|
||||
selectDate = [NSDate br_setMinute:date.br_minute second:date.br_second];
|
||||
} else {
|
||||
selectDate = date;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 不设置默认日期
|
||||
if (self.pickerMode == BRDatePickerModeTime ||
|
||||
self.pickerMode == BRDatePickerModeCountDownTimer ||
|
||||
self.pickerMode == BRDatePickerModeHM ||
|
||||
self.pickerMode == BRDatePickerModeHMS ||
|
||||
self.pickerMode == BRDatePickerModeMS) {
|
||||
// 默认选中最小日期
|
||||
selectDate = self.minDate;
|
||||
} else {
|
||||
if (self.minuteInterval > 1 || self.secondInterval > 1) {
|
||||
NSDate *date = [NSDate date];
|
||||
NSInteger minute = self.minDate.br_minute % self.minuteInterval == 0 ? self.minDate.br_minute : 0;
|
||||
NSInteger second = self.minDate.br_second % self.secondInterval == 0 ? self.minDate.br_second : 0;
|
||||
selectDate = [NSDate br_setYear:date.br_year month:date.br_month day:date.br_day hour:date.br_hour minute:minute second:second];
|
||||
} else {
|
||||
// 默认选中今天的日期
|
||||
selectDate = [NSDate date];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectDate) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// 判断日期是否超过边界限制
|
||||
BOOL selectLessThanMin = [self br_compareDate:selectDate targetDate:self.minDate dateFormat:dateFormat] == NSOrderedAscending;
|
||||
BOOL selectMoreThanMax = [self br_compareDate:selectDate targetDate:self.maxDate dateFormat:dateFormat] == NSOrderedDescending;
|
||||
if (selectLessThanMin) {
|
||||
BRErrorLog(@"默认选择的日期不能小于最小日期!");
|
||||
selectDate = self.minDate;
|
||||
}
|
||||
if (selectMoreThanMax) {
|
||||
BRErrorLog(@"默认选择的日期不能大于最大日期!");
|
||||
selectDate = self.maxDate;
|
||||
}
|
||||
|
||||
return selectDate;
|
||||
}
|
||||
|
||||
#pragma mark - NSDate 转 NSString
|
||||
- (NSString *)br_stringFromDate:(NSDate *)date dateFormat:(NSString *)dateFormat {
|
||||
return [NSDate br_stringFromDate:date dateFormat:dateFormat language:self.pickerStyle.language];
|
||||
}
|
||||
|
||||
#pragma mark - NSString 转 NSDate
|
||||
- (NSDate *)br_dateFromString:(NSString *)dateString dateFormat:(NSString *)dateFormat {
|
||||
return [NSDate br_dateFromString:dateString dateFormat:dateFormat language:self.pickerStyle.language];
|
||||
}
|
||||
|
||||
#pragma mark - 比较两个日期大小(可以指定比较级数,即按指定格式进行比较)
|
||||
- (NSComparisonResult)br_compareDate:(NSDate *)date targetDate:(NSDate *)targetDate dateFormat:(NSString *)dateFormat {
|
||||
NSString *dateString1 = [self br_stringFromDate:date dateFormat:dateFormat];
|
||||
NSString *dateString2 = [self br_stringFromDate:targetDate dateFormat:dateFormat];
|
||||
NSDate *date1 = [self br_dateFromString:dateString1 dateFormat:dateFormat];
|
||||
NSDate *date2 = [self br_dateFromString:dateString2 dateFormat:dateFormat];
|
||||
if ([date1 compare:date2] == NSOrderedDescending) {
|
||||
return 1; // 大于
|
||||
} else if ([date1 compare:date2] == NSOrderedAscending) {
|
||||
return -1; // 小于
|
||||
} else {
|
||||
return 0; // 等于
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 获取 yearArr 数组
|
||||
- (NSArray *)getYearArr {
|
||||
NSMutableArray *tempArr = [[NSMutableArray alloc]init];
|
||||
for (NSInteger i = self.minDate.br_year; i <= self.maxDate.br_year; i++) {
|
||||
[tempArr addObject:[self getYearNumber:i]];
|
||||
}
|
||||
if (self.isDescending) {
|
||||
NSArray *reversedArr = [[tempArr reverseObjectEnumerator] allObjects];
|
||||
tempArr = [reversedArr mutableCopy];
|
||||
}
|
||||
// 判断是否需要添加【自定义字符串】
|
||||
if (self.lastRowContent || self.firstRowContent) {
|
||||
switch (self.pickerMode) {
|
||||
case BRDatePickerModeYMDHMS:
|
||||
case BRDatePickerModeYMDHM:
|
||||
case BRDatePickerModeYMDH:
|
||||
case BRDatePickerModeYMD:
|
||||
case BRDatePickerModeYM:
|
||||
case BRDatePickerModeY:
|
||||
case BRDatePickerModeYMW:
|
||||
case BRDatePickerModeYW:
|
||||
case BRDatePickerModeYQ:
|
||||
{
|
||||
if (self.lastRowContent) {
|
||||
[tempArr addObject:self.lastRowContent];
|
||||
}
|
||||
if (self.firstRowContent) {
|
||||
[tempArr insertObject:self.firstRowContent atIndex:0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [tempArr copy];
|
||||
}
|
||||
|
||||
#pragma mark - 获取 monthArr 数组
|
||||
- (NSArray *)getMonthArr:(NSInteger)year {
|
||||
NSInteger startMonth = 1;
|
||||
NSInteger endMonth = 12;
|
||||
if (year == self.minDate.br_year) {
|
||||
startMonth = self.minDate.br_month;
|
||||
}
|
||||
if (year == self.maxDate.br_year) {
|
||||
endMonth = self.maxDate.br_month;
|
||||
}
|
||||
NSMutableArray *tempArr = [[NSMutableArray alloc]init];
|
||||
for (NSInteger i = startMonth; i <= endMonth; i++) {
|
||||
[tempArr addObject:[self getMDHMSNumber:i]];
|
||||
}
|
||||
if (self.isDescending) {
|
||||
NSArray *reversedArr = [[tempArr reverseObjectEnumerator] allObjects];
|
||||
tempArr = [reversedArr mutableCopy];
|
||||
}
|
||||
// 判断是否需要添加【自定义字符串】
|
||||
if (self.lastRowContent || self.firstRowContent) {
|
||||
switch (self.pickerMode) {
|
||||
case BRDatePickerModeMDHM:
|
||||
case BRDatePickerModeMD:
|
||||
{
|
||||
if (self.lastRowContent) {
|
||||
[tempArr addObject:self.lastRowContent];
|
||||
}
|
||||
if (self.firstRowContent) {
|
||||
[tempArr insertObject:self.firstRowContent atIndex:0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [tempArr copy];
|
||||
}
|
||||
|
||||
#pragma mark - 获取 dayArr 数组
|
||||
- (NSArray *)getDayArr:(NSInteger)year month:(NSInteger)month {
|
||||
NSInteger startDay = 1;
|
||||
NSInteger endDay = [NSDate br_getDaysInYear:year month:month];
|
||||
if (year == self.minDate.br_year && month == self.minDate.br_month) {
|
||||
startDay = self.minDate.br_day;
|
||||
}
|
||||
if (year == self.maxDate.br_year && month == self.maxDate.br_month) {
|
||||
endDay = self.maxDate.br_day;
|
||||
}
|
||||
NSMutableArray *tempArr = [[NSMutableArray alloc]init];
|
||||
for (NSInteger i = startDay; i <= endDay; i++) {
|
||||
[tempArr addObject:[self getMDHMSNumber:i]];
|
||||
}
|
||||
if (self.isDescending) {
|
||||
return [[tempArr reverseObjectEnumerator] allObjects];
|
||||
}
|
||||
|
||||
return [tempArr copy];
|
||||
}
|
||||
|
||||
#pragma mark - 获取 hourArr 数组
|
||||
- (NSArray *)getHourArr:(NSInteger)year month:(NSInteger)month day:(NSInteger)day {
|
||||
if (self.pickerMode == BRDatePickerModeYMDH && self.isShowAMAndPM) {
|
||||
return @[[self getAMText], [self getPMText]];
|
||||
}
|
||||
|
||||
NSInteger startHour = self.isTwelveHourMode ? 1 : 0;
|
||||
NSInteger endHour = self.isTwelveHourMode ? 12 : 23;
|
||||
if (year == self.minDate.br_year && month == self.minDate.br_month && day == self.minDate.br_day) {
|
||||
startHour = self.minDate.br_hour;
|
||||
if (self.isTwelveHourMode) {
|
||||
if (startHour < 1 || startHour > 12) {
|
||||
startHour = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (year == self.maxDate.br_year && month == self.maxDate.br_month && day == self.maxDate.br_day) {
|
||||
endHour = self.maxDate.br_hour;
|
||||
if (self.isTwelveHourMode) {
|
||||
if (endHour < 1 || endHour > 12) {
|
||||
endHour = 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
NSMutableArray *tempArr = [[NSMutableArray alloc]init];
|
||||
for (NSInteger i = startHour; i <= endHour; i++) {
|
||||
[tempArr addObject:[self getMDHMSNumber:i]];
|
||||
}
|
||||
if (self.isDescending) {
|
||||
NSArray *reversedArr = [[tempArr reverseObjectEnumerator] allObjects];
|
||||
tempArr = [reversedArr mutableCopy];
|
||||
}
|
||||
// 判断是否需要添加【自定义字符串】
|
||||
if (self.lastRowContent || self.firstRowContent) {
|
||||
switch (self.pickerMode) {
|
||||
case BRDatePickerModeHMS:
|
||||
case BRDatePickerModeHM:
|
||||
{
|
||||
if (self.lastRowContent) {
|
||||
[tempArr addObject:self.lastRowContent];
|
||||
}
|
||||
if (self.firstRowContent) {
|
||||
[tempArr insertObject:self.firstRowContent atIndex:0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [tempArr copy];
|
||||
}
|
||||
|
||||
#pragma mark - 获取 minuteArr 数组
|
||||
- (NSArray *)getMinuteArr:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour {
|
||||
NSInteger startMinute = 0;
|
||||
NSInteger endMinute = 59;
|
||||
if (year == self.minDate.br_year && month == self.minDate.br_month && day == self.minDate.br_day && hour == self.minDate.br_hour) {
|
||||
startMinute = self.minDate.br_minute;
|
||||
}
|
||||
if (year == self.maxDate.br_year && month == self.maxDate.br_month && day == self.maxDate.br_day && hour == self.maxDate.br_hour) {
|
||||
endMinute = self.maxDate.br_minute;
|
||||
}
|
||||
NSMutableArray *tempArr = [[NSMutableArray alloc]init];
|
||||
for (NSInteger i = startMinute; i <= endMinute; i += self.minuteInterval) {
|
||||
[tempArr addObject:[self getMDHMSNumber:i]];
|
||||
}
|
||||
if (self.isDescending) {
|
||||
NSArray *reversedArr = [[tempArr reverseObjectEnumerator] allObjects];
|
||||
tempArr = [reversedArr mutableCopy];
|
||||
}
|
||||
// 判断是否需要添加【自定义字符串】
|
||||
if (self.lastRowContent || self.firstRowContent) {
|
||||
switch (self.pickerMode) {
|
||||
case BRDatePickerModeMS:
|
||||
{
|
||||
if (self.lastRowContent) {
|
||||
[tempArr addObject:self.lastRowContent];
|
||||
}
|
||||
if (self.firstRowContent) {
|
||||
[tempArr insertObject:self.firstRowContent atIndex:0];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return [tempArr copy];
|
||||
}
|
||||
|
||||
#pragma mark - 获取 secondArr 数组
|
||||
- (NSArray *)getSecondArr:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute {
|
||||
NSInteger startSecond = 0;
|
||||
NSInteger endSecond = 59;
|
||||
if (year == self.minDate.br_year && month == self.minDate.br_month && day == self.minDate.br_day && hour == self.minDate.br_hour && minute == self.minDate.br_minute) {
|
||||
startSecond = self.minDate.br_second;
|
||||
}
|
||||
if (year == self.maxDate.br_year && month == self.maxDate.br_month && day == self.maxDate.br_day && hour == self.maxDate.br_hour && minute == self.maxDate.br_minute) {
|
||||
endSecond = self.maxDate.br_second;
|
||||
}
|
||||
NSMutableArray *tempArr = [[NSMutableArray alloc]init];
|
||||
for (NSInteger i = startSecond; i <= endSecond; i += self.secondInterval) {
|
||||
[tempArr addObject:[self getMDHMSNumber:i]];
|
||||
}
|
||||
if (self.isDescending) {
|
||||
return [[tempArr reverseObjectEnumerator] allObjects];
|
||||
}
|
||||
|
||||
return [tempArr copy];
|
||||
}
|
||||
|
||||
#pragma mark - 获取 monthWeekArr 数组
|
||||
- (NSArray *)getMonthWeekArr:(NSInteger)year month:(NSInteger)month {
|
||||
NSInteger startWeek = 1;
|
||||
NSInteger endWeek = [NSDate br_getWeeksOfMonthInYear:year month:month];
|
||||
if (year == self.minDate.br_year && month == self.minDate.br_month) {
|
||||
startWeek = self.minDate.br_monthWeek;
|
||||
}
|
||||
if (year == self.maxDate.br_year && month == self.maxDate.br_month) {
|
||||
endWeek = self.maxDate.br_monthWeek;
|
||||
}
|
||||
NSMutableArray *tempArr = [[NSMutableArray alloc]init];
|
||||
for (NSInteger i = startWeek; i <= endWeek; i++) {
|
||||
[tempArr addObject:[self getMDHMSNumber:i]];
|
||||
}
|
||||
if (self.isDescending) {
|
||||
return [[tempArr reverseObjectEnumerator] allObjects];
|
||||
}
|
||||
|
||||
return [tempArr copy];
|
||||
}
|
||||
|
||||
#pragma mark - 获取 yearWeekArr 数组
|
||||
- (NSArray *)getYearWeekArr:(NSInteger)year {
|
||||
NSInteger startWeek = 1;
|
||||
NSInteger endWeek = [NSDate br_getWeeksOfYearInYear:year];
|
||||
if (year == self.minDate.br_year) {
|
||||
startWeek = self.minDate.br_yearWeek;
|
||||
}
|
||||
if (year == self.maxDate.br_year) {
|
||||
endWeek = self.maxDate.br_yearWeek;
|
||||
}
|
||||
NSMutableArray *tempArr = [[NSMutableArray alloc]init];
|
||||
for (NSInteger i = startWeek; i <= endWeek; i++) {
|
||||
[tempArr addObject:[self getMDHMSNumber:i]];
|
||||
}
|
||||
if (self.isDescending) {
|
||||
return [[tempArr reverseObjectEnumerator] allObjects];
|
||||
}
|
||||
|
||||
return [tempArr copy];
|
||||
}
|
||||
|
||||
#pragma mark - 获取 quarterArr 数组
|
||||
- (NSArray *)getQuarterArr:(NSInteger)year {
|
||||
NSInteger startQuarter = 1;
|
||||
NSInteger endQuarter = [NSDate br_getQuartersInYear:year];
|
||||
if (year == self.minDate.br_year) {
|
||||
startQuarter = self.minDate.br_quarter;
|
||||
}
|
||||
if (year == self.maxDate.br_year) {
|
||||
endQuarter = self.maxDate.br_quarter;
|
||||
}
|
||||
NSMutableArray *tempArr = [[NSMutableArray alloc]init];
|
||||
for (NSInteger i = startQuarter; i <= endQuarter; i++) {
|
||||
[tempArr addObject:[self getMDHMSNumber:i]];
|
||||
}
|
||||
if (self.isDescending) {
|
||||
return [[tempArr reverseObjectEnumerator] allObjects];
|
||||
}
|
||||
|
||||
return [tempArr copy];
|
||||
}
|
||||
|
||||
#pragma mark - 添加 pickerView
|
||||
- (void)setupPickerView:(UIView *)pickerView toView:(UIView *)view {
|
||||
if (view) {
|
||||
// 立即刷新容器视图 view 的布局(防止 view 使用自动布局时,选择器视图无法正常显示)
|
||||
[view setNeedsLayout];
|
||||
[view layoutIfNeeded];
|
||||
|
||||
self.frame = view.bounds;
|
||||
CGFloat pickerHeaderViewHeight = self.pickerHeaderView ? self.pickerHeaderView.bounds.size.height : 0;
|
||||
CGFloat pickerFooterViewHeight = self.pickerFooterView ? self.pickerFooterView.bounds.size.height : 0;
|
||||
pickerView.frame = CGRectMake(0, pickerHeaderViewHeight, view.bounds.size.width, view.bounds.size.height - pickerHeaderViewHeight - pickerFooterViewHeight);
|
||||
[self addSubview:pickerView];
|
||||
} else {
|
||||
// iOS16:重新设置 pickerView 高度(解决懒加载设置frame不生效问题)
|
||||
CGFloat pickerHeaderViewHeight = self.pickerHeaderView ? self.pickerHeaderView.bounds.size.height : 0;
|
||||
pickerView.frame = CGRectMake(0, self.pickerStyle.titleBarHeight + pickerHeaderViewHeight, self.keyView.bounds.size.width, self.pickerStyle.pickerHeight);
|
||||
|
||||
[self.alertView addSubview:pickerView];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 获取日期单位
|
||||
- (NSArray *)setupPickerUnitLabel:(UIPickerView *)pickerView unitArr:(NSArray *)unitArr {
|
||||
NSMutableArray *tempArr = [[NSMutableArray alloc]init];
|
||||
for (NSInteger i = 0; i < pickerView.numberOfComponents; i++) {
|
||||
CGFloat componentWidth = [self pickerView:pickerView widthForComponent:i];
|
||||
// 单位label
|
||||
UILabel *unitLabel = [[UILabel alloc]init];
|
||||
unitLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
|
||||
unitLabel.backgroundColor = [UIColor clearColor];
|
||||
unitLabel.font = self.pickerStyle.dateUnitTextFont;
|
||||
unitLabel.textColor = self.pickerStyle.dateUnitTextColor;
|
||||
// 字体自适应属性
|
||||
unitLabel.adjustsFontSizeToFitWidth = YES;
|
||||
// 自适应最小字体缩放比例
|
||||
unitLabel.minimumScaleFactor = 0.5f;
|
||||
unitLabel.text = (unitArr.count > 0 && i < unitArr.count) ? unitArr[i] : nil;
|
||||
[unitLabel sizeToFit];
|
||||
|
||||
// 根据占位文本长度去计算lable文本宽度
|
||||
NSString *tempText = @"00";
|
||||
if (i == 0) {
|
||||
switch (self.pickerMode) {
|
||||
case BRDatePickerModeYMDHMS:
|
||||
case BRDatePickerModeYMDHM:
|
||||
case BRDatePickerModeYMDH:
|
||||
case BRDatePickerModeYMD:
|
||||
case BRDatePickerModeYM:
|
||||
case BRDatePickerModeY:
|
||||
{
|
||||
tempText = @"0000";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 文本宽度
|
||||
CGFloat labelTextWidth = [tempText boundingRectWithSize:CGSizeMake(MAXFLOAT, self.pickerStyle.rowHeight)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
|
||||
attributes:@{NSFontAttributeName:self.pickerStyle.selectRowTextFont ?: self.pickerStyle.pickerTextFont}
|
||||
context:nil].size.width;
|
||||
CGFloat margin = (pickerView.frame.size.width - componentWidth * pickerView.numberOfComponents) / 2;
|
||||
CGFloat deltaX = (6 - pickerView.numberOfComponents) * 3 + 2;
|
||||
CGFloat centerX = margin + componentWidth / 2.0f + i * (componentWidth + 5) + labelTextWidth / 2.0f + deltaX + self.pickerStyle.dateUnitOffsetX;
|
||||
CGFloat centerY = pickerView.frame.origin.y + pickerView.frame.size.height / 2.0f + self.pickerStyle.dateUnitOffsetY;
|
||||
unitLabel.center = CGPointMake(centerX, centerY);
|
||||
[tempArr addObject:unitLabel];
|
||||
[pickerView.superview addSubview:unitLabel];
|
||||
}
|
||||
|
||||
return [tempArr copy];
|
||||
}
|
||||
|
||||
- (NSString *)getYearNumber:(NSInteger)year {
|
||||
NSString *yearString = [NSString stringWithFormat:@"%@", @(year)];
|
||||
if (self.isNumberFullName) {
|
||||
yearString = [NSString stringWithFormat:@"%04d", [yearString intValue]];
|
||||
}
|
||||
return yearString;
|
||||
}
|
||||
|
||||
- (NSString *)getMDHMSNumber:(NSInteger)number {
|
||||
NSString *string = [NSString stringWithFormat:@"%@", @(number)];
|
||||
if (self.isNumberFullName) {
|
||||
string = [NSString stringWithFormat:@"%02d", [string intValue]];
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
- (NSString *)getYearText:(NSArray *)yearArr row:(NSInteger)row {
|
||||
if (yearArr.count == 0) {
|
||||
return @"";
|
||||
}
|
||||
NSInteger index = 0;
|
||||
if (row >= 0) {
|
||||
index = MIN(row, yearArr.count - 1);
|
||||
}
|
||||
NSString *yearString = [yearArr objectAtIndex:index];
|
||||
if ((self.lastRowContent && [yearString isEqualToString:self.lastRowContent]) || (self.firstRowContent && [yearString isEqualToString:self.firstRowContent])) {
|
||||
return yearString;
|
||||
}
|
||||
NSString *yearUnit = self.showUnitType == BRShowUnitTypeAll ? [self getYearUnit] : @"";
|
||||
return [NSString stringWithFormat:@"%@%@", yearString, yearUnit];
|
||||
}
|
||||
|
||||
- (NSString *)getMonthText:(NSArray *)monthArr row:(NSInteger)row {
|
||||
if (monthArr.count == 0) {
|
||||
return @"";
|
||||
}
|
||||
NSInteger index = 0;
|
||||
if (row >= 0) {
|
||||
index = MIN(row, monthArr.count - 1);
|
||||
}
|
||||
NSString *monthString = [monthArr objectAtIndex:index];
|
||||
// 首行/末行是自定义字符串,直接返回
|
||||
if ((self.firstRowContent && [monthString isEqualToString:self.firstRowContent]) || (self.lastRowContent && [monthString isEqualToString:self.lastRowContent])) {
|
||||
return monthString;
|
||||
}
|
||||
|
||||
// 自定义月份数据源
|
||||
if (self.monthNames && self.monthNames.count > 0) {
|
||||
NSInteger index = [monthString integerValue] - 1;
|
||||
monthString = (index >= 0 && index < self.monthNames.count) ? self.monthNames[index] : @"";
|
||||
} else {
|
||||
if (![self.pickerStyle.language hasPrefix:@"zh"] && (self.pickerMode == BRDatePickerModeYMD || self.pickerMode == BRDatePickerModeYM || self.pickerMode == BRDatePickerModeYMW)) {
|
||||
// 非中文环境:月份使用系统的月份名称
|
||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
dateFormatter.locale = [[NSLocale alloc]initWithLocaleIdentifier:self.pickerStyle.language];
|
||||
// monthSymbols: @[@"January", @"February", @"March", @"April", @"May", @"June", @"July", @"August", @"September", @"October", @"November", @"December"];
|
||||
// shortMonthSymbols: @[@"Jan", @"Feb", @"Mar", @"Apr", @"May", @"Jun", @"Jul", @"Aug", @"Sep", @"Oct", @"Nov", @"Dec"];
|
||||
NSArray *monthNames = self.isShortMonthName ? dateFormatter.shortMonthSymbols : dateFormatter.monthSymbols;
|
||||
NSInteger index = [monthString integerValue] - 1;
|
||||
monthString = (index >= 0 && index < monthNames.count) ? monthNames[index] : @"";
|
||||
} else {
|
||||
// 中文环境:月份显示数字
|
||||
NSString *monthUnit = self.showUnitType == BRShowUnitTypeAll ? [self getMonthUnit] : @"";
|
||||
monthString = [NSString stringWithFormat:@"%@%@", monthString, monthUnit];
|
||||
}
|
||||
}
|
||||
|
||||
return monthString;
|
||||
}
|
||||
|
||||
- (NSString *)getDayText:(NSArray *)dayArr row:(NSInteger)row mSelectDate:(NSDate *)mSelectDate {
|
||||
if (dayArr.count == 0) {
|
||||
return @"";
|
||||
}
|
||||
NSInteger index = 0;
|
||||
if (row >= 0) {
|
||||
index = MIN(row, dayArr.count - 1);
|
||||
}
|
||||
NSString *dayString = [dayArr objectAtIndex:index];
|
||||
if (self.isShowToday && mSelectDate.br_year == [NSDate date].br_year && mSelectDate.br_month == [NSDate date].br_month && [dayString integerValue] == [NSDate date].br_day) {
|
||||
return [NSBundle br_localizedStringForKey:@"今天" language:self.pickerStyle.language];
|
||||
}
|
||||
NSString *dayUnit = self.showUnitType == BRShowUnitTypeAll ? [self getDayUnit] : @"";
|
||||
dayString = [NSString stringWithFormat:@"%@%@", dayString, dayUnit];
|
||||
if (self.isShowWeek) {
|
||||
NSDate *date = [NSDate br_setYear:mSelectDate.br_year month:mSelectDate.br_month day:[dayString integerValue]];
|
||||
NSString *weekdayString = [NSBundle br_localizedStringForKey:[date br_weekdayString] language:self.pickerStyle.language];
|
||||
dayString = [NSString stringWithFormat:@"%@%@", dayString, weekdayString];
|
||||
}
|
||||
return dayString;
|
||||
}
|
||||
|
||||
- (NSString *)getHourText:(NSArray *)hourArr row:(NSInteger)row {
|
||||
if (hourArr.count == 0) {
|
||||
return @"";
|
||||
}
|
||||
NSInteger index = 0;
|
||||
if (row >= 0) {
|
||||
index = MIN(row, hourArr.count - 1);
|
||||
}
|
||||
NSString *hourString = [hourArr objectAtIndex:index];
|
||||
if ((self.lastRowContent && [hourString isEqualToString:self.lastRowContent]) || (self.firstRowContent && [hourString isEqualToString:self.firstRowContent])) {
|
||||
return hourString;
|
||||
}
|
||||
NSString *hourUnit = self.showUnitType == BRShowUnitTypeAll ? [self getHourUnit] : @"";
|
||||
return [NSString stringWithFormat:@"%@%@", hourString, hourUnit];
|
||||
}
|
||||
|
||||
- (NSString *)getMinuteText:(NSArray *)minuteArr row:(NSInteger)row {
|
||||
if (minuteArr.count == 0) {
|
||||
return @"";
|
||||
}
|
||||
NSInteger index = 0;
|
||||
if (row >= 0) {
|
||||
index = MIN(row, minuteArr.count - 1);
|
||||
}
|
||||
NSString *minuteString = [minuteArr objectAtIndex:index];
|
||||
NSString *minuteUnit = self.showUnitType == BRShowUnitTypeAll ? [self getMinuteUnit] : @"";
|
||||
return [NSString stringWithFormat:@"%@%@", minuteString, minuteUnit];
|
||||
}
|
||||
|
||||
- (NSString *)getSecondText:(NSArray *)secondArr row:(NSInteger)row {
|
||||
if (secondArr.count == 0) {
|
||||
return @"";
|
||||
}
|
||||
NSInteger index = 0;
|
||||
if (row >= 0) {
|
||||
index = MIN(row, secondArr.count - 1);
|
||||
}
|
||||
NSString *secondString = [secondArr objectAtIndex:index];
|
||||
NSString *secondUnit = self.showUnitType == BRShowUnitTypeAll ? [self getSecondUnit] : @"";
|
||||
return [NSString stringWithFormat:@"%@%@", secondString, secondUnit];
|
||||
}
|
||||
|
||||
- (NSString *)getWeekText:(NSArray *)weekArr row:(NSInteger)row {
|
||||
if (weekArr.count == 0) {
|
||||
return @"";
|
||||
}
|
||||
NSInteger index = 0;
|
||||
if (row >= 0) {
|
||||
index = MIN(row, weekArr.count - 1);
|
||||
}
|
||||
NSString *weekString = [weekArr objectAtIndex:index];
|
||||
if ((self.lastRowContent && [weekString isEqualToString:self.lastRowContent]) || (self.firstRowContent && [weekString isEqualToString:self.firstRowContent])) {
|
||||
return weekString;
|
||||
}
|
||||
NSString *weekUnit = self.showUnitType == BRShowUnitTypeAll ? [self getWeekUnit] : @"";
|
||||
return [NSString stringWithFormat:@"%@%@", weekString, weekUnit];
|
||||
}
|
||||
|
||||
- (NSString *)getQuarterText:(NSArray *)quarterArr row:(NSInteger)row {
|
||||
if (quarterArr.count == 0) {
|
||||
return @"";
|
||||
}
|
||||
NSInteger index = 0;
|
||||
if (row >= 0) {
|
||||
index = MIN(row, quarterArr.count - 1);
|
||||
}
|
||||
NSString *quarterString = [quarterArr objectAtIndex:index];
|
||||
if ((self.lastRowContent && [quarterString isEqualToString:self.lastRowContent]) || (self.firstRowContent && [quarterString isEqualToString:self.firstRowContent])) {
|
||||
return quarterString;
|
||||
}
|
||||
NSString *quarterUnit = self.showUnitType == BRShowUnitTypeAll ? [self getQuarterUnit] : @"";
|
||||
return [NSString stringWithFormat:@"%@%@", quarterString, quarterUnit];
|
||||
}
|
||||
|
||||
- (NSString *)getAMText {
|
||||
return [NSBundle br_localizedStringForKey:@"上午" language:self.pickerStyle.language];
|
||||
}
|
||||
|
||||
- (NSString *)getPMText {
|
||||
return [NSBundle br_localizedStringForKey:@"下午" language:self.pickerStyle.language];
|
||||
}
|
||||
|
||||
- (NSString *)getYearUnit {
|
||||
if (self.customUnit) {
|
||||
return self.customUnit[@"year"] ? : @"";
|
||||
}
|
||||
if (![self.pickerStyle.language hasPrefix:@"zh"]) {
|
||||
return @"";
|
||||
}
|
||||
return [NSBundle br_localizedStringForKey:@"年" language:self.pickerStyle.language];
|
||||
}
|
||||
|
||||
- (NSString *)getMonthUnit {
|
||||
if (self.customUnit) {
|
||||
return self.customUnit[@"month"] ? : @"";
|
||||
}
|
||||
if (![self.pickerStyle.language hasPrefix:@"zh"]) {
|
||||
return @"";
|
||||
}
|
||||
return [NSBundle br_localizedStringForKey:@"月" language:self.pickerStyle.language];
|
||||
}
|
||||
|
||||
- (NSString *)getDayUnit {
|
||||
if (self.customUnit) {
|
||||
return self.customUnit[@"day"] ? : @"";
|
||||
}
|
||||
if (![self.pickerStyle.language hasPrefix:@"zh"]) {
|
||||
return @"";
|
||||
}
|
||||
return [NSBundle br_localizedStringForKey:@"日" language:self.pickerStyle.language];
|
||||
}
|
||||
|
||||
- (NSString *)getHourUnit {
|
||||
if (self.pickerMode == BRDatePickerModeYMDH && self.isShowAMAndPM) {
|
||||
return @"";
|
||||
}
|
||||
if (self.customUnit) {
|
||||
return self.customUnit[@"hour"] ? : @"";
|
||||
}
|
||||
if (![self.pickerStyle.language hasPrefix:@"zh"]) {
|
||||
return @"";
|
||||
}
|
||||
return [NSBundle br_localizedStringForKey:@"时" language:self.pickerStyle.language];
|
||||
}
|
||||
|
||||
- (NSString *)getMinuteUnit {
|
||||
if (self.customUnit) {
|
||||
return self.customUnit[@"minute"] ? : @"";
|
||||
}
|
||||
if (![self.pickerStyle.language hasPrefix:@"zh"]) {
|
||||
return @"";
|
||||
}
|
||||
return [NSBundle br_localizedStringForKey:@"分" language:self.pickerStyle.language];
|
||||
}
|
||||
|
||||
- (NSString *)getSecondUnit {
|
||||
if (self.customUnit) {
|
||||
return self.customUnit[@"second"] ? : @"";
|
||||
}
|
||||
if (![self.pickerStyle.language hasPrefix:@"zh"]) {
|
||||
return @"";
|
||||
}
|
||||
return [NSBundle br_localizedStringForKey:@"秒" language:self.pickerStyle.language];
|
||||
}
|
||||
|
||||
- (NSString *)getWeekUnit {
|
||||
if (self.customUnit) {
|
||||
return self.customUnit[@"week"] ? : @"";
|
||||
}
|
||||
if (![self.pickerStyle.language hasPrefix:@"zh"]) {
|
||||
return @"";
|
||||
}
|
||||
return [NSBundle br_localizedStringForKey:@"周" language:self.pickerStyle.language];
|
||||
}
|
||||
|
||||
- (NSString *)getQuarterUnit {
|
||||
if (self.customUnit) {
|
||||
return self.customUnit[@"quarter"] ? : @"";
|
||||
}
|
||||
if (![self.pickerStyle.language hasPrefix:@"zh"]) {
|
||||
return @"";
|
||||
}
|
||||
return [NSBundle br_localizedStringForKey:@"季度" language:self.pickerStyle.language];
|
||||
}
|
||||
|
||||
- (NSInteger)getIndexWithArray:(NSArray *)array object:(NSString *)obj {
|
||||
if (!array || array.count == 0 || !obj) {
|
||||
return 0;
|
||||
}
|
||||
if ([array containsObject:obj]) {
|
||||
return [array indexOfObject:obj];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
//
|
||||
// BRDatePickerView.h
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2017/8/11.
|
||||
// Copyright © 2017 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import "BRPickerAlertView.h"
|
||||
#import "NSDate+BRPickerView.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 日期选择器格式
|
||||
typedef NS_ENUM(NSInteger, BRDatePickerMode) {
|
||||
// ----- 以下4种是系统样式(兼容国际化日期格式) -----
|
||||
/** 【yyyy-MM-dd】UIDatePickerModeDate(美式日期:MM-dd-yyyy;英式日期:dd-MM-yyyy)*/
|
||||
BRDatePickerModeDate,
|
||||
/** 【yyyy-MM-dd HH:mm】 UIDatePickerModeDateAndTime */
|
||||
BRDatePickerModeDateAndTime,
|
||||
/** 【HH:mm】UIDatePickerModeTime */
|
||||
BRDatePickerModeTime,
|
||||
/** 【HH:mm】UIDatePickerModeCountDownTimer */
|
||||
BRDatePickerModeCountDownTimer,
|
||||
|
||||
// ----- 以下14种是自定义样式 -----
|
||||
/** 【yyyy-MM-dd HH:mm:ss】年月日时分秒 */
|
||||
BRDatePickerModeYMDHMS,
|
||||
/** 【yyyy-MM-dd HH:mm】年月日时分 */
|
||||
BRDatePickerModeYMDHM,
|
||||
/** 【yyyy-MM-dd HH】年月日时 */
|
||||
BRDatePickerModeYMDH,
|
||||
/** 【MM-dd HH:mm】月日时分 */
|
||||
BRDatePickerModeMDHM,
|
||||
/** 【yyyy-MM-dd】年月日(兼容国际化日期:dd-MM-yyyy)*/
|
||||
BRDatePickerModeYMD,
|
||||
/** 【yyyy-MM】年月(兼容国际化日期:MM-yyyy)*/
|
||||
BRDatePickerModeYM,
|
||||
/** 【yyyy】年 */
|
||||
BRDatePickerModeY,
|
||||
/** 【MM-dd】月日 */
|
||||
BRDatePickerModeMD,
|
||||
/** 【HH:mm:ss】时分秒 */
|
||||
BRDatePickerModeHMS,
|
||||
/** 【HH:mm】时分 */
|
||||
BRDatePickerModeHM,
|
||||
/** 【mm:ss】分秒 */
|
||||
BRDatePickerModeMS,
|
||||
|
||||
/** 【yyyy-qq】年季度 */
|
||||
BRDatePickerModeYQ,
|
||||
/** 【yyyy-MM-ww】年月周 */
|
||||
BRDatePickerModeYMW,
|
||||
/** 【yyyy-ww】年周 */
|
||||
BRDatePickerModeYW
|
||||
};
|
||||
|
||||
/// 日期单位显示的位置
|
||||
typedef NS_ENUM(NSInteger, BRShowUnitType) {
|
||||
/** 日期单位显示全部行(默认)*/
|
||||
BRShowUnitTypeAll,
|
||||
/** 日期单位仅显示中间行 */
|
||||
BRShowUnitTypeOnlyCenter,
|
||||
/** 日期单位不显示(隐藏日期单位)*/
|
||||
BRShowUnitTypeNone
|
||||
};
|
||||
|
||||
typedef void (^BRDateResultBlock)(NSDate * _Nullable selectDate, NSString * _Nullable selectValue);
|
||||
|
||||
typedef void (^BRDateResultRangeBlock)(NSDate * _Nullable selectStartDate, NSDate * _Nullable selectEndDate, NSString * _Nullable selectValue);
|
||||
|
||||
@interface BRDatePickerView : BRPickerAlertView
|
||||
|
||||
/**
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// 【用法一】
|
||||
/// 特点:灵活,扩展性强(推荐使用!)
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/** 日期选择器显示类型 */
|
||||
@property (nonatomic, assign) BRDatePickerMode pickerMode;
|
||||
|
||||
/** 设置选中的日期(推荐使用 selectDate) */
|
||||
@property (nullable, nonatomic, strong) NSDate *selectDate;
|
||||
@property (nullable, nonatomic, copy) NSString *selectValue;
|
||||
|
||||
/** 最小日期(可使用 NSDate+BRPickerView 分类中对应的方法进行创建)*/
|
||||
@property (nullable, nonatomic, strong) NSDate *minDate;
|
||||
/** 最大日期(可使用 NSDate+BRPickerView 分类中对应的方法进行创建)*/
|
||||
@property (nullable, nonatomic, strong) NSDate *maxDate;
|
||||
|
||||
/** 是否自动选择,即滚动选择器后就执行结果回调,默认为 NO */
|
||||
@property (nonatomic, assign) BOOL isAutoSelect;
|
||||
|
||||
/** 选择结果的回调 */
|
||||
@property (nullable, nonatomic, copy) BRDateResultBlock resultBlock;
|
||||
/** 选择结果范围的回调:for `BRDatePickerModeYQ`、`BRDatePickerModeYMW`、`BRDatePickerModeYW`, ignored otherwise. */
|
||||
@property (nullable, nonatomic, copy) BRDateResultRangeBlock resultRangeBlock;
|
||||
|
||||
/** 滚动选择时触发的回调 */
|
||||
@property (nullable, nonatomic, copy) BRDateResultBlock changeBlock;
|
||||
/** 滚动选择范围时触发的回调:for `BRDatePickerModeYQ`、`BRDatePickerModeYMW`、`BRDatePickerModeYW`, ignored otherwise. */
|
||||
@property (nullable, nonatomic, copy) BRDateResultRangeBlock changeRangeBlock;
|
||||
|
||||
/** 判断选择器是否处于滚动中。可以用于解决快速滑动选择器,在滚动结束前秒选确定按钮,出现显示不对的问题。*/
|
||||
@property (nonatomic, readonly, assign, getter=isRolling) BOOL rolling;
|
||||
|
||||
/** 日期单位显示类型 */
|
||||
@property (nonatomic, assign) BRShowUnitType showUnitType;
|
||||
|
||||
/** 是否显示【星期】,默认为 NO */
|
||||
@property (nonatomic, assign, getter=isShowWeek) BOOL showWeek;
|
||||
|
||||
/** 是否显示【今天】,默认为 NO */
|
||||
@property (nonatomic, assign, getter=isShowToday) BOOL showToday;
|
||||
|
||||
/** 是否添加【至今】,默认为 NO */
|
||||
@property (nonatomic, assign, getter=isAddToNow) BOOL addToNow;
|
||||
|
||||
/** 首行添加 自定义字符串,配合 selectValue 可设置默认选中 */
|
||||
@property (nullable, nonatomic, copy) NSString *firstRowContent;
|
||||
|
||||
/** 末行添加 自定义字符串(如:至今),配合 selectValue 可设置默认选中 */
|
||||
@property (nullable, nonatomic, copy) NSString *lastRowContent;
|
||||
|
||||
/** 滚轮上日期数据排序是否降序,默认为 NO(升序)*/
|
||||
@property (nonatomic, assign, getter=isDescending) BOOL descending;
|
||||
|
||||
/** 选择器上数字是否带有前导零,默认为 NO(如:无前导零:2020-1-1;有前导零:2020-01-01)*/
|
||||
@property (nonatomic, assign, getter=isNumberFullName) BOOL numberFullName;
|
||||
|
||||
/** 是否为12小时制,默认为NO */
|
||||
@property (nonatomic, assign, getter=isTwelveHourMode) BOOL twelveHourMode;
|
||||
|
||||
/** 设置分的时间间隔,默认为1(范围:1 ~ 30)*/
|
||||
@property (nonatomic, assign) NSInteger minuteInterval;
|
||||
|
||||
/** 设置秒的时间间隔,默认为1(范围:1 ~ 30)*/
|
||||
@property (nonatomic, assign) NSInteger secondInterval;
|
||||
|
||||
/** 设置倒计时的时长,默认为0(范围:0 ~ 24*60*60-1,单位为秒) for `BRDatePickerModeCountDownTimer`, ignored otherwise. */
|
||||
@property (nonatomic, assign) NSTimeInterval countDownDuration;
|
||||
|
||||
/**
|
||||
* 自定义月份数据源
|
||||
* 如:@[@"1月", @"2月",..., @"12月"]、 @[@"一月", @"二月",..., @"十二月"]、 @[@"Jan", @"Feb",..., @"Dec"] 等
|
||||
*/
|
||||
@property (nonatomic, copy) NSArray <NSString *> *monthNames;
|
||||
|
||||
/**
|
||||
* 设置国际化日期(非中文环境下)月份是否显示简称,默认为 NO。for `BRDatePickerModeYMD` and `BRDatePickerModeYM`, ignored otherwise.
|
||||
* 如:January 的简称为:Jan
|
||||
*/
|
||||
@property (nonatomic, assign, getter=isShortMonthName) BOOL shortMonthName;
|
||||
|
||||
/**
|
||||
* 自定义日期单位
|
||||
* 字典格式:@{@"year": @"年", @"month": @"月", @"day": @"日", @"hour": @"时", @"minute": @"分", @"second": @"秒"}
|
||||
*/
|
||||
@property (nonatomic, copy) NSDictionary *customUnit;
|
||||
|
||||
/** 显示上午和下午,默认为 NO. for `BRDatePickerModeYMDH`, ignored otherwise. */
|
||||
@property (nonatomic, assign, getter=isShowAMAndPM) BOOL showAMAndPM;
|
||||
|
||||
/**
|
||||
* 设置时区,默认为当前时区
|
||||
* 如:timeZone = [NSTimeZone timeZoneWithName:@"America/New_York"]; // 如:设置时区为 美国纽约
|
||||
* 特别提示:如果有设置自定义时区,需要把有使用 NSDate+BRPickerView 分类中方法的代码(如:设置minDate、maxDate等) 放在设置时区代码的后面,目的是同步时区设置到 NSDate+BRPickerView 分类中
|
||||
*/
|
||||
@property (nullable, nonatomic, copy) NSTimeZone *timeZone;
|
||||
|
||||
/**
|
||||
* 设置日历对象,可以指定日历的算法。default is [NSCalendar currentCalendar]. setting nil returns to default. for `UIDatePicker`, ignored otherwise.
|
||||
* 如:calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierChinese]; // 设置中国农历(阴历)日期
|
||||
*/
|
||||
@property (nullable, nonatomic, copy) NSCalendar *calendar;
|
||||
|
||||
/** 指定不允许选择的日期 */
|
||||
@property (nullable, nonatomic, copy) NSArray <NSDate *> *nonSelectableDates;
|
||||
|
||||
/** 不允许选择日期的回调 */
|
||||
@property (nullable, nonatomic, copy) BRDateResultBlock nonSelectableBlock;
|
||||
|
||||
/// 初始化日期选择器
|
||||
/// @param pickerMode 日期选择器显示类型
|
||||
- (instancetype)initWithPickerMode:(BRDatePickerMode)pickerMode;
|
||||
|
||||
/// 弹出选择器视图
|
||||
- (void)show;
|
||||
|
||||
/// 关闭选择器视图
|
||||
- (void)dismiss;
|
||||
|
||||
|
||||
|
||||
|
||||
//================================================= 华丽的分割线 =================================================
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// 【用法二】:快捷使用,直接选择下面其中的一个方法进行使用
|
||||
/// 特点:快捷,方便
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* 1.显示日期选择器
|
||||
*
|
||||
* @param mode 日期显示类型
|
||||
* @param title 选择器标题
|
||||
* @param selectValue 默认选中的日期(默认选中当前日期)
|
||||
* @param resultBlock 选择结果的回调
|
||||
*
|
||||
*/
|
||||
+ (void)showDatePickerWithMode:(BRDatePickerMode)mode
|
||||
title:(nullable NSString *)title
|
||||
selectValue:(nullable NSString *)selectValue
|
||||
resultBlock:(nullable BRDateResultBlock)resultBlock;
|
||||
|
||||
/**
|
||||
* 2.显示日期选择器
|
||||
*
|
||||
* @param mode 日期显示类型
|
||||
* @param title 选择器标题
|
||||
* @param selectValue 默认选中的日期(默认选中当前日期)
|
||||
* @param isAutoSelect 是否自动选择,即滚动选择器后就执行结果回调,默认为 NO
|
||||
* @param resultBlock 选择结果的回调
|
||||
*
|
||||
*/
|
||||
+ (void)showDatePickerWithMode:(BRDatePickerMode)mode
|
||||
title:(nullable NSString *)title
|
||||
selectValue:(nullable NSString *)selectValue
|
||||
isAutoSelect:(BOOL)isAutoSelect
|
||||
resultBlock:(nullable BRDateResultBlock)resultBlock;
|
||||
|
||||
/**
|
||||
* 3.显示日期选择器
|
||||
*
|
||||
* @param mode 日期显示类型
|
||||
* @param title 选择器标题
|
||||
* @param selectValue 默认选中的日期(默认选中当前日期)
|
||||
* @param minDate 最小日期(可使用 NSDate+BRPickerView 分类中对应的方法进行创建)
|
||||
* @param maxDate 最大日期(可使用 NSDate+BRPickerView 分类中对应的方法进行创建)
|
||||
* @param isAutoSelect 是否自动选择,即滚动选择器后就执行结果回调,默认为 NO
|
||||
* @param resultBlock 选择结果的回调
|
||||
*
|
||||
*/
|
||||
+ (void)showDatePickerWithMode:(BRDatePickerMode)mode
|
||||
title:(nullable NSString *)title
|
||||
selectValue:(nullable NSString *)selectValue
|
||||
minDate:(nullable NSDate *)minDate
|
||||
maxDate:(nullable NSDate *)maxDate
|
||||
isAutoSelect:(BOOL)isAutoSelect
|
||||
resultBlock:(nullable BRDateResultBlock)resultBlock;
|
||||
|
||||
/**
|
||||
* 4.显示日期选择器
|
||||
*
|
||||
* @param mode 日期显示类型
|
||||
* @param title 选择器标题
|
||||
* @param selectValue 默认选中的日期(默认选中当前日期)
|
||||
* @param minDate 最小日期(可使用 NSDate+BRPickerView 分类中对应的方法进行创建)
|
||||
* @param maxDate 最大日期(可使用 NSDate+BRPickerView 分类中对应的方法进行创建)
|
||||
* @param isAutoSelect 是否自动选择,即滚动选择器后就执行结果回调,默认为 NO
|
||||
* @param resultBlock 选择结果的回调
|
||||
* @param resultRangeBlock 范围选择结果的回调
|
||||
*
|
||||
*/
|
||||
+ (void)showDatePickerWithMode:(BRDatePickerMode)mode
|
||||
title:(nullable NSString *)title
|
||||
selectValue:(nullable NSString *)selectValue
|
||||
minDate:(nullable NSDate *)minDate
|
||||
maxDate:(nullable NSDate *)maxDate
|
||||
isAutoSelect:(BOOL)isAutoSelect
|
||||
resultBlock:(nullable BRDateResultBlock)resultBlock
|
||||
resultRangeBlock:(nullable BRDateResultRangeBlock)resultRangeBlock;
|
||||
|
||||
|
||||
// 获取列宽(组件内部方法)
|
||||
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
//
|
||||
// NSDate+BRPickerView.h
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2018/3/15.
|
||||
// Copyright © 2018 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@interface NSDate (BRPickerView)
|
||||
|
||||
/// ---------------- 设置【日历对象】和【时区】 ----------------
|
||||
/** 设置日历对象 */
|
||||
+ (void)br_setCalendar:(NSCalendar *)calendar;
|
||||
/** 获取日历对象 */
|
||||
+ (NSCalendar *)br_getCalendar;
|
||||
|
||||
/** 设置时区 */
|
||||
+ (void)br_setTimeZone:(NSTimeZone *)timeZone;
|
||||
/** 获取当前时区 */
|
||||
+ (NSTimeZone *)br_getTimeZone;
|
||||
|
||||
/// 获取指定date的详细信息
|
||||
@property (readonly) NSInteger br_year; // 年
|
||||
@property (readonly) NSInteger br_month; // 月
|
||||
@property (readonly) NSInteger br_day; // 日
|
||||
@property (readonly) NSInteger br_hour; // 时
|
||||
@property (readonly) NSInteger br_minute; // 分
|
||||
@property (readonly) NSInteger br_second; // 秒
|
||||
@property (readonly) NSInteger br_weekday; // 星期
|
||||
@property (readonly) NSInteger br_monthWeek; // 月周
|
||||
@property (readonly) NSInteger br_yearWeek; // 年周
|
||||
@property (readonly) NSInteger br_quarter; // 季度
|
||||
|
||||
/** 获取中文星期字符串 */
|
||||
@property (nullable, nonatomic, readonly, copy) NSString *br_weekdayString;
|
||||
|
||||
/// ---------------- 创建 date ----------------
|
||||
/** yyyy */
|
||||
+ (nullable NSDate *)br_setYear:(NSInteger)year;
|
||||
|
||||
/** yyyy-MM */
|
||||
+ (nullable NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month;
|
||||
|
||||
/** yyyy-MM-dd */
|
||||
+ (nullable NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day;
|
||||
|
||||
/** yyyy-MM-dd HH */
|
||||
+ (nullable NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour;
|
||||
|
||||
/** yyyy-MM-dd HH:mm */
|
||||
+ (nullable NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute;
|
||||
|
||||
/** yyyy-MM-dd HH:mm:ss */
|
||||
+ (nullable NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)second;
|
||||
|
||||
/** MM-dd HH:mm */
|
||||
+ (nullable NSDate *)br_setMonth:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute;
|
||||
|
||||
/** MM-dd */
|
||||
+ (nullable NSDate *)br_setMonth:(NSInteger)month day:(NSInteger)day;
|
||||
|
||||
/** HH:mm:ss */
|
||||
+ (nullable NSDate *)br_setHour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)second;
|
||||
|
||||
/** HH:mm */
|
||||
+ (nullable NSDate *)br_setHour:(NSInteger)hour minute:(NSInteger)minute;
|
||||
|
||||
/** mm:ss */
|
||||
+ (nullable NSDate *)br_setMinute:(NSInteger)minute second:(NSInteger)second;
|
||||
|
||||
/** yyyy-MM-ww */
|
||||
+ (nullable NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month weekOfMonth:(NSInteger)weekOfMont;
|
||||
|
||||
/** yyyy-ww */
|
||||
+ (nullable NSDate *)br_setYear:(NSInteger)year weekOfYear:(NSInteger)weekOfYear;
|
||||
|
||||
/** yyyy-qq */
|
||||
+ (nullable NSDate *)br_setYear:(NSInteger)year quarter:(NSInteger)quarter;
|
||||
|
||||
/** 设置12小时制时的hour值 */
|
||||
- (NSDate *)br_setTwelveHour:(NSInteger)hour;
|
||||
|
||||
/** 获取某个月的天数(通过年月求每月天数)*/
|
||||
+ (NSUInteger)br_getDaysInYear:(NSInteger)year month:(NSInteger)month;
|
||||
|
||||
/** 获取某个月的周数(通过年月求该月周数)*/
|
||||
+ (NSUInteger)br_getWeeksOfMonthInYear:(NSInteger)year month:(NSInteger)month;
|
||||
|
||||
/** 获取某一年的周数(通过年求该年周数)*/
|
||||
+ (NSUInteger)br_getWeeksOfYearInYear:(NSInteger)year;
|
||||
|
||||
/** 获取某一年的季度数(通过年求该年季度数)*/
|
||||
+ (NSUInteger)br_getQuartersInYear:(NSInteger)year;
|
||||
|
||||
/** 获取 日期加上/减去某天数后的新日期 */
|
||||
- (nullable NSDate *)br_getNewDateToDays:(NSTimeInterval)days;
|
||||
|
||||
/** 获取 日期加上/减去某个月数后的新日期 */
|
||||
- (nullable NSDate *)br_getNewDateToMonths:(NSTimeInterval)months;
|
||||
|
||||
/** NSDate 转 NSString(使用系统默认 时区 和 语言)*/
|
||||
+ (nullable NSString *)br_stringFromDate:(NSDate *)date dateFormat:(NSString *)dateFormat;
|
||||
/** NSDate 转 NSString */
|
||||
+ (nullable NSString *)br_stringFromDate:(NSDate *)date
|
||||
dateFormat:(NSString *)dateFormat
|
||||
language:(nullable NSString *)language;
|
||||
|
||||
/** NSString 转 NSDate(使用系统默认 时区 和 语言)*/
|
||||
+ (nullable NSDate *)br_dateFromString:(NSString *)dateString dateFormat:(NSString *)dateFormat;
|
||||
/** NSString 转 NSDate */
|
||||
+ (nullable NSDate *)br_dateFromString:(NSString *)dateString
|
||||
dateFormat:(NSString *)dateFormat
|
||||
language:(nullable NSString *)language;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
@ -0,0 +1,398 @@
|
|||
//
|
||||
// NSDate+BRPickerView.m
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2018/3/15.
|
||||
// Copyright © 2018 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import "NSDate+BRPickerView.h"
|
||||
#import "BRPickerViewMacro.h"
|
||||
|
||||
BRSYNTH_DUMMY_CLASS(NSDate_BRPickerView)
|
||||
|
||||
static const NSCalendarUnit unitFlags = (NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitWeekOfYear | NSCalendarUnitWeekOfMonth | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitWeekday | NSCalendarUnitWeekdayOrdinal | NSCalendarUnitQuarter);
|
||||
|
||||
@implementation NSDate (BRPickerView)
|
||||
|
||||
/// 日历对象
|
||||
static NSCalendar *_sharedCalendar = nil;
|
||||
/// 时区
|
||||
static NSTimeZone *_timeZone = nil;
|
||||
|
||||
/// ---------------- 设置【日历对象】和【时区】 ----------------
|
||||
#pragma mark - 设置日历对象
|
||||
+ (void)br_setCalendar:(NSCalendar *)calendar {
|
||||
_sharedCalendar = calendar;
|
||||
}
|
||||
|
||||
#pragma mark - 获取日历对象
|
||||
+ (NSCalendar *)br_getCalendar {
|
||||
if (!_sharedCalendar) {
|
||||
// 创建日历对象,指定日历的算法(公历/阳历)
|
||||
_sharedCalendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
|
||||
}
|
||||
return _sharedCalendar;
|
||||
}
|
||||
|
||||
#pragma mark - 设置时区
|
||||
+ (void)br_setTimeZone:(NSTimeZone *)timeZone {
|
||||
_timeZone = timeZone;
|
||||
// 同步日历对象时区设置
|
||||
[self br_getCalendar].timeZone = timeZone;
|
||||
}
|
||||
|
||||
#pragma mark - 获取当前时区
|
||||
+ (NSTimeZone *)br_getTimeZone {
|
||||
if (!_timeZone) {
|
||||
// 当前时区
|
||||
NSTimeZone *localTimeZone = [NSTimeZone localTimeZone];
|
||||
// 当前时区相对于GMT(零时区)的偏移秒数
|
||||
NSInteger interval = [localTimeZone secondsFromGMTForDate:[NSDate date]];
|
||||
// 当前时区(不使用夏时制):由偏移量获得对应的NSTimeZone对象
|
||||
// 注意:一些夏令时时间 NSString 转 NSDate 时,默认会导致 NSDateFormatter 格式化失败,返回 null
|
||||
_timeZone = [NSTimeZone timeZoneForSecondsFromGMT:interval];
|
||||
}
|
||||
return _timeZone;
|
||||
}
|
||||
|
||||
#pragma mark - NSDate 转 NSDateComponents
|
||||
+ (NSDateComponents *)br_componentsFromDate:(NSDate *)date {
|
||||
// 通过日历类 NSCalendar 进行转换
|
||||
NSCalendar *calendar = [self br_getCalendar];
|
||||
// NSDateComponents 可以获得日期的详细信息,即日期的组成
|
||||
return [calendar components:unitFlags fromDate:date];
|
||||
}
|
||||
|
||||
#pragma mark - NSDateComponents 转 NSDate
|
||||
+ (NSDate *)br_dateFromComponents:(NSDateComponents *)components {
|
||||
// 通过日历类 NSCalendar 进行转换
|
||||
NSCalendar *calendar = [self br_getCalendar];
|
||||
return [calendar dateFromComponents:components];
|
||||
}
|
||||
|
||||
#pragma mark - 获取指定日期的年份
|
||||
- (NSInteger)br_year {
|
||||
return [NSDate br_componentsFromDate:self].year;
|
||||
}
|
||||
|
||||
#pragma mark - 获取指定日期的月份
|
||||
- (NSInteger)br_month {
|
||||
return [NSDate br_componentsFromDate:self].month;
|
||||
}
|
||||
|
||||
#pragma mark - 获取指定日期的天
|
||||
- (NSInteger)br_day {
|
||||
return [NSDate br_componentsFromDate:self].day;
|
||||
}
|
||||
|
||||
#pragma mark - 获取指定日期的小时
|
||||
- (NSInteger)br_hour {
|
||||
return [NSDate br_componentsFromDate:self].hour;
|
||||
}
|
||||
|
||||
#pragma mark - 获取指定日期的分钟
|
||||
- (NSInteger)br_minute {
|
||||
return [NSDate br_componentsFromDate:self].minute;
|
||||
}
|
||||
|
||||
#pragma mark - 获取指定日期的秒
|
||||
- (NSInteger)br_second {
|
||||
return [NSDate br_componentsFromDate:self].second;
|
||||
}
|
||||
|
||||
#pragma mark - 获取指定日期的星期
|
||||
- (NSInteger)br_weekday {
|
||||
return [NSDate br_componentsFromDate:self].weekday;
|
||||
}
|
||||
|
||||
#pragma mark - 获取指定日期的月周
|
||||
- (NSInteger)br_monthWeek {
|
||||
return [NSDate br_componentsFromDate:self].weekOfMonth;
|
||||
}
|
||||
|
||||
#pragma mark - 获取指定日期的年周
|
||||
- (NSInteger)br_yearWeek {
|
||||
return [NSDate br_componentsFromDate:self].weekOfYear;
|
||||
}
|
||||
|
||||
#pragma mark - 获取指定日期的季度
|
||||
- (NSInteger)br_quarter {
|
||||
// [NSDate br_componentsFromDate:self].quarter; // 取到的季度值总是0?
|
||||
NSInteger quarter = 1;
|
||||
NSInteger month = self.br_month;
|
||||
if (month > 3) quarter = 2;
|
||||
if (month > 6) quarter = 3;
|
||||
if (month > 9) quarter = 4;
|
||||
|
||||
return quarter;
|
||||
}
|
||||
|
||||
#pragma mark - 获取指定日期的星期
|
||||
- (NSString *)br_weekdayString {
|
||||
switch (self.br_weekday - 1) {
|
||||
case 0:
|
||||
{
|
||||
return @"周日";
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
return @"周一";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
return @"周二";
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
return @"周三";
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
return @"周四";
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
return @"周五";
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
return @"周六";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return @"";
|
||||
}
|
||||
|
||||
/// ---------------- 创建 date ----------------
|
||||
#pragma mark - 创建date(通过 NSCalendar 类来创建日期)
|
||||
+ (NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)second {
|
||||
return [self br_setYear:year month:month day:day hour:hour minute:minute second:second weekOfMonth:0 weekOfYear:0 quarter:0];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day
|
||||
hour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)second
|
||||
weekOfMonth:(NSInteger)weekOfMonth weekOfYear:(NSInteger)weekOfYear quarter:(NSInteger)quarter {
|
||||
NSDateComponents *components = [self br_componentsFromDate:[NSDate date]];
|
||||
if (year > 0) {
|
||||
// 初始化日期组件
|
||||
components = [[NSDateComponents alloc]init];
|
||||
components.year = year;
|
||||
}
|
||||
if (month > 0) {
|
||||
components.month = month;
|
||||
}
|
||||
if (day > 0) {
|
||||
components.day = day;
|
||||
}
|
||||
if (hour >= 0) {
|
||||
components.hour = hour;
|
||||
}
|
||||
if (minute >= 0) {
|
||||
components.minute = minute;
|
||||
}
|
||||
if (second >= 0) {
|
||||
components.second = second;
|
||||
}
|
||||
if (weekOfMonth > 0) {
|
||||
components.weekOfMonth = weekOfMonth;
|
||||
}
|
||||
if (weekOfYear > 0) {
|
||||
components.weekOfYear = weekOfYear;
|
||||
}
|
||||
if (quarter > 0) {
|
||||
components.quarter = quarter;
|
||||
}
|
||||
|
||||
return [self br_dateFromComponents:components];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute {
|
||||
return [self br_setYear:year month:month day:day hour:hour minute:minute second:0];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour {
|
||||
return [self br_setYear:year month:month day:day hour:hour minute:0 second:0];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day {
|
||||
return [self br_setYear:year month:month day:day hour:0 minute:0 second:0];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month {
|
||||
return [self br_setYear:year month:month day:0 hour:0 minute:0 second:0];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setYear:(NSInteger)year {
|
||||
return [self br_setYear:year month:0 day:0 hour:0 minute:0 second:0];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setMonth:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute {
|
||||
return [self br_setYear:0 month:month day:day hour:hour minute:minute second:0];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setMonth:(NSInteger)month day:(NSInteger)day {
|
||||
return [self br_setYear:0 month:month day:day hour:0 minute:0 second:0];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setHour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)second {
|
||||
return [self br_setYear:0 month:0 day:0 hour:hour minute:minute second:second];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setHour:(NSInteger)hour minute:(NSInteger)minute {
|
||||
return [self br_setYear:0 month:0 day:0 hour:hour minute:minute second:0];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setMinute:(NSInteger)minute second:(NSInteger)second {
|
||||
return [self br_setYear:0 month:0 day:0 hour:0 minute:minute second:second];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setYear:(NSInteger)year month:(NSInteger)month weekOfMonth:(NSInteger)weekOfMonth {
|
||||
return [self br_setYear:year month:month day:0 hour:0 minute:0 second:0 weekOfMonth:weekOfMonth weekOfYear:0 quarter:0];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setYear:(NSInteger)year weekOfYear:(NSInteger)weekOfYear {
|
||||
return [self br_setYear:year month:0 day:0 hour:0 minute:0 second:0 weekOfMonth:0 weekOfYear:weekOfYear quarter:0];
|
||||
}
|
||||
|
||||
+ (NSDate *)br_setYear:(NSInteger)year quarter:(NSInteger)quarter {
|
||||
return [self br_setYear:year month:0 day:0 hour:0 minute:0 second:0 weekOfMonth:0 weekOfYear:0 quarter:quarter];
|
||||
}
|
||||
|
||||
- (NSDate *)br_setTwelveHour:(NSInteger)hour {
|
||||
NSDateComponents *components = [NSDate br_componentsFromDate:self];
|
||||
if (hour >= 0) {
|
||||
components.hour = hour;
|
||||
}
|
||||
return [NSDate br_dateFromComponents:components];
|
||||
}
|
||||
|
||||
#pragma mark - 获取某个月的天数(通过年月求每月天数)
|
||||
+ (NSUInteger)br_getDaysInYear:(NSInteger)year month:(NSInteger)month {
|
||||
BOOL isLeapYear = year % 4 == 0 ? (year % 100 == 0 ? (year % 400 == 0 ? YES : NO) : YES) : NO;
|
||||
switch (month) {
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
{
|
||||
return 31;
|
||||
}
|
||||
case 4:
|
||||
case 6:
|
||||
case 9:
|
||||
case 11:
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (isLeapYear) {
|
||||
return 29;
|
||||
} else {
|
||||
return 28;
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma mark - 获取某个月的周数(通过年月求该月周数)
|
||||
+ (NSUInteger)br_getWeeksOfMonthInYear:(NSInteger)year month:(NSInteger)month {
|
||||
NSUInteger lastDayOfMonth = [self br_getDaysInYear:year month:month];
|
||||
NSDate *endDate = [self br_setYear:year month:month day:lastDayOfMonth];
|
||||
return endDate.br_monthWeek;
|
||||
}
|
||||
|
||||
#pragma mark - 获取某一年的周数(通过年求该年周数)
|
||||
+ (NSUInteger)br_getWeeksOfYearInYear:(NSInteger)year {
|
||||
NSDate *endDate = [self br_setYear:year month:12 day:31];
|
||||
NSInteger weeks = endDate.br_yearWeek;
|
||||
if (weeks == 1) weeks = 52;
|
||||
return weeks;
|
||||
}
|
||||
|
||||
#pragma mark - 获取某一年的季度数(通过年求该年季度数)
|
||||
+ (NSUInteger)br_getQuartersInYear:(NSInteger)year {
|
||||
NSDate *endDate = [self br_setYear:year month:12 day:31];
|
||||
return endDate.br_quarter;
|
||||
}
|
||||
|
||||
#pragma mark - 获取 日期加上/减去某天数后的新日期
|
||||
- (NSDate *)br_getNewDateToDays:(NSTimeInterval)days {
|
||||
// days 为正数时,表示几天之后的日期;负数表示几天之前的日期
|
||||
return [self dateByAddingTimeInterval:60 * 60 * 24 * days];
|
||||
}
|
||||
|
||||
#pragma mark - 获取 日期加上/减去某个月数后的新日期
|
||||
- (nullable NSDate *)br_getNewDateToMonths:(NSTimeInterval)months {
|
||||
// months 为正数时,表示几个月之后的日期;负数表示几个月之前的日期
|
||||
NSDateComponents *components = [[NSDateComponents alloc] init];
|
||||
[components setMonth:months];
|
||||
NSCalendar *calender = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
|
||||
return [calender dateByAddingComponents:components toDate:self options:0];
|
||||
}
|
||||
|
||||
#pragma mark - NSDate 转 NSString
|
||||
+ (NSString *)br_stringFromDate:(NSDate *)date dateFormat:(NSString *)dateFormat {
|
||||
return [self br_stringFromDate:date dateFormat:dateFormat language:nil];
|
||||
}
|
||||
#pragma mark - NSDate 转 NSString
|
||||
+ (NSString *)br_stringFromDate:(NSDate *)date
|
||||
dateFormat:(NSString *)dateFormat
|
||||
language:(NSString *)language {
|
||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
// 设置日期格式
|
||||
dateFormatter.dateFormat = dateFormat;
|
||||
// NSDateFormatter 设置时区 ,不设置默认为系统时区
|
||||
dateFormatter.timeZone = [self br_getTimeZone];
|
||||
if (!language) {
|
||||
language = [NSLocale preferredLanguages].firstObject;
|
||||
}
|
||||
dateFormatter.locale = [[NSLocale alloc]initWithLocaleIdentifier:language];
|
||||
NSString *dateString = [dateFormatter stringFromDate:date];
|
||||
|
||||
return dateString;
|
||||
}
|
||||
|
||||
#pragma mark - NSString 转 NSDate
|
||||
+ (NSDate *)br_dateFromString:(NSString *)dateString dateFormat:(NSString *)dateFormat {
|
||||
return [self br_dateFromString:dateString dateFormat:dateFormat language:nil];
|
||||
}
|
||||
#pragma mark - NSString 转 NSDate
|
||||
+ (NSDate *)br_dateFromString:(NSString *)dateString
|
||||
dateFormat:(NSString *)dateFormat
|
||||
language:(NSString *)language {
|
||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
// 设置日期格式
|
||||
dateFormatter.dateFormat = dateFormat;
|
||||
if (!language) {
|
||||
language = [NSLocale preferredLanguages].firstObject;
|
||||
}
|
||||
// 设置时区
|
||||
dateFormatter.timeZone = [self br_getTimeZone];
|
||||
dateFormatter.locale = [[NSLocale alloc]initWithLocaleIdentifier:language];
|
||||
// 如果当前时间不存在,就获取距离最近的整点时间
|
||||
dateFormatter.lenient = YES;
|
||||
|
||||
return [dateFormatter dateFromString:dateString];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
<key>NSPrivacyTrackingDomains</key>
|
||||
<array/>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array/>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// BRTextModel.h
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2019/10/2.
|
||||
// Copyright © 2019 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface BRTextModel : NSObject
|
||||
/** code */
|
||||
@property (nullable, nonatomic, copy) NSString *code;
|
||||
/** text */
|
||||
@property (nullable, nonatomic, copy) NSString *text;
|
||||
/** 子级 list */
|
||||
@property (nullable, nonatomic, copy) NSArray<BRTextModel *> *children;
|
||||
/** 父级 code */
|
||||
@property (nonatomic, strong) NSString *parentCode;
|
||||
/** 其它扩展字段 */
|
||||
@property (nullable, nonatomic, strong) id extras;
|
||||
/** 记录选择的索引位置 */
|
||||
@property (nonatomic, assign) NSInteger index;
|
||||
|
||||
/** 字典 转 模型 */
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dictionary;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/// 工具方法
|
||||
@interface NSArray (BRPickerView)
|
||||
|
||||
/// 数组 转 模型数组
|
||||
/// - Parameters:
|
||||
/// - dataArr: 字典数组
|
||||
/// - mapper: 指定 BRTextModel模型的属性 与 字典key 的映射关系
|
||||
+ (NSArray *)br_modelArrayWithJson:(NSArray *)dataArr mapper:(nullable NSDictionary *)mapper;
|
||||
|
||||
/// 获取模型数组元素,指定属性的值组成新数组
|
||||
/// - Parameter propertyName: 模型的属性名称
|
||||
- (NSArray *)br_getValueArr:(NSString *)propertyName;
|
||||
|
||||
/// 将模型数组元素,指定属性连接成字符串
|
||||
/// - Parameters:
|
||||
/// - propertyName: 模型的属性名称
|
||||
/// - separator: 分隔符
|
||||
- (NSString *)br_joinValue:(NSString *)propertyName separator:(NSString *)separator;
|
||||
|
||||
/// 将模型数组元素的 text 属性,连接成字符串
|
||||
/// - Parameter separator: 分隔符
|
||||
- (NSString *)br_joinText:(NSString *)separator;
|
||||
|
||||
/// 将扁平结构模型数组 转换成 树状结构模型数组
|
||||
- (NSArray<BRTextModel *> *)br_buildTreeArray;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
//
|
||||
// BRTextModel.m
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2019/10/2.
|
||||
// Copyright © 2019 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import "BRTextModel.h"
|
||||
|
||||
@implementation BRTextModel
|
||||
|
||||
/// 字典 转 模型
|
||||
- (instancetype)initWithDictionary:(NSDictionary *)dictionary {
|
||||
if (self = [super init]) {
|
||||
self.code = dictionary[@"code"];
|
||||
self.text = dictionary[@"text"];
|
||||
self.parentCode = dictionary[@"parent_code"];
|
||||
NSArray *childrenArray = dictionary[@"children"];
|
||||
if (childrenArray) {
|
||||
NSMutableArray *tempArr = [NSMutableArray array];
|
||||
for (NSDictionary *childDict in childrenArray) {
|
||||
BRTextModel *child = [[BRTextModel alloc] initWithDictionary:childDict];
|
||||
[tempArr addObject:child];
|
||||
}
|
||||
self.children = [tempArr copy];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/// 判断两个对象是否相等
|
||||
/// @param object 目标对象
|
||||
- (BOOL)isEqual:(id)object {
|
||||
// 1.对象的地址相同
|
||||
if (self == object) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
if (![object isKindOfClass:[BRTextModel class]]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
BRTextModel *model = (BRTextModel *)object;
|
||||
if (!model) {
|
||||
return NO;
|
||||
}
|
||||
// 2.对象的类型相同,且对象的各个属性相等
|
||||
BOOL isSameCode = (!self.code && !model.code) || [self.code isEqualToString:model.code];
|
||||
BOOL isSameText = (!self.text && !model.text) || [self.text isEqualToString:model.text];
|
||||
|
||||
return isSameCode && isSameText;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return [self.code hash] ^ [self.text hash];
|
||||
}
|
||||
|
||||
|
||||
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
|
||||
|
||||
}
|
||||
|
||||
// value为nil,key不为nil的时候会调用
|
||||
- (void)setNilValueForKey:(NSString *)key {
|
||||
|
||||
}
|
||||
|
||||
// 防止使用 valueForKey 获取值,key不存在时奔溃
|
||||
- (id)valueForUndefinedKey:(NSString *)key {
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/// 工具方法
|
||||
@implementation NSArray (BRPickerView)
|
||||
|
||||
/// 数组 转 模型数组
|
||||
+ (NSArray *)br_modelArrayWithJson:(NSArray *)dataArr mapper:(nullable NSDictionary *)mapper {
|
||||
if (!dataArr || dataArr.count == 0) {
|
||||
return nil;
|
||||
}
|
||||
if (!mapper) {
|
||||
// 如果属性映射字典为空,就使用下面默认的
|
||||
mapper = @{
|
||||
@"code": @"code",
|
||||
@"text": @"text",
|
||||
@"parentCode": @"parent_code",
|
||||
@"extras": @"extras",
|
||||
@"children": @"children"
|
||||
};
|
||||
}
|
||||
NSMutableArray *tempArr = [NSMutableArray array];
|
||||
for (NSDictionary *dic in dataArr) {
|
||||
BRTextModel *model = [[BRTextModel alloc]init];
|
||||
|
||||
NSString *codeMappingKey = mapper[@"code"] ?: @"code";
|
||||
model.code = dic[codeMappingKey] ? [NSString stringWithFormat:@"%@", dic[codeMappingKey]] : nil;
|
||||
|
||||
NSString *textMappingKey = mapper[@"text"] ?: @"text";
|
||||
model.text = dic[textMappingKey];
|
||||
|
||||
NSString *parentCodeMappingKey = mapper[@"parentCode"] ?: @"parentCode";
|
||||
model.parentCode = dic[parentCodeMappingKey] ? [NSString stringWithFormat:@"%@", dic[parentCodeMappingKey]] : nil;
|
||||
|
||||
NSString *extrasMappingKey = mapper[@"extras"] ?: @"extras";
|
||||
model.extras = dic[extrasMappingKey];
|
||||
|
||||
NSString *childrenMappingKey = mapper[@"children"] ?: @"children";
|
||||
NSArray *children = dic[childrenMappingKey];
|
||||
if (children && children.count > 0) {
|
||||
model.children = [self br_modelArrayWithJson:children mapper:mapper]; // 递归处理子list
|
||||
}
|
||||
|
||||
[tempArr addObject:model];
|
||||
}
|
||||
|
||||
return [tempArr copy];
|
||||
}
|
||||
|
||||
/// 获取模型数组元素,指定属性的值组成新数组
|
||||
- (NSArray *)br_getValueArr:(NSString *)propertyName {
|
||||
NSMutableArray *valueArr = [[NSMutableArray alloc]init];
|
||||
for (BRTextModel *model in self) {
|
||||
id propertyValue = [model valueForKey:propertyName];
|
||||
if (propertyValue) {
|
||||
[valueArr addObject:propertyValue];
|
||||
}
|
||||
}
|
||||
return [valueArr copy];
|
||||
}
|
||||
|
||||
/// 将模型数组元素,指定属性连接成字符串
|
||||
- (NSString *)br_joinValue:(NSString *)propertyName separator:(NSString *)separator {
|
||||
NSArray *valueArr = [self br_getValueArr:propertyName];
|
||||
if (valueArr && valueArr.count > 0) {
|
||||
return [valueArr componentsJoinedByString:separator];
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
/// 将模型数组元素的 text 属性,连接成字符串
|
||||
- (NSString *)br_joinText:(NSString *)separator {
|
||||
NSArray *valueArr = [self br_getValueArr:@"text"];
|
||||
if (valueArr && valueArr.count > 0) {
|
||||
return [valueArr componentsJoinedByString:separator];
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
/// 将扁平结构模型数组 转换成 树状结构模型数组
|
||||
- (NSArray<BRTextModel *> *)br_buildTreeArray {
|
||||
NSMutableArray<BRTextModel *> *treeModels = [NSMutableArray array];
|
||||
NSMutableDictionary<NSString *, BRTextModel *> *allItemDic = [NSMutableDictionary dictionary];
|
||||
|
||||
// 将所有模型对象以 code 作为 key 存入字典
|
||||
for (BRTextModel *model in self) {
|
||||
if (model.code && model.code.length > 0) {
|
||||
allItemDic[model.code] = model;
|
||||
}
|
||||
}
|
||||
|
||||
for (BRTextModel *model in self) {
|
||||
NSString *parentCode = model.parentCode;
|
||||
BRTextModel *parentModel = parentCode && parentCode.length > 0 ? allItemDic[parentCode] : nil;
|
||||
if (parentModel) {
|
||||
if (!parentModel.children) {
|
||||
parentModel.children = [NSArray array];
|
||||
}
|
||||
parentModel.children = [parentModel.children arrayByAddingObject:model];
|
||||
} else {
|
||||
// 没有找到对应的父级模型,即该模型为根节点
|
||||
[treeModels addObject:model];
|
||||
}
|
||||
}
|
||||
|
||||
return treeModels;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
//
|
||||
// BRTextPickerView.h
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2017/8/11.
|
||||
// Copyright © 2017 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import "BRPickerAlertView.h"
|
||||
#import "BRTextModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 文本选择器类型
|
||||
typedef NS_ENUM(NSInteger, BRTextPickerMode) {
|
||||
/** 单列选择器 */
|
||||
BRTextPickerComponentSingle,
|
||||
/** 多列选择器 */
|
||||
BRTextPickerComponentMulti,
|
||||
/** 多列联动选择器 */
|
||||
BRTextPickerComponentCascade
|
||||
};
|
||||
|
||||
typedef void(^BRSingleResultBlock)(BRTextModel * _Nullable model, NSInteger index);
|
||||
|
||||
typedef void(^BRMultiResultBlock)(NSArray <BRTextModel *> * _Nullable models, NSArray<NSNumber *> * _Nullable indexs);
|
||||
|
||||
@interface BRTextPickerView : BRPickerAlertView
|
||||
|
||||
/**
|
||||
////////////////////////////////////////////////////////////////////////// *
|
||||
///
|
||||
/// 【用法一】
|
||||
/// 特点:灵活,扩展性强(推荐使用!)
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/** 文本选择器显示类型 */
|
||||
@property (nonatomic, assign) BRTextPickerMode pickerMode;
|
||||
|
||||
/**
|
||||
* 1.设置数据源
|
||||
* 单列:@[@"男", @"女", @"其他"],或直接传一维模型数组(NSArray <BRTextModel *>*)
|
||||
* 多列:@[@[@"语文", @"数学", @"英语"], @[@"优秀", @"良好"]],或直接传多维模型数组
|
||||
*
|
||||
* 联动:传树状结构模型数组(NSArray <BRTextModel *>*),对应的 JSON 基本数据格式如下:
|
||||
|
||||
[
|
||||
{
|
||||
"text" : "北京市",
|
||||
"children" : [
|
||||
{ "text": "北京城区", "children": [{ "text": "东城区" }, { "text": "西城区" }] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"text" : "浙江省",
|
||||
"children" : [
|
||||
{ "text": "杭州市", "children": [{ "text": "西湖区" }, { "text": "滨江区" }] },
|
||||
{ "text": "宁波市", "children": [{ "text": "海曙区" }, { "text": "江北区" }] }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
提示:可以使用下面方法,把上面的 JSON 数据 转成 模型数组
|
||||
dataSourceArr = [NSArray br_modelArrayWithJson:dataArr mapper:nil];
|
||||
*/
|
||||
@property (nullable, nonatomic, copy) NSArray *dataSourceArr;
|
||||
/**
|
||||
* 2.设置数据源(传本地文件名,支持 plist/json 文件)
|
||||
* ① 对于单列/多列选择器:可以直接传 plist 文件名(如:@"education_data.plist",要带后缀名)
|
||||
* ② 对于多列联动选择器:可以直接传 JSON 文件名(如:@"region_tree_data.json",要带后缀名),另外要注意JSON数据源的格式(参考上面设置数据源)
|
||||
*
|
||||
* 场景:可以将数据源数据(数组/JSON格式数据)放到 plist/json 文件中,直接传文件名更加简单
|
||||
*/
|
||||
@property (nullable, nonatomic, copy) NSString *fileName;
|
||||
|
||||
/** 设置默认选中的位置【单列】*/
|
||||
@property (nonatomic, assign) NSInteger selectIndex;
|
||||
/** 设置默认选中的位置【多列】*/
|
||||
@property (nullable, nonatomic, copy) NSArray <NSNumber *> *selectIndexs;
|
||||
|
||||
/** 滚动选择时,触发的回调【单列】 */
|
||||
@property (nullable, nonatomic, copy) BRSingleResultBlock singleChangeBlock;
|
||||
/** 滚动选择时,触发的回调【多列】 */
|
||||
@property (nullable, nonatomic, copy) BRMultiResultBlock multiChangeBlock;
|
||||
|
||||
/** 点击确定时,触发的回调【单列】 */
|
||||
@property (nullable, nonatomic, copy) BRSingleResultBlock singleResultBlock;
|
||||
/** 点击确定时,触发的回调【多列】 */
|
||||
@property (nullable, nonatomic, copy) BRMultiResultBlock multiResultBlock;
|
||||
|
||||
/** 判断选择器是否处于滚动中。可以用于解决快速滑动选择器,在滚动结束前秒选确定按钮,出现显示不对的问题 */
|
||||
@property (nonatomic, readonly, assign, getter=isRolling) BOOL rolling;
|
||||
|
||||
/** 设置选择器显示的列数(即层级数),默认是根据数据源层级动态计算显示 */
|
||||
@property (nonatomic, assign) NSUInteger showColumnNum;
|
||||
|
||||
/** 滚动至选择行动画,默认为 NO */
|
||||
@property (nonatomic, assign) BOOL selectRowAnimated;
|
||||
|
||||
/// 初始化文本选择器
|
||||
/// @param pickerMode 文本选择器显示类型
|
||||
- (instancetype)initWithPickerMode:(BRTextPickerMode)pickerMode;
|
||||
|
||||
/// 弹出选择器视图
|
||||
- (void)show;
|
||||
|
||||
/// 关闭选择器视图
|
||||
- (void)dismiss;
|
||||
|
||||
|
||||
|
||||
|
||||
//================================================= 华丽的分割线 =================================================
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// 【用法二】:快捷使用,直接选择下面其中的一个方法进行使用
|
||||
/// 特点:快捷,方便
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* 1.显示【单列】选择器
|
||||
*
|
||||
* @param title 选择器标题
|
||||
* @param dataSourceArr 数据源(如:@[@"男", @"女", @"其他"],或直接传模型数组)
|
||||
* @param selectIndex 默认选中的位置
|
||||
* @param resultBlock 选择后的回调
|
||||
*
|
||||
*/
|
||||
+ (void)showPickerWithTitle:(nullable NSString *)title
|
||||
dataSourceArr:(nullable NSArray *)dataSourceArr
|
||||
selectIndex:(NSInteger)selectIndex
|
||||
resultBlock:(nullable BRSingleResultBlock)resultBlock;
|
||||
|
||||
/**
|
||||
* 2.显示【多列】选择器
|
||||
*
|
||||
* @param title 选择器标题
|
||||
* @param dataSourceArr 数据源,格式:@[@[@"语文", @"数学", @"英语"], @[@"优秀", @"良好"]],或直接传多维模型数组
|
||||
* @param selectIndexs 默认选中的位置(传索引数组,如:@[@2, @1])
|
||||
* @param resultBlock 选择后的回调
|
||||
*
|
||||
*/
|
||||
+ (void)showMultiPickerWithTitle:(nullable NSString *)title
|
||||
dataSourceArr:(nullable NSArray *)dataSourceArr
|
||||
selectIndexs:(nullable NSArray <NSNumber *> *)selectIndexs
|
||||
resultBlock:(nullable BRMultiResultBlock)resultBlock;
|
||||
|
||||
/**
|
||||
* 3.显示【联动】选择器
|
||||
*
|
||||
* @param title 选择器标题
|
||||
* @param dataSourceArr 数据源,格式:直接传一维模型数组(NSArray <BRTextModel *>*)
|
||||
* @param selectIndexs 默认选中的位置(传索引数组,如:@[@2, @1])
|
||||
* @param resultBlock 选择后的回调
|
||||
*
|
||||
*/
|
||||
+ (void)showCascadePickerWithTitle:(nullable NSString *)title
|
||||
dataSourceArr:(nullable NSArray *)dataSourceArr
|
||||
selectIndexs:(nullable NSArray <NSNumber *> *)selectIndexs
|
||||
resultBlock:(nullable BRMultiResultBlock)resultBlock;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
@ -0,0 +1,623 @@
|
|||
//
|
||||
// BRTextPickerView.m
|
||||
// BRPickerViewDemo
|
||||
//
|
||||
// Created by renbo on 2017/8/11.
|
||||
// Copyright © 2017 irenb. All rights reserved.
|
||||
//
|
||||
// 最新代码下载地址:https://github.com/agiapp/BRPickerView
|
||||
|
||||
#import "BRTextPickerView.h"
|
||||
|
||||
@interface BRTextPickerView ()<UIPickerViewDelegate, UIPickerViewDataSource>
|
||||
{
|
||||
BOOL _isSyncingRollingSelection; // 滚动未结束时批量同步,抑制 change 回调
|
||||
}
|
||||
/** 选择器 */
|
||||
@property (nonatomic, strong) UIPickerView *pickerView;
|
||||
/** 当前显示的数据源 */
|
||||
@property (nonatomic, copy) NSArray *dataList;
|
||||
|
||||
@end
|
||||
|
||||
@implementation BRTextPickerView
|
||||
|
||||
#pragma mark - 1.显示【单列】选择器
|
||||
+ (void)showPickerWithTitle:(NSString *)title
|
||||
dataSourceArr:(NSArray *)dataSourceArr
|
||||
selectIndex:(NSInteger)selectIndex
|
||||
resultBlock:(BRSingleResultBlock)resultBlock {
|
||||
// 创建选择器
|
||||
BRTextPickerView *strPickerView = [[BRTextPickerView alloc]init];
|
||||
strPickerView.pickerMode = BRTextPickerComponentSingle;
|
||||
strPickerView.title = title;
|
||||
strPickerView.dataSourceArr = dataSourceArr;
|
||||
strPickerView.selectIndex = selectIndex;
|
||||
strPickerView.singleResultBlock = resultBlock;
|
||||
|
||||
// 显示
|
||||
[strPickerView show];
|
||||
}
|
||||
|
||||
#pragma mark - 2.显示【多列】选择器
|
||||
+ (void)showMultiPickerWithTitle:(NSString *)title
|
||||
dataSourceArr:(NSArray *)dataSourceArr
|
||||
selectIndexs:(NSArray <NSNumber *>*)selectIndexs
|
||||
resultBlock:(BRMultiResultBlock)resultBlock {
|
||||
// 创建选择器
|
||||
BRTextPickerView *strPickerView = [[BRTextPickerView alloc]init];
|
||||
strPickerView.pickerMode = BRTextPickerComponentMulti;
|
||||
strPickerView.title = title;
|
||||
strPickerView.dataSourceArr = dataSourceArr;
|
||||
strPickerView.selectIndexs = selectIndexs;
|
||||
strPickerView.multiResultBlock = resultBlock;
|
||||
|
||||
// 显示
|
||||
[strPickerView show];
|
||||
}
|
||||
|
||||
#pragma mark - 3.显示【联动】选择器
|
||||
+ (void)showCascadePickerWithTitle:(nullable NSString *)title
|
||||
dataSourceArr:(nullable NSArray *)dataSourceArr
|
||||
selectIndexs:(nullable NSArray <NSNumber *> *)selectIndexs
|
||||
resultBlock:(nullable BRMultiResultBlock)resultBlock {
|
||||
// 创建选择器
|
||||
BRTextPickerView *strPickerView = [[BRTextPickerView alloc]init];
|
||||
strPickerView.pickerMode = BRTextPickerComponentCascade;
|
||||
strPickerView.title = title;
|
||||
strPickerView.dataSourceArr = dataSourceArr;
|
||||
strPickerView.selectIndexs = selectIndexs;
|
||||
strPickerView.multiResultBlock = resultBlock;
|
||||
|
||||
// 显示
|
||||
[strPickerView show];
|
||||
}
|
||||
|
||||
#pragma mark - 初始化自定义选择器
|
||||
- (instancetype)initWithPickerMode:(BRTextPickerMode)pickerMode {
|
||||
if (self = [super init]) {
|
||||
self.pickerMode = pickerMode;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - 处理选择器数据 和 默认选择状态
|
||||
- (void)handlerPickerData {
|
||||
// 1.检查数据源数据格式是否有误
|
||||
BOOL dataSourceError = NO;
|
||||
if (self.dataSourceArr.count == 0) {
|
||||
dataSourceError = YES;
|
||||
}
|
||||
id item = [self.dataSourceArr firstObject];
|
||||
if (self.pickerMode == BRTextPickerComponentSingle) {
|
||||
dataSourceError = !([item isKindOfClass:[NSString class]] || [item isKindOfClass:[BRTextModel class]]);
|
||||
} else if (self.pickerMode == BRTextPickerComponentMulti) {
|
||||
dataSourceError = ![item isKindOfClass:[NSArray class]];
|
||||
} else if (self.pickerMode == BRTextPickerComponentCascade) {
|
||||
dataSourceError = ![item isKindOfClass:[BRTextModel class]];
|
||||
}
|
||||
if (dataSourceError) {
|
||||
BRErrorLog(@"数据源异常!请检查选择器数据源的格式");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2.处理默认选择状态
|
||||
if (self.pickerMode == BRTextPickerComponentSingle) {
|
||||
self.dataList = self.dataSourceArr;
|
||||
if (self.selectIndex < 0 || self.selectIndex >= self.dataList.count) {
|
||||
self.selectIndex = 0;
|
||||
}
|
||||
} else if (self.pickerMode == BRTextPickerComponentMulti) {
|
||||
self.dataList = self.dataSourceArr;
|
||||
NSMutableArray *selectIndexs = [[NSMutableArray alloc]init];
|
||||
for (NSInteger component = 0; component < self.dataList.count; component++) {
|
||||
NSArray *itemArr = self.dataList[component];
|
||||
NSInteger row = 0;
|
||||
if (self.selectIndexs.count > 0 && component < self.selectIndexs.count) {
|
||||
NSInteger index = [self.selectIndexs[component] integerValue];
|
||||
row = (index >= 0 && index < itemArr.count) ? index : 0;
|
||||
}
|
||||
[selectIndexs addObject:@(row)];
|
||||
}
|
||||
self.selectIndexs = [selectIndexs copy];
|
||||
} else if (self.pickerMode == BRTextPickerComponentCascade) {
|
||||
NSMutableArray *dataList = [[NSMutableArray alloc]init];
|
||||
[dataList addObject:self.dataSourceArr];
|
||||
NSMutableArray *selectIndexs = [[NSMutableArray alloc]init];
|
||||
|
||||
BOOL hasNext = self.dataSourceArr.count > 0;
|
||||
NSInteger i = 0;
|
||||
NSInteger selectIndex = self.selectIndexs.count > 0 && i < self.selectIndexs.count ? [self.selectIndexs[i] integerValue] : 0;
|
||||
[selectIndexs addObject:@(selectIndex)];
|
||||
if (selectIndex >= 0 && selectIndex < self.dataSourceArr.count) {
|
||||
BRTextModel *selectModel = self.dataSourceArr[selectIndex];
|
||||
while (hasNext) {
|
||||
NSArray *nextArr = selectModel.children;
|
||||
if (!nextArr || nextArr.count == 0) {
|
||||
hasNext = NO;
|
||||
break;
|
||||
}
|
||||
[dataList addObject:nextArr];
|
||||
|
||||
i++;
|
||||
selectIndex = self.selectIndexs.count > 0 && i < self.selectIndexs.count ? [self.selectIndexs[i] integerValue] : 0;
|
||||
[selectIndexs addObject:@(selectIndex)];
|
||||
if (selectIndex < nextArr.count) {
|
||||
selectModel = nextArr[selectIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 控制选择器固定显示的列数
|
||||
if (self.showColumnNum > 0) {
|
||||
NSInteger dataListCount = dataList.count;
|
||||
if (self.showColumnNum < dataListCount) {
|
||||
// 显示子集数据
|
||||
dataList = [[dataList subarrayWithRange:NSMakeRange(0, self.showColumnNum)] mutableCopy];
|
||||
selectIndexs = [[selectIndexs subarrayWithRange:NSMakeRange(0, self.showColumnNum)] mutableCopy];
|
||||
} else {
|
||||
// 补全占位数据
|
||||
for (NSInteger i = 0; i < self.showColumnNum - dataListCount; i++) {
|
||||
// 添加空白占位数据
|
||||
BRTextModel *placeholderModel = [[BRTextModel alloc]init];
|
||||
NSArray *placeholderArr = @[placeholderModel];
|
||||
[dataList addObject:placeholderArr];
|
||||
[selectIndexs addObject:@(0)];
|
||||
}
|
||||
}
|
||||
}
|
||||
self.dataList = [dataList copy];
|
||||
self.selectIndexs = [selectIndexs copy];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 选择器
|
||||
- (UIPickerView *)pickerView {
|
||||
if (!_pickerView) {
|
||||
CGFloat pickerHeaderViewHeight = self.pickerHeaderView ? self.pickerHeaderView.bounds.size.height : 0;
|
||||
_pickerView = [[UIPickerView alloc]initWithFrame:CGRectMake(0, self.pickerStyle.titleBarHeight + pickerHeaderViewHeight, self.keyView.bounds.size.width, self.pickerStyle.pickerHeight)];
|
||||
_pickerView.backgroundColor = self.pickerStyle.pickerColor;
|
||||
_pickerView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
|
||||
_pickerView.dataSource = self;
|
||||
_pickerView.delegate = self;
|
||||
}
|
||||
return _pickerView;
|
||||
}
|
||||
|
||||
#pragma mark - UIPickerViewDataSource
|
||||
// 1.返回组件数量
|
||||
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
|
||||
switch (self.pickerMode) {
|
||||
case BRTextPickerComponentSingle:
|
||||
return 1;
|
||||
case BRTextPickerComponentMulti:
|
||||
case BRTextPickerComponentCascade:
|
||||
{
|
||||
if (self.pickerStyle.columnSpacing > 0) {
|
||||
return self.dataList.count * 2 - 1;
|
||||
}
|
||||
return self.dataList.count;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 2.返回每个组件的行数
|
||||
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
|
||||
switch (self.pickerMode) {
|
||||
case BRTextPickerComponentSingle:
|
||||
return self.dataList.count;
|
||||
case BRTextPickerComponentMulti:
|
||||
case BRTextPickerComponentCascade:
|
||||
{
|
||||
if (self.pickerStyle.columnSpacing > 0) {
|
||||
if (component % 2 == 1) {
|
||||
return 1;
|
||||
} else {
|
||||
component = component / 2;
|
||||
}
|
||||
}
|
||||
if (component < self.dataList.count) {
|
||||
return [self.dataList[component] count];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UIPickerViewDelegate
|
||||
// 3.设置 pickerView 的显示内容
|
||||
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(nullable UIView *)view {
|
||||
// 1.自定义 row 的内容视图
|
||||
UILabel *label = (UILabel *)view;
|
||||
if (!label) {
|
||||
label = [[UILabel alloc]init];
|
||||
label.backgroundColor = [UIColor clearColor];
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
label.font = self.pickerStyle.pickerTextFont;
|
||||
label.textColor = self.pickerStyle.pickerTextColor;
|
||||
label.numberOfLines = self.pickerStyle.maxTextLines;
|
||||
// 字体自适应属性
|
||||
label.adjustsFontSizeToFitWidth = YES;
|
||||
// 自适应最小字体缩放比例
|
||||
label.minimumScaleFactor = 0.5f;
|
||||
}
|
||||
|
||||
// 2.设置选择器中间选中行的样式
|
||||
[self.pickerStyle setupPickerSelectRowStyle:pickerView titleForRow:row forComponent:component];
|
||||
|
||||
// 设置文本
|
||||
if (self.pickerMode == BRTextPickerComponentSingle) {
|
||||
id item = row < self.dataList.count ? self.dataList[row] : nil;
|
||||
if (item && [item isKindOfClass:[BRTextModel class]]) {
|
||||
BRTextModel *model = (BRTextModel *)item;
|
||||
label.text = model.text;
|
||||
} else {
|
||||
label.text = item;
|
||||
}
|
||||
} else if (self.pickerMode == BRTextPickerComponentMulti || self.pickerMode == BRTextPickerComponentCascade) {
|
||||
// 如果有设置列间距,且是第奇数列,则不显示内容(即空白间隔列)
|
||||
if (self.pickerStyle.columnSpacing > 0) {
|
||||
if (component % 2 == 1) {
|
||||
label.text = @"";
|
||||
return label;
|
||||
} else {
|
||||
component = component / 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (component < self.dataList.count) {
|
||||
NSArray *itemArr = self.dataList[component];
|
||||
id item = row < itemArr.count ? itemArr[row] : nil;
|
||||
if (item && [item isKindOfClass:[BRTextModel class]]) {
|
||||
BRTextModel *model = (BRTextModel *)item;
|
||||
label.text = model.text;
|
||||
} else {
|
||||
label.text = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
// 获取选择器是否滚动中状态
|
||||
- (BOOL)getRollingStatus:(UIView *)view {
|
||||
if ([view isKindOfClass:[UIScrollView class]]) {
|
||||
UIScrollView *scrollView = (UIScrollView *)view;
|
||||
if (scrollView.dragging || scrollView.decelerating) {
|
||||
// 如果 UIPickerView 正在拖拽或正在减速,返回YES
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
for (UIView *subView in view.subviews) {
|
||||
if ([self getRollingStatus:subView]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
// 选择器是否正在滚动
|
||||
- (BOOL)isRolling {
|
||||
return [self getRollingStatus:self.pickerView];
|
||||
}
|
||||
|
||||
// 4.滚动 pickerView 执行的回调方法
|
||||
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
|
||||
switch (self.pickerMode) {
|
||||
case BRTextPickerComponentSingle:
|
||||
{
|
||||
self.selectIndex = row;
|
||||
if (!_isSyncingRollingSelection) {
|
||||
// 滚动选择时执行 singleChangeBlock
|
||||
self.singleChangeBlock ? self.singleChangeBlock([self getSingleSelectModel], self.selectIndex): nil;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRTextPickerComponentMulti:
|
||||
{
|
||||
// 处理选择器有设置列间距时,选择器的滚动问题
|
||||
if (self.pickerStyle.columnSpacing > 0) {
|
||||
if (component % 2 == 1) {
|
||||
return;
|
||||
} else {
|
||||
component = component / 2;
|
||||
}
|
||||
}
|
||||
|
||||
NSMutableArray *mutableArr = [NSMutableArray arrayWithArray:self.selectIndexs ?: @[]];
|
||||
while (mutableArr.count <= component) {
|
||||
[mutableArr addObject:@(0)];
|
||||
}
|
||||
[mutableArr replaceObjectAtIndex:component withObject:@(row)];
|
||||
self.selectIndexs = [mutableArr copy];
|
||||
|
||||
if (!_isSyncingRollingSelection) {
|
||||
// 滚动选择时执行 multiChangeBlock
|
||||
self.multiChangeBlock ? self.multiChangeBlock([self getMultiSelectModels], self.selectIndexs): nil;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRTextPickerComponentCascade:
|
||||
{
|
||||
// 处理选择器有设置列间距时,选择器的滚动问题
|
||||
if (self.pickerStyle.columnSpacing > 0) {
|
||||
if (component % 2 == 1) {
|
||||
return;
|
||||
} else {
|
||||
component = component / 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (component < self.selectIndexs.count) {
|
||||
NSMutableArray *selectIndexs = [[NSMutableArray alloc]init];
|
||||
for (NSInteger i = 0; i < self.selectIndexs.count; i++) {
|
||||
if (i < component) {
|
||||
[selectIndexs addObject:self.selectIndexs[i]];
|
||||
} else if (i == component) {
|
||||
[selectIndexs addObject:@(row)];
|
||||
} else {
|
||||
[selectIndexs addObject:@(0)];
|
||||
}
|
||||
}
|
||||
self.selectIndexs = [selectIndexs copy];
|
||||
}
|
||||
|
||||
if (!_isSyncingRollingSelection) {
|
||||
// 刷新选择器数据
|
||||
[self reloadData];
|
||||
// 滚动选择时执行 multiChangeBlock
|
||||
self.multiChangeBlock ? self.multiChangeBlock([self getMultiSelectModels], self.selectIndexs): nil;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 获取【单列】选择器选择的值
|
||||
- (BRTextModel *)getSingleSelectModel {
|
||||
id item = self.selectIndex < self.dataList.count ? self.dataList[self.selectIndex] : nil;
|
||||
if ([item isKindOfClass:[BRTextModel class]]) {
|
||||
BRTextModel *model = (BRTextModel *)item;
|
||||
model.index = self.selectIndex;
|
||||
return model;
|
||||
} else {
|
||||
BRTextModel *model = [[BRTextModel alloc]init];
|
||||
model.index = self.selectIndex;
|
||||
model.text = item;
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - 获取【多列】选择器选择的值
|
||||
- (NSArray *)getMultiSelectModels {
|
||||
NSMutableArray *modelArr = [[NSMutableArray alloc]init];
|
||||
for (NSInteger i = 0; i < self.dataList.count; i++) {
|
||||
NSInteger index = i < self.selectIndexs.count ? [self.selectIndexs[i] integerValue] : 0;
|
||||
NSArray *dataArr = i < self.dataList.count ? self.dataList[i] : @[];
|
||||
id item = index >= 0 && index < dataArr.count ? dataArr[index] : nil;
|
||||
|
||||
if ([item isKindOfClass:[BRTextModel class]]) {
|
||||
BRTextModel *model = (BRTextModel *)item;
|
||||
model.index = index;
|
||||
[modelArr addObject:model];
|
||||
} else {
|
||||
BRTextModel *model = [[BRTextModel alloc]init];
|
||||
model.index = index;
|
||||
model.text = item;
|
||||
[modelArr addObject:model];
|
||||
}
|
||||
}
|
||||
return [modelArr copy];
|
||||
}
|
||||
|
||||
// 设置行高
|
||||
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component {
|
||||
return self.pickerStyle.rowHeight;
|
||||
}
|
||||
|
||||
// 设置列宽
|
||||
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
|
||||
if (self.pickerStyle.columnSpacing > 0 && component % 2 == 1) {
|
||||
return self.pickerStyle.columnSpacing;
|
||||
}
|
||||
NSInteger columnCount = [self numberOfComponentsInPickerView:pickerView];
|
||||
CGFloat columnWidth = self.pickerView.bounds.size.width / columnCount - 5;
|
||||
if (self.pickerStyle.columnWidth > 0 && self.pickerStyle.columnWidth <= columnWidth) {
|
||||
return self.pickerStyle.columnWidth;
|
||||
}
|
||||
return columnWidth;
|
||||
}
|
||||
|
||||
#pragma mark - 重写父类方法
|
||||
- (void)reloadData {
|
||||
// 1.处理数据源
|
||||
[self handlerPickerData];
|
||||
// 2.刷新选择器
|
||||
[self.pickerView reloadAllComponents];
|
||||
// 3.滚动到选择的值
|
||||
if (self.pickerMode == BRTextPickerComponentSingle) {
|
||||
if (self.selectIndex >= 0 && self.selectIndex < self.dataList.count) {
|
||||
[self.pickerView selectRow:self.selectIndex inComponent:0 animated:self.selectRowAnimated];
|
||||
}
|
||||
} else if (self.pickerMode == BRTextPickerComponentMulti || self.pickerMode == BRTextPickerComponentCascade) {
|
||||
for (NSInteger i = 0; i < self.selectIndexs.count; i++) {
|
||||
NSInteger component = self.pickerStyle.columnSpacing > 0 ? i * 2 : i;
|
||||
NSInteger row = i < self.selectIndexs.count ? [self.selectIndexs[i] integerValue] : 0;
|
||||
[self.pickerView selectRow:row inComponent:component animated:self.selectRowAnimated];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addPickerToView:(UIView *)view {
|
||||
// 1.添加选择器
|
||||
if (view) {
|
||||
// 立即刷新容器视图 view 的布局(防止 view 使用自动布局时,选择器视图无法正常显示)
|
||||
[view setNeedsLayout];
|
||||
[view layoutIfNeeded];
|
||||
|
||||
self.frame = view.bounds;
|
||||
CGFloat pickerHeaderViewHeight = self.pickerHeaderView ? self.pickerHeaderView.bounds.size.height : 0;
|
||||
CGFloat pickerFooterViewHeight = self.pickerFooterView ? self.pickerFooterView.bounds.size.height : 0;
|
||||
self.pickerView.frame = CGRectMake(0, pickerHeaderViewHeight, view.bounds.size.width, view.bounds.size.height - pickerHeaderViewHeight - pickerFooterViewHeight);
|
||||
[self addSubview:self.pickerView];
|
||||
} else {
|
||||
// iOS16:重新设置 pickerView 高度(解决懒加载设置frame不生效问题)
|
||||
CGFloat pickerHeaderViewHeight = self.pickerHeaderView ? self.pickerHeaderView.bounds.size.height : 0;
|
||||
self.pickerView.frame = CGRectMake(0, self.pickerStyle.titleBarHeight + pickerHeaderViewHeight, self.keyView.bounds.size.width, self.pickerStyle.pickerHeight);
|
||||
|
||||
[self.alertView addSubview:self.pickerView];
|
||||
}
|
||||
|
||||
// ③添加中间选择行的两条分割线
|
||||
if (self.pickerStyle.clearPickerNewStyle) {
|
||||
[self.pickerStyle addSeparatorLineView:self.pickerView];
|
||||
}
|
||||
|
||||
// 2.绑定数据
|
||||
[self reloadData];
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
// 点击确定按钮的回调:点击确定按钮后,执行这个block回调
|
||||
self.doneBlock = ^{
|
||||
if (!weakSelf) {
|
||||
return;
|
||||
}
|
||||
if (weakSelf.isRolling) {
|
||||
[weakSelf handleAutoSelectRollingRow];
|
||||
}
|
||||
|
||||
// 点击确定,执行选择结果回调
|
||||
if (weakSelf.pickerMode == BRTextPickerComponentSingle) {
|
||||
weakSelf.singleResultBlock ? weakSelf.singleResultBlock([weakSelf getSingleSelectModel], weakSelf.selectIndex): nil;
|
||||
} else if (weakSelf.pickerMode == BRTextPickerComponentMulti || weakSelf.pickerMode == BRTextPickerComponentCascade) {
|
||||
weakSelf.multiResultBlock ? weakSelf.multiResultBlock([weakSelf getMultiSelectModels], weakSelf.selectIndexs): nil;
|
||||
}
|
||||
};
|
||||
|
||||
[super addPickerToView:view];
|
||||
}
|
||||
|
||||
#pragma mark - 获取指定列当前选中行(边界修正)
|
||||
- (NSInteger)clampedSelectedRowInComponent:(NSInteger)component {
|
||||
NSInteger maxRow = [_pickerView numberOfRowsInComponent:component] - 1;
|
||||
if (maxRow < 0) {
|
||||
return NSNotFound;
|
||||
}
|
||||
NSInteger row = [_pickerView selectedRowInComponent:component];
|
||||
return MAX(0, MIN(row, maxRow));
|
||||
}
|
||||
|
||||
#pragma mark - 处理滚动未结束前自动选择行
|
||||
- (void)handleAutoSelectRollingRow {
|
||||
if (!_pickerView) {
|
||||
return;
|
||||
}
|
||||
NSInteger componentCount = [_pickerView numberOfComponents];
|
||||
if (componentCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.pickerMode == BRTextPickerComponentCascade) {
|
||||
NSInteger changedIndex = NSNotFound;
|
||||
NSInteger changedRow = NSNotFound;
|
||||
for (NSInteger component = 0; component < componentCount; component++) {
|
||||
if (self.pickerStyle.columnSpacing > 0 && component % 2 == 1) {
|
||||
continue;
|
||||
}
|
||||
NSInteger dataComponent = self.pickerStyle.columnSpacing > 0 ? component / 2 : component;
|
||||
NSInteger row = [self clampedSelectedRowInComponent:component];
|
||||
if (row == NSNotFound) {
|
||||
continue;
|
||||
}
|
||||
NSInteger oldRow = dataComponent < self.selectIndexs.count ? [self.selectIndexs[dataComponent] integerValue] : 0;
|
||||
if (row != oldRow) {
|
||||
changedIndex = dataComponent;
|
||||
changedRow = row;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (changedIndex != NSNotFound) {
|
||||
NSMutableArray<NSNumber *> *selectIndexs = [NSMutableArray array];
|
||||
for (NSInteger index = 0; index < self.selectIndexs.count; index++) {
|
||||
if (index < changedIndex) {
|
||||
[selectIndexs addObject:self.selectIndexs[index]];
|
||||
} else if (index == changedIndex) {
|
||||
[selectIndexs addObject:@(changedRow)];
|
||||
} else {
|
||||
[selectIndexs addObject:@(0)];
|
||||
}
|
||||
}
|
||||
self.selectIndexs = [selectIndexs copy];
|
||||
[self reloadData];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_isSyncingRollingSelection = YES;
|
||||
if (self.pickerMode == BRTextPickerComponentSingle) {
|
||||
NSInteger row = [self clampedSelectedRowInComponent:0];
|
||||
if (row != NSNotFound) {
|
||||
[self pickerView:_pickerView didSelectRow:row inComponent:0];
|
||||
}
|
||||
} else {
|
||||
for (NSInteger component = 0; component < componentCount; component++) {
|
||||
NSInteger row = [self clampedSelectedRowInComponent:component];
|
||||
if (row == NSNotFound) {
|
||||
continue;
|
||||
}
|
||||
[self pickerView:_pickerView didSelectRow:row inComponent:component];
|
||||
}
|
||||
}
|
||||
_isSyncingRollingSelection = NO;
|
||||
}
|
||||
|
||||
#pragma mark - 重写父类方法
|
||||
- (void)addSubViewToPicker:(UIView *)customView {
|
||||
[self.pickerView addSubview:customView];
|
||||
}
|
||||
|
||||
#pragma mark - 弹出选择器视图
|
||||
- (void)show {
|
||||
[self addPickerToView:nil];
|
||||
}
|
||||
|
||||
#pragma mark - 关闭选择器视图
|
||||
- (void)dismiss {
|
||||
[self removePickerFromView:nil];
|
||||
}
|
||||
|
||||
#pragma mark - setter 方法
|
||||
- (void)setFileName:(NSString *)fileName {
|
||||
NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
|
||||
if (filePath && filePath.length > 0) {
|
||||
if ([fileName hasSuffix:@".plist"]) {
|
||||
// 获取本地 plist文件 数据源
|
||||
NSArray *dataArr = [[NSArray alloc] initWithContentsOfFile:filePath];
|
||||
if (dataArr && dataArr.count > 0) {
|
||||
self.dataSourceArr = dataArr;
|
||||
}
|
||||
} else if ([fileName hasSuffix:@".json"]) {
|
||||
// 获取本地 JSON文件 数据源
|
||||
NSData *jsonData = [NSData dataWithContentsOfFile:filePath];
|
||||
NSArray *dataArr = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
|
||||
if (dataArr && dataArr.count > 0) {
|
||||
self.dataSourceArr = [NSArray br_modelArrayWithJson:dataArr mapper:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 91renb
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -0,0 +1,926 @@
|
|||
# BRPickerView
|
||||
|
||||
BRPickerView 封装的是iOS中常用的选择器组件,主要包括:**`BRDatePickerView`** 日期选择器(支持年月日、年月等15种日期样式选择,支持设置星期、至今等)、**`BRTextPickerView`** 文本选择器(支持单列、多列、省市区、省市、省、自定义多级联动选择)。支持自定义主题样式,适配深色模式,支持将选择器组件添加到指定容器视图。
|
||||
|
||||
⚠️【特别说明】
|
||||
|
||||
>- 从 `V3.0.0` 版本起,移除了 `BRAddressPickerView`、`BRStringPickerView` 废弃组件;请使用 `BRTextPickerView` 新组件进行替代。如果项目大面积报错:① 可暂时使用 2.9.9 旧版本:`pod 'BRPickerView', '2.9.9'`;② 或下载Demo,手动把`Deprecated` 目录添加到项目中。
|
||||
>- 如果不能找到最新版本,请先执行一下 `pod repo update ` 更新本地仓库,使 CocoaPods 能识别最新可用的库版本。
|
||||
|
||||
#### 📒 稀土掘金:https://juejin.cn/post/6844903605468676104
|
||||
|
||||
|
||||
|
||||
# 效果演示
|
||||
|
||||
查看并运行 `BRPickerViewDemo.xcodeproj`
|
||||
|
||||
|  |  |
|
||||
| :----------------------------------------------------------: | :----------------------------------------------------------: |
|
||||
| 框架Demo运行效果图1 | 框架Demo运行效果图2 |
|
||||
|
||||
# 安装
|
||||
|
||||
#### CocoaPods
|
||||
|
||||
1. 在 Podfile 中添加 `pod 'BRPickerView'`
|
||||
2. 执行 `pod install` 或 `pod update`
|
||||
3. 导入头文件 ` #import <BRPickerView.h>`
|
||||
|
||||
#### SPM Supported
|
||||
|
||||
1. 依次点击 Xcode 的菜单 File > Add Package Dependencies...
|
||||
2. 输出 `https://github.com/agiapp/BRPickerView`搜索并选择,然后点击 Add Package
|
||||
|
||||
|
||||
#### 手动导入
|
||||
|
||||
1. 将与 `README.md` 同级目录下的 `BRPickerView` 文件夹拽入项目中(注意:删除PrivacyInfo.xcprivacy文件)
|
||||
|
||||
2. 导入头文件 ` #import "BRPickerView.h"`。
|
||||
|
||||
|
||||
# 系统要求
|
||||
|
||||
- iOS 11.0+
|
||||
- ARC
|
||||
|
||||
# 使用
|
||||
|
||||
### 时间选择器:`BRDatePickerView`
|
||||
|
||||
查看 BRDatePickerView.h 头文件,里面提供了两种使用方式,参见源码。
|
||||
|
||||
```objective-c
|
||||
/// 日期选择器格式
|
||||
typedef NS_ENUM(NSInteger, BRDatePickerMode) {
|
||||
// ----- 以下4种是系统样式(兼容国际化日期格式) -----
|
||||
/** 【yyyy-MM-dd】UIDatePickerModeDate(美式日期:MM-dd-yyyy;英式日期:dd-MM-yyyy)*/
|
||||
BRDatePickerModeDate,
|
||||
/** 【yyyy-MM-dd HH:mm】 UIDatePickerModeDateAndTime */
|
||||
BRDatePickerModeDateAndTime,
|
||||
/** 【HH:mm】UIDatePickerModeTime */
|
||||
BRDatePickerModeTime,
|
||||
/** 【HH:mm】UIDatePickerModeCountDownTimer */
|
||||
BRDatePickerModeCountDownTimer,
|
||||
|
||||
// ----- 以下14种是自定义样式 -----
|
||||
/** 【yyyy-MM-dd HH:mm:ss】年月日时分秒 */
|
||||
BRDatePickerModeYMDHMS,
|
||||
/** 【yyyy-MM-dd HH:mm】年月日时分 */
|
||||
BRDatePickerModeYMDHM,
|
||||
/** 【yyyy-MM-dd HH】年月日时 */
|
||||
BRDatePickerModeYMDH,
|
||||
/** 【MM-dd HH:mm】月日时分 */
|
||||
BRDatePickerModeMDHM,
|
||||
/** 【yyyy-MM-dd】年月日(兼容国际化日期:dd-MM-yyyy)*/
|
||||
BRDatePickerModeYMD,
|
||||
/** 【yyyy-MM】年月(兼容国际化日期:MM-yyyy)*/
|
||||
BRDatePickerModeYM,
|
||||
/** 【yyyy】年 */
|
||||
BRDatePickerModeY,
|
||||
/** 【MM-dd】月日 */
|
||||
BRDatePickerModeMD,
|
||||
/** 【HH:mm:ss】时分秒 */
|
||||
BRDatePickerModeHMS,
|
||||
/** 【HH:mm】时分 */
|
||||
BRDatePickerModeHM,
|
||||
/** 【mm:ss】分秒 */
|
||||
BRDatePickerModeMS,
|
||||
|
||||
/** 【yyyy-qq】年季度 */
|
||||
BRDatePickerModeYQ,
|
||||
/** 【yyyy-MM-ww】年月周 */
|
||||
BRDatePickerModeYMW,
|
||||
/** 【yyyy-ww】年周 */
|
||||
BRDatePickerModeYW
|
||||
};
|
||||
```
|
||||
|
||||
- 使用示例(参考Demo):
|
||||
|
||||
```objective-c
|
||||
// 1.创建日期选择器
|
||||
BRDatePickerView *datePickerView = [[BRDatePickerView alloc]init];
|
||||
// 2.设置属性
|
||||
datePickerView.pickerMode = BRDatePickerModeYMD;
|
||||
datePickerView.title = @"选择年月日";
|
||||
// datePickerView.selectValue = @"2019-10-30";
|
||||
datePickerView.selectDate = [NSDate br_setYear:2019 month:10 day:30];
|
||||
datePickerView.minDate = [NSDate br_setYear:1949 month:3 day:12];
|
||||
datePickerView.maxDate = [NSDate date];
|
||||
datePickerView.isAutoSelect = YES;
|
||||
datePickerView.resultBlock = ^(NSDate *selectDate, NSString *selectValue) {
|
||||
NSLog(@"选择的值:%@", selectValue);
|
||||
};
|
||||
// 设置自定义样式
|
||||
BRPickerStyle *customStyle = [[BRPickerStyle alloc]init];
|
||||
customStyle.pickerColor = BR_RGB_HEX(0xd9dbdf, 1.0f);
|
||||
customStyle.pickerTextColor = [UIColor redColor];
|
||||
customStyle.separatorColor = [UIColor redColor];
|
||||
datePickerView.pickerStyle = customStyle;
|
||||
|
||||
// 3.显示
|
||||
[datePickerView show];
|
||||
```
|
||||
|
||||
**时间选择器显示类型的效果图(默认样式):**
|
||||
|
||||
- 以下4种样式是使用 UIDatePicker 类 进行封装的,支持循环滚动
|
||||
|
||||
|  |  |
|
||||
| :----------------------------------------------------------: | :----------------------------------------------------------: |
|
||||
| 样式1:BRDatePickerModeDate | 样式2:BRDatePickerModeDateAndTime |
|
||||
| | |
|
||||
|  |  |
|
||||
| 样式3:BRDatePickerModeTime | 样式4:BRDatePickerModeCountDownTimer |
|
||||
|
||||
- 以下11种样式是使用 UIPickerView 类进行封装的。
|
||||
|
||||
|  |  |
|
||||
| :----------------------------------------------------------: | :----------------------------------------------------------: |
|
||||
| 样式5:BRDatePickerModeYMDHMS | 样式6:BRDatePickerModeYMDHM |
|
||||
| | |
|
||||
|  |  |
|
||||
| 样式7:BRDatePickerModeYMDH | 样式8:BRDatePickerModeMDHM |
|
||||
| | |
|
||||
|  |  |
|
||||
| 样式9:BRDatePickerModeYMD | 样式10:BRDatePickerModeYM |
|
||||
| | |
|
||||
|  |  |
|
||||
| 样式11:BRDatePickerModeY | 样式12:BRDatePickerModeMD |
|
||||
| | |
|
||||
|  |  |
|
||||
| 样式13:BRDatePickerModeHMS | 样式14:BRDatePickerModeHM |
|
||||
| | |
|
||||
|  | |
|
||||
| 样式15:BRDatePickerModeMS | |
|
||||
|
||||
- 其它日期样式
|
||||
|
||||
|  |  |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| 设置显示星期:datePickerView.showWeek = YES; | 设置显示星期:datePickerView.showWeek = YES; |
|
||||
| | |
|
||||
|  |  |
|
||||
| 设置添加至今:datePickerView.addToNow = YES; | 设置显示今天:datePickerView.showToday = YES; |
|
||||
| | |
|
||||
|  |  |
|
||||
| 日期单位显示样式:datePickerView.showUnitType = BRShowUnitTypeOnlyCenter; | 设置选择器中间选中行的背景颜色:selectRowColor |
|
||||
|
||||
```objective-c
|
||||
// 设置选择器中间选中行的样式
|
||||
BRPickerStyle *customStyle = [[BRPickerStyle alloc]init];
|
||||
customStyle.selectRowColor = [UIColor blueColor];
|
||||
customStyle.selectRowTextFont = [UIFont boldSystemFontOfSize:20.0f];
|
||||
customStyle.selectRowTextColor = [UIColor redColor];
|
||||
datePickerView.pickerStyle = customStyle;
|
||||
```
|
||||
|
||||
|  |  |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| 样式:BRDatePickerModeYMD (默认非中文环境显示英式日期) | 样式:BRDatePickerModeYM (默认非中文环境显示英式日期) |
|
||||
|
||||
- 几种常见的弹框样式模板
|
||||
|
||||
|  |  |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| 弹框样式模板1:datePickerView.pickerStyle = [BRPickerStyle pickerStyleWithThemeColor:[UIColor blueColor]]; | 弹框样式模板2:datePickerView.pickerStyle = [BRPickerStyle pickerStyleWithDoneTextColor:[UIColor blueColor]]; |
|
||||
| | |
|
||||
|  |  |
|
||||
| 弹框样式模板3:datePickerView.pickerStyle = [BRPickerStyle pickerStyleWithDoneBtnImage:[UIImage imageNamed:@"icon_close"]]; | 添加选择器的头视图:pickerHeaderView |
|
||||
|
||||
```objective-c
|
||||
// 添加选择器头视图(pickerHeaderView)
|
||||
UIView *headerView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 36)];
|
||||
headerView.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.1f];
|
||||
NSArray *unitArr = @[@"年", @"月", @"日"];
|
||||
for (NSInteger i = 0; i < unitArr.count; i++) {
|
||||
CGFloat width = SCREEN_WIDTH / unitArr.count;
|
||||
CGFloat orginX = i * (SCREEN_WIDTH / unitArr.count);
|
||||
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(orginX, 0, width, 36)];
|
||||
label.backgroundColor = [UIColor clearColor];
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
label.font = [UIFont systemFontOfSize:16.0f];
|
||||
label.textColor = [UIColor darkGrayColor];
|
||||
label.text = unitArr[i];
|
||||
[headerView addSubview:label];
|
||||
}
|
||||
datePickerView.pickerHeaderView = headerView;
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 文本选择器:`BRTextPickerView`
|
||||
|
||||
查看 BRTextPickerView.h 头文件,提供了三种类型:
|
||||
|
||||
```objective-c
|
||||
/// 文本选择器类型
|
||||
typedef NS_ENUM(NSInteger, BRTextPickerMode) {
|
||||
/** 单列选择器 */
|
||||
BRTextPickerComponentSingle,
|
||||
/** 多列选择器 */
|
||||
BRTextPickerComponentMulti,
|
||||
/** 多列联动选择器 */
|
||||
BRTextPickerComponentCascade
|
||||
};
|
||||
```
|
||||
|
||||
#### 1. 单列文本选择器
|
||||
|
||||
- 使用示例:
|
||||
|
||||
```objective-c
|
||||
/// 单列文本选择器
|
||||
BRTextPickerView *textPickerView = [[BRTextPickerView alloc]initWithPickerMode:BRTextPickerComponentSingle];
|
||||
textPickerView.title = @"学历";
|
||||
// 设置数据源
|
||||
textPickerView.dataSourceArr = @[@"大专以下", @"大专", @"本科", @"硕士", @"博士", @"博士后"];
|
||||
textPickerView.selectIndex = self.mySelectIndex;
|
||||
textPickerView.singleResultBlock = ^(BRTextModel * _Nullable model, NSInteger index) {
|
||||
NSLog(@"选择的值:%@", model.text);
|
||||
self.mySelectIndex = index;
|
||||
textField.text = model.text;
|
||||
};
|
||||
[textPickerView show];
|
||||
```
|
||||
|
||||
- 设置数据源有3种方式
|
||||
|
||||
```objective-c
|
||||
// 方式1:传字符串数组
|
||||
textPickerView.dataSourceArr = @[@"大专以下", @"大专", @"本科", @"硕士", @"博士", @"博士后"];
|
||||
```
|
||||
|
||||
```objective-c
|
||||
// 方式2:直接传入 plist 文件名(可以将上面的字符串数组放到本地plist文件中,如:education_data.plist)
|
||||
textPickerView.fileName = @"education_data.plist";
|
||||
```
|
||||
|
||||
```objective-c
|
||||
// 方式3:传入一维模型数组(NSArray <BRTextModel *>*)
|
||||
NSArray *dataArr = @[@{@"code": @"1", @"text": @"大专以下"},
|
||||
@{@"code": @"2", @"text": @"大专"},
|
||||
@{@"code": @"3", @"text": @"本科"},
|
||||
@{@"code": @"4", @"text": @"硕士"},
|
||||
@{@"code": @"5", @"text": @"博士"},
|
||||
@{@"code": @"6", @"text": @"博士后"}];
|
||||
// 将上面数组 转为 模型数组(组件内封装的工具方法)
|
||||
NSArray<BRTextModel *> *modelArr = [NSArray br_modelArrayWithJson:dataArr mapper:nil];
|
||||
textPickerView.dataSourceArr = modelArr;
|
||||
```
|
||||
|
||||
说明:当字典key 与 BRTextModel模型的属性不匹配时,需要指定模型属性与字典key的映射关系
|
||||
|
||||
```objective-c
|
||||
/// 单列文本选择器
|
||||
BRTextPickerView *textPickerView = [[BRTextPickerView alloc]initWithPickerMode:BRTextPickerComponentSingle];
|
||||
textPickerView.title = @"融资情况";
|
||||
// 方式3:传入一维模型数组(NSArray <BRTextModel *>*)
|
||||
NSArray *dataArr = @[@{@"key": @"1001", @"value": @"无融资", @"remark": @""},
|
||||
@{@"key": @"2001", @"value": @"天使轮", @"remark": @""},
|
||||
@{@"key": @"3001", @"value": @"A轮", @"remark": @""},
|
||||
@{@"key": @"4001", @"value": @"B轮", @"remark": @""},
|
||||
@{@"key": @"5001", @"value": @"C轮以后", @"remark": @""},
|
||||
@{@"key": @"6001", @"value": @"已上市", @"remark": @""}];
|
||||
// 指定 BRTextModel模型的属性 与 字典key 的映射关系
|
||||
NSDictionary *mapper = @{ @"code": @"key", @"text": @"value", @"extras": @"remark" };
|
||||
// 将上面数组 转为 模型数组(组件内封装的工具方法)
|
||||
NSArray<BRTextModel *> *modelArr = [NSArray br_modelArrayWithJson:dataArr mapper:mapper];
|
||||
textPickerView.dataSourceArr = modelArr;
|
||||
textPickerView.singleResultBlock = ^(BRTextModel * _Nullable model, NSInteger index) {
|
||||
NSLog(@"选择的值:%@", model.text);
|
||||
};
|
||||
[textPickerView show];
|
||||
```
|
||||
|
||||
- 单列文本选择器效果图:
|
||||
|
||||
|  |  |
|
||||
| :----------------------------------------------------------: | :----------------------------------------------------------: |
|
||||
|
||||
|
||||
|
||||
#### 2. 多列文本选择器
|
||||
|
||||
- 使用示例:
|
||||
|
||||
```objective-c
|
||||
/// 多列文本选择器
|
||||
BRTextPickerView *textPickerView = [[BRTextPickerView alloc]initWithPickerMode:BRTextPickerComponentMulti];
|
||||
textPickerView.title = @"多列文本选择器";
|
||||
// 设置数据源
|
||||
textPickerView.dataSourceArr = @[@[@"语文", @"数学", @"英语"], @[@"优秀", @"良好"]];
|
||||
textPickerView.selectIndexs = self.mySelectIndexs;
|
||||
textPickerView.multiResultBlock = ^(NSArray<BRTextModel *> * _Nullable models, NSArray<NSNumber *> * _Nullable indexs) {
|
||||
self.mySelectIndexs = indexs;
|
||||
// 将模型数组元素的 text 属性值,通过分隔符-连接成字符串(组件内封装的工具方法)
|
||||
NSString *selectText = [models br_joinText:@"-"];
|
||||
NSLog(@"选择的结果:%@", selectText);
|
||||
};
|
||||
[textPickerView show];
|
||||
```
|
||||
|
||||
- 多列文本选择器设置数据源同单列一样,也有3种方式:
|
||||
|
||||
```objective-c
|
||||
// 方式1:多维字符串数组
|
||||
textPickerView.dataSourceArr = @[@[@"语文", @"数学", @"英语"], @[@"优秀", @"良好"]];
|
||||
```
|
||||
|
||||
```objective-c
|
||||
// 方式2:直接传入 plist 文件名(可以将上面的数组放到本地plist文件中,如:grade_level_data.plist)
|
||||
textPickerView.fileName = @"grade_level_data.plist";
|
||||
```
|
||||
|
||||
```objective-c
|
||||
// 方式3:传入多维模型数组
|
||||
NSArray *subjectDataArr = @[@{@"subject_id": @"11", @"subject": @"语文"}, @{@"subject_id": @"12", @"subject": @"数学"}, @{@"subject_id": @"13", @"subject": @"英语"}];
|
||||
NSArray *gradeDataArr = @[@{@"grade_id": @"1", @"grade": @"优秀"}, @{@"grade_id": @"2", @"grade": @"良好"}];
|
||||
// 将上面数组 转为 模型数组(组件内封装的工具方法)
|
||||
NSArray *subjectModelArr = [NSArray br_modelArrayWithJson:subjectDataArr mapper:@{ @"code": @"subject_id", @"text": @"subject" }];
|
||||
NSArray *gradeModelArr = [NSArray br_modelArrayWithJson:gradeDataArr mapper:@{ @"code": @"grade_id", @"text": @"grade" }];
|
||||
textPickerView.dataSourceArr = @[subjectModelArr, gradeModelArr];
|
||||
```
|
||||
|
||||
- 另外还可以设置更多自定义样式
|
||||
|
||||
```objective-c
|
||||
/// 多列文本选择器
|
||||
BRTextPickerView *textPickerView = [[BRTextPickerView alloc]initWithPickerMode:BRTextPickerComponentMulti];
|
||||
textPickerView.title = @"自定义多列字符串";
|
||||
textPickerView.dataSourceArr = @[@[@"01", @"02", @"03", @"04", @"05", @"06", @"07", @"08", @"09", @"10", @"11", @"12"], @[@"00", @"10", @"20", @"30", @"40", @"50"]];
|
||||
textPickerView.selectIndexs = self.mySelectIndexs;
|
||||
textPickerView.multiResultBlock = ^(NSArray<BRTextModel *> * _Nullable models, NSArray<NSNumber *> * _Nullable indexs) {
|
||||
self.mySelectIndexs = indexs;
|
||||
// 将模型数组元素的 text 属性值,通过:分隔符 连接成字符串(组件内封装的工具方法)
|
||||
NSString *selectText = [models br_joinText:@":"];
|
||||
NSLog(@"选择的结果:%@", selectText);
|
||||
};
|
||||
|
||||
// 设置自定义样式
|
||||
BRPickerStyle *customStyle = [[BRPickerStyle alloc]init];
|
||||
// 设置 picker 的列宽
|
||||
customStyle.columnWidth = 30;
|
||||
// 设置 picker 的列间隔
|
||||
customStyle.columnSpacing = 60;
|
||||
// 设置圆角矩形背景
|
||||
// 方式1:使用系统自带样式,保留iOS14之后系统默认的圆角样式。
|
||||
customStyle.clearPickerNewStyle = NO;
|
||||
// 方式2:可以使用UIView自定义一个圆角矩形视图rectView,并添加到 alertView 上也能实现同样的效果([textPickerView.alertView addSubview:rectView];)
|
||||
// 设置选择器中间选中行的样式
|
||||
customStyle.selectRowTextFont = [UIFont boldSystemFontOfSize:20.0f];
|
||||
customStyle.selectRowTextColor = [UIColor blueColor];
|
||||
textPickerView.pickerStyle = customStyle;
|
||||
|
||||
[textPickerView show];
|
||||
```
|
||||
|
||||
- 多列文本选择器效果图:
|
||||
|
||||
|  |  |
|
||||
| :----------------------------------------------------------: | :----------------------------------------------------------: |
|
||||
|
||||
|
||||
|
||||
#### 3. 多列联动文本选择器
|
||||
|
||||
- 使用示例:
|
||||
|
||||
```objective-c
|
||||
/// 多列联动文本选择器
|
||||
BRTextPickerView *textPickerView = [[BRTextPickerView alloc]initWithPickerMode:BRTextPickerComponentCascade];
|
||||
textPickerView.title = @"多列联动文本选择器";
|
||||
NSArray *dataArr = @[
|
||||
@{
|
||||
@"text" : @"浙江省",
|
||||
@"children" : @[
|
||||
@{ @"text": @"杭州市", @"children": @[@{ @"text": @"西湖区" }, @{ @"text": @"滨江区" }] },
|
||||
@{ @"text": @"宁波市", @"children": @[@{ @"text": @"海曙区" }, @{ @"text": @"江北区" }] },
|
||||
@{ @"text": @"温州市", @"children": @[@{ @"text": @"鹿城区" }, @{ @"text": @"龙湾区" }] }
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"text" : @"江苏省",
|
||||
@"children" : @[
|
||||
@{ @"text": @"南京市", @"children": @[@{ @"text": @"玄武区" }, @{ @"text": @"秦淮区" }] },
|
||||
@{ @"text": @"苏州市", @"children": @[@{ @"text": @"虎丘区" }, @{ @"text": @"吴中区" }] }
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"text" : @"辽宁省",
|
||||
@"children" : @[
|
||||
@{ @"text": @"沈阳市", @"children": @[@{ @"text": @"沈河区" }, @{ @"text": @"和平区" }] },
|
||||
@{ @"text": @"大连市", @"children": @[@{ @"text": @"中山区" }, @{ @"text": @"金州区" }] }
|
||||
]
|
||||
}
|
||||
];
|
||||
// 设置数据源:传树状结构模型数组(NSArray <BRTextModel *>*)
|
||||
textPickerView.dataSourceArr = [NSArray br_modelArrayWithJson:dataArr mapper:nil];
|
||||
textPickerView.selectIndexs = self.mySelectIndexs;
|
||||
textPickerView.multiResultBlock = ^(NSArray<BRTextModel *> * _Nullable models, NSArray<NSNumber *> * _Nullable indexs) {
|
||||
self.mySelectIndexs = indexs;
|
||||
// 将模型数组元素的 text 属性值,通过-分隔符 连接成字符串(组件内封装的工具方法)
|
||||
NSString *selectText = [models br_joinText:@"-"];
|
||||
NSLog(@"选择的结果:%@", selectText);
|
||||
};
|
||||
[textPickerView show];
|
||||
```
|
||||
|
||||
|
||||
|
||||
- 实现省、市、区/县选择(通常省市区/县数据是从自己业务后台API获取,这里使用本地数据源仅做参考,文件下载地址:[region_tree_data.json](https://raw.githubusercontent.com/agiapp/BRPickerView/master/BRPickerViewDemo/DataFile/region_tree_data.json))
|
||||
|
||||
```objective-c
|
||||
// 地区
|
||||
BRTextPickerView *textPickerView = [[BRTextPickerView alloc]initWithPickerMode:BRTextPickerComponentCascade];
|
||||
textPickerView.title = @"请选择地区";
|
||||
// 设置数据源:传入本地json文件名(可以下载Demo中的 region_tree_data.json 文件放到自己的项目中)
|
||||
textPickerView.fileName = @"region_tree_data.json";
|
||||
// 设置选择器显示的列数(即层级数),默认是根据数据源层级动态计算显示。如:设置1则只显示前1列数据(即只显示省);设置2则只显示前2列数据(即只显示省、市);设置3则只显示前3列数据(即显示省、市、区)
|
||||
textPickerView.showColumnNum = 3;
|
||||
textPickerView.selectIndexs = self.addressSelectIndexs;
|
||||
textPickerView.multiResultBlock = ^(NSArray<BRTextModel *> * _Nullable models, NSArray<NSNumber *> * _Nullable indexs) {
|
||||
self.addressSelectIndexs = indexs;
|
||||
// 将模型数组元素的 text 属性值,通过-分隔符 连接成字符串(组件内封装的工具方法)
|
||||
NSString *selectText = [models br_joinText:@"-"];
|
||||
NSLog(@"选择的结果:%@", selectText);
|
||||
textField.text = selectText;
|
||||
};
|
||||
[textPickerView show];
|
||||
```
|
||||
|
||||
- 地址文本选择器的3种显示效果
|
||||
|
||||
|  |  |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| 样式1:textPickerView.showColumnNum = 3; | 样式2:textPickerView.showColumnNum = 2; |
|
||||
| | |
|
||||
|  | |
|
||||
| 样式3:textPickerView.showColumnNum = 1; | |
|
||||
|
||||
- 处理树状结构数据
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "200",
|
||||
"message": "OK",
|
||||
"data": [
|
||||
{
|
||||
"adcode": "330000",
|
||||
"name": "浙江省",
|
||||
"districts" : [
|
||||
{ "adcode" : "330100", "name": "杭州市", "districts": [{ "adcode" : "330106", "name": "西湖区" }, { "adcode" : "330108", "name": "滨江区" }] },
|
||||
{ "adcode" : "330200", "name": "宁波市", "districts": [{ "adcode" : "330203", "name": "海曙区" }, { "adcode" : "330205", "name": "江北区" }] },
|
||||
{ "adcode" : "330300", "name": "温州市", "districts": [{ "adcode" : "330302", "name": "鹿城区" }, { "adcode" : "330303", "name": "龙湾区" }] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"adcode": "320000",
|
||||
"name": "江苏省",
|
||||
"districts" : [
|
||||
{ "adcode" : "320100", "name": "南京市", "districts": [{ "adcode" : "320102", "name": "玄武区" }, { "adcode" : "320104", "name": "秦淮区" }] },
|
||||
{ "adcode" : "320500", "name": "苏州市", "districts": [{ "adcode" : "320505", "name": "虎丘区" }, { "adcode" : "320506", "name": "吴中区" }] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"adcode": "210000",
|
||||
"name": "辽宁省",
|
||||
"districts" : [
|
||||
{ "adcode" : "210100", "name": "沈阳市", "districts": [{ "adcode" : "210103", "name": "沈河区" }, { "adcode" : "210102", "name": "和平区" }] },
|
||||
{ "adcode" : "210200", "name": "大连市", "districts": [{ "adcode" : "210202", "name": "中山区" }, { "adcode" : "210213", "name": "金州区" }] }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```objective-c
|
||||
/// 多列联动文本选择器
|
||||
BRTextPickerView *textPickerView = [[BRTextPickerView alloc]initWithPickerMode:BRTextPickerComponentCascade];
|
||||
textPickerView.title = @"多列联动文本选择器";
|
||||
|
||||
// 接收网络请求结果数据(下面省略号表示省略部分代码)
|
||||
NSArray *dataArr = ...... responseObject[@"data"];
|
||||
// 指定 BRTextModel模型的属性 与 字典key 的映射关系
|
||||
NSDictionary *mapper = @{ @"code": @"adcode", @"text": @"name", @"children": @"districts" };
|
||||
// 将上面数组 转为 模型数组(组件内封装的工具方法)
|
||||
NSArray<BRTextModel *> *modelArr = [NSArray br_modelArrayWithJson:dataArr mapper:mapper];
|
||||
textPickerView.dataSourceArr = modelArr;
|
||||
textPickerView.multiResultBlock = ^(NSArray<BRTextModel *> * _Nullable models, NSArray<NSNumber *> * _Nullable indexs) {
|
||||
// 将模型数组元素的 text 属性值,通过-分隔符 连接成字符串(组件内封装的工具方法)
|
||||
NSString *selectText = [models br_joinText:@"-"];
|
||||
NSLog(@"选择的结果:%@", selectText);
|
||||
};
|
||||
[textPickerView show];
|
||||
```
|
||||
|
||||
- 处理扁平结构数据
|
||||
|
||||
```json
|
||||
{
|
||||
"Code" : 200,
|
||||
"Msg" : "获取成功",
|
||||
"Result" : [
|
||||
{
|
||||
"ParentID" : "-1",
|
||||
"ParentName" : "",
|
||||
"CategoryID" : "330000",
|
||||
"CategoryName" : "浙江省"
|
||||
},
|
||||
{
|
||||
"ParentID" : "-1",
|
||||
"ParentName" : "",
|
||||
"CategoryID" : "320000",
|
||||
"CategoryName" : "江苏省"
|
||||
},
|
||||
{
|
||||
"ParentID" : "-1",
|
||||
"ParentName" : "",
|
||||
"CategoryID" : "210000",
|
||||
"CategoryName" : "辽宁省"
|
||||
},
|
||||
{
|
||||
"ParentID" : "330000",
|
||||
"ParentName" : "浙江省",
|
||||
"CategoryID" : "330100",
|
||||
"CategoryName" : "杭州市"
|
||||
},
|
||||
{
|
||||
"ParentID" : "330000",
|
||||
"ParentName" : "浙江省",
|
||||
"CategoryID" : "330200",
|
||||
"CategoryName" : "宁波市"
|
||||
},
|
||||
{
|
||||
"ParentID" : "330000",
|
||||
"ParentName" : "浙江省",
|
||||
"CategoryID" : "330300",
|
||||
"CategoryName" : "温州市"
|
||||
},
|
||||
{
|
||||
"ParentID" : "320000",
|
||||
"ParentName" : "江苏省",
|
||||
"CategoryID" : "320100",
|
||||
"CategoryName" : "南京市"
|
||||
},
|
||||
{
|
||||
"ParentID" : "320000",
|
||||
"ParentName" : "江苏省",
|
||||
"CategoryID" : "320500",
|
||||
"CategoryName" : "苏州市"
|
||||
},
|
||||
{
|
||||
"ParentID" : "210000",
|
||||
"ParentName" : "辽宁省",
|
||||
"CategoryID" : "210100",
|
||||
"CategoryName" : "沈阳市"
|
||||
},
|
||||
{
|
||||
"ParentID" : "210000",
|
||||
"ParentName" : "辽宁省",
|
||||
"CategoryID" : "210200",
|
||||
"CategoryName" : "大连市"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```objective-c
|
||||
/// 多列联动文本选择器
|
||||
BRTextPickerView *textPickerView = [[BRTextPickerView alloc]initWithPickerMode:BRTextPickerComponentCascade];
|
||||
textPickerView.title = @"多列联动文本选择器";
|
||||
|
||||
// 接收网络请求结果数据(下面省略号表示省略部分代码)
|
||||
NSArray *dataArr = ...... responseObject[@"Result"];
|
||||
// 指定 BRTextModel模型的属性 与 字典key 的映射关系
|
||||
NSDictionary *mapper = @{ @"parentCode": @"ParentID", @"code": @"CategoryID", @"text": @"CategoryName" };
|
||||
// 1.先将上面数组 转为 模型数组(组件内封装的工具方法)。如果数据源是多个数组,需要自己先手动组装成一个NSArray<BRTextModel *>类型的扁平结构模型数组。
|
||||
NSArray<BRTextModel *> *listModelArr = [NSArray br_modelArrayWithJson:dataArr mapper:mapper];
|
||||
// 2.将扁平结构模型数组 转成 树状结构模型数组(组件内封装的工具方法)
|
||||
NSArray<BRTextModel *> *treeModelArr = [listModelArr br_buildTreeArray];
|
||||
textPickerView.dataSourceArr = treeModelArr;
|
||||
|
||||
textPickerView.multiResultBlock = ^(NSArray<BRTextModel *> * _Nullable models, NSArray<NSNumber *> * _Nullable indexs) {
|
||||
// 将模型数组元素的 text 属性值,通过-分隔符 连接成字符串(组件内封装的工具方法)
|
||||
NSString *selectText = [models br_joinText:@"-"];
|
||||
NSLog(@"选择的结果:%@", selectText);
|
||||
// 获取选择模型指定属性(如:code)组成的数组(组件内封装的工具方法)
|
||||
NSArray *selectIDs = [models br_getValueArr:@"code"];
|
||||
};
|
||||
|
||||
// 设置选择器中间选中行的样式
|
||||
BRPickerStyle *customStyle = [[BRPickerStyle alloc]init];
|
||||
customStyle.selectRowTextFont = [UIFont boldSystemFontOfSize:20.0f];
|
||||
customStyle.selectRowTextColor = [UIColor blueColor];
|
||||
customStyle.columnWidth = 80;
|
||||
customStyle.columnSpacing = 10;
|
||||
textPickerView.pickerStyle = customStyle;
|
||||
|
||||
[textPickerView show];
|
||||
```
|
||||
|
||||
- 多列联动文本选择器效果图:
|
||||
|
||||
|  |  |
|
||||
| :----------------------------------------------------------: | :----------------------------------------------------------: |
|
||||
|
||||
|
||||
|
||||
补充说明:对于一些需要特殊定制弹框的应用场景,可以使用下面的方法把日期选择器/文本选择器到指定容器视图上,实现个性化的弹框需求。
|
||||
|
||||
```objective-c
|
||||
/// 扩展一:添加选择器到指定容器视图上
|
||||
/// 应用场景:可将中间的滚轮选择器 pickerView 视图(不包含蒙层及标题栏)添加到任何自定义视图上(会自动填满容器视图),也方便自定义更多的弹框样式
|
||||
/// 补充说明:如果是自定义确定按钮,需要回调默认选择的值:只需在自定义确定按钮的点击事件方法里执行一下 doneBlock 回调(目的是去触发组件内部执行 resultBlock 回调,进而回调默认选择的值)
|
||||
/// @param view 容器视图
|
||||
- (void)addPickerToView:(nullable UIView *)view;
|
||||
```
|
||||
|
||||
|
||||
|
||||
# 更新记录
|
||||
|
||||
#### 2026-05-20(V3.0.0)
|
||||
|
||||
- 移除 BRAddressPickerView、BRStringPickerView 废弃组件
|
||||
- 修改库支持的平台和版本为 iOS 11.0+
|
||||
|
||||
- fix:[#355](https://github.com/agiapp/BRPickerView/issues/355)
|
||||
|
||||
#### 2025-10-24(V2.9.9)
|
||||
|
||||
- Merge pull request [#329](https://github.com/agiapp/BRPickerView/pull/329)、 [#348](https://github.com/agiapp/BRPickerView/pull/348)
|
||||
|
||||
#### 2025-10-17(V2.9.8)
|
||||
|
||||
- fix:[#345](https://github.com/agiapp/BRPickerView/issues/345) 、[#349](https://github.com/agiapp/BRPickerView/issues/349)
|
||||
|
||||
#### 2025-05-27(V2.9.7)
|
||||
|
||||
- 修改 Swift Package Manager 集成方式
|
||||
|
||||
#### 2025-05-21(V2.9.6)
|
||||
|
||||
- fix:[#318](https://github.com/agiapp/BRPickerView/issues/318)
|
||||
|
||||
#### 2025-04-22(V2.9.5)
|
||||
|
||||
- fix:[#319](https://github.com/agiapp/BRPickerView/issues/319) 、[#326](https://github.com/agiapp/BRPickerView/issues/326) 、[#340](https://github.com/agiapp/BRPickerView/issues/340)
|
||||
|
||||
#### 2025-03-16(V2.9.3)
|
||||
|
||||
- [#336](https://github.com/agiapp/BRPickerView/issues/336) :优化选择年月日时分秒时,UI显示最后一个秒显示不全问题
|
||||
|
||||
#### 2024-07-24(V2.9.1)
|
||||
|
||||
- 新增 maxTextLines 属性
|
||||
- 取消 selectRowAnimated 属性 readonly 限制
|
||||
|
||||
#### 2024-07-17(V2.9.0)
|
||||
|
||||
- 新增 BRTextPickerView 文本选择组件(用于替代BRAddressPickerView、BRStringPickerView组件)
|
||||
|
||||
#### 2024-07-02(V2.8.8)
|
||||
|
||||
- [#310](https://github.com/agiapp/BRPickerView/issues/310) :更新本地省市区数据源数据
|
||||
|
||||
- [#314](https://github.com/agiapp/BRPickerView/issues/314) :修改maskView视图命名,解决因命名冲突在iOS 18 上出现的崩溃问题
|
||||
|
||||
#### 2024-05-28(V2.8.7)
|
||||
|
||||
- 解决已知问题:[#308](https://github.com/agiapp/BRPickerView/issues/308) 、[#309](https://github.com/agiapp/BRPickerView/issues/309)
|
||||
- 时间选择器新增 `twelveHourMode` 属性,支持设置12小时制
|
||||
- 支持 Swift Package Manager
|
||||
|
||||
#### 2024-04-28(V2.8.5)
|
||||
|
||||
- 解决已知问题:[#305](https://github.com/agiapp/BRPickerView/issues/305)
|
||||
- 添加可设置选择器组件的列宽属性:`columnWidth`
|
||||
- 添加可设置`BRStringPickerView` 选择器组件的列间隔属性:`columnSpacing`
|
||||
|
||||
#### 2024-04-23(V2.8.2)
|
||||
|
||||
- 解决已知问题:[#304](https://github.com/agiapp/BRPickerView/issues/304)
|
||||
|
||||
- Add PrivacyInfo.xcprivacy
|
||||
|
||||
#### 2022-07-08(V2.8.0)
|
||||
|
||||
- 优化代码。
|
||||
|
||||
#### 2022-06-16(V2.7.8)
|
||||
|
||||
- 优化代码。
|
||||
|
||||
#### 2022-03-30(V2.7.7)
|
||||
|
||||
- 优化代码。
|
||||
|
||||
#### 2021-10-09(V2.7.6)
|
||||
|
||||
- 适配iOS15
|
||||
|
||||
#### 2021-05-28(V2.7.5)
|
||||
|
||||
- 日期选择器新增属性:`monthNames` 和 `customUnit`
|
||||
|
||||
- 解决已知问题:[#232](https://github.com/agiapp/BRPickerView/issues/232) 、[#231](https://github.com/agiapp/BRPickerView/issues/231) 、[#230](https://github.com/agiapp/BRPickerView/issues/230) 、[#227](https://github.com/agiapp/BRPickerView/issues/227) 、[#225](https://github.com/agiapp/BRPickerView/issues/225) 、[#219](https://github.com/agiapp/BRPickerView/issues/219) 、[#206](https://github.com/agiapp/BRPickerView/issues/206)
|
||||
|
||||
#### 2020-09-25(V2.7.3)
|
||||
|
||||
- 适配选择器iOS14的样式:[#189](https://github.com/agiapp/BRPickerView/issues/189) 、[#191](https://github.com/agiapp/BRPickerView/issues/191)
|
||||
|
||||
#### 2020-09-23(V2.7.2)
|
||||
|
||||
- 日期选择器新增添加自定义字符串属性:`firstRowContent` 和 `lastRowContent`
|
||||
- 解决日期选择器设置最小日期时,存在的联动不正确的问题:[#184](https://github.com/agiapp/BRPickerView/issues/184)
|
||||
|
||||
#### 2020-08-28(V2.7.0)
|
||||
|
||||
- 日期选择器添加 `nonSelectableDates` 属性:[#178](https://github.com/agiapp/BRPickerView/issues/178)
|
||||
- 优化选中行文本显示:[#177](https://github.com/agiapp/BRPickerView/issues/177)
|
||||
|
||||
#### 2020-08-16(V2.6.8)
|
||||
|
||||
- 优化代码,适配 iPad 分屏显示
|
||||
- 新增 `keyView` 属性(即组件的父视图:可以将组件添加到 自己获取的 keyWindow 上,或页面的 view 上)
|
||||
|
||||
#### 2020-08-09(V2.6.7)
|
||||
|
||||
- 适配 iOS14
|
||||
|
||||
#### 2020-08-06(V2.6.6)
|
||||
|
||||
- 修复 [#163](https://github.com/agiapp/BRPickerView/issues/163) 和 [#170](https://github.com/agiapp/BRPickerView/issues/170)
|
||||
|
||||
#### 2020-07-18(V2.6.5)
|
||||
|
||||
- 字符串选择器新增支持多级联动选择
|
||||
|
||||
#### 2020-06-24(V2.6.3)
|
||||
|
||||
- 日期选择器新增属性:`timeZone` 和 `addCustomString`
|
||||
|
||||
#### 2020-05-12(V2.6.2)
|
||||
|
||||
- 实现 [#145](#145) 和 [#146](#146) 需求
|
||||
|
||||
#### 2020-04-30(V2.6.0)
|
||||
|
||||
- 新增样式属性:`selectRowTextColor` 和 `selectRowTextFont`
|
||||
- 日期选择器新增数字显示属性:`numberFullName`
|
||||
- 优化代码,添加 `BRDatePickerModeYMD` 支持国际化英式日期
|
||||
|
||||
- 修复 [#143](#143)
|
||||
|
||||
#### 2020-04-27(V2.5.8)
|
||||
|
||||
- 修复 [#138](https://github.com/agiapp/BRPickerView/issues/138) 和 [#142](https://github.com/agiapp/BRPickerView/issues/142)
|
||||
- 日期选择器新增 `descending` 属性,支持降序的时间列表
|
||||
- 更新地址选择器地区数据源
|
||||
|
||||
#### 2020-03-31(V2.5.7)
|
||||
|
||||
- 优化代码,解决已知问题
|
||||
|
||||
#### 2020-02-26(V2.5.6)
|
||||
|
||||
- 优化代码,兼容部分国际化日期样式
|
||||
|
||||
#### 2020-02-24(V2.5.5)
|
||||
|
||||
- 添加设置选择器选中行背景颜色的功能,新增属性 `selectRowColor`
|
||||
|
||||
#### 2020-01-31(V2.5.3)
|
||||
|
||||
- 新增属性:`pickerHeaderView`、`pickerFooterView`
|
||||
- 新增刷新选择器数据方法:`reloadData`
|
||||
|
||||
#### 2020-01-05(V2.5.1)
|
||||
|
||||
- 优化代码,添加 `BRDatePickerModeYM` 支持国际化英式日期
|
||||
|
||||
#### 2020-01-02(V2.5.0)
|
||||
|
||||
- 日期选择器新增属性:`showUnitType`(日期单位显示样式)、`minuteInterval`、`secondInterval`
|
||||
- 封装了常用的几种模板样式,使用更加简单便捷
|
||||
- 框架内默认适配深色模式显示
|
||||
|
||||
#### 2019-12-26(V2.4.6)
|
||||
|
||||
- 添加支持动态更新属性 `title` 、 `selectDate`、`pickerMode` 的值
|
||||
- 日期选择器添加 `showWeek` 属性,及新增 `BRDatePickerModeMS` 日期类型
|
||||
- 优化选择器【用法二】的使用,新增选择器滚动选择时回调的属性
|
||||
|
||||
#### 2019-11-28(V2.4.5)
|
||||
|
||||
- 日期选择器新增选择 ”至今“ 和 显示 ”今天“ 的功能,见以下两个属性:
|
||||
|
||||
`showToday` :控制是否显示 “今天” ,默认为 NO
|
||||
|
||||
`addToNow`:控制是否添加选择 “至今”,默认为 NO
|
||||
|
||||
#### 2019-11-26(V2.4.3)
|
||||
|
||||
- 日期选择器新增以下三种选择类型:
|
||||
|
||||
`BRDatePickerModeYMDHMS`(年月日时分秒)、`BRDatePickerModeYMDE`(年月日星期)、`BRDatePickerModeHMS`(时分秒)
|
||||
|
||||
- 更新地址选择器地区数据源
|
||||
|
||||
#### 2019-11-07(V2.4.2)
|
||||
|
||||
- 日期选择器添加:BRDatePickerModeYMDH(yyyy-MM-dd HH)类型
|
||||
- 地址选择器添加:selectIndexs 属性,可根据索引去设置默认选择
|
||||
- 适配横屏及刘海屏安全区域显示效果
|
||||
|
||||
#### 2019-11-04(V2.4.0)
|
||||
|
||||
- 优化选择器子目录管理,方便轻量级、模块化集成
|
||||
|
||||
`pod 'BRPickerView'` // 集成全部的功能
|
||||
|
||||
`pod 'BRPickerView/DatePickerView'` // 仅集成日期选择器的功能
|
||||
|
||||
`pod 'BRPickerView/AddressPickerView'` // 仅集成地址选择器的功能
|
||||
|
||||
`pod 'BRPickerView/StringPickerView'` // 仅集成字符串选择器的功能
|
||||
|
||||
#### 2019-11-01(V2.3.8)
|
||||
|
||||
- 优化代码,添加更多的自定义样式属性
|
||||
|
||||
#### 2019-10-30(V2.3.6)
|
||||
|
||||
- 优化代码,添加国际化支持
|
||||
|
||||
#### 2019-10-26(V2.3.5)
|
||||
|
||||
- 添加传统的创建对象设置属性的使用方式
|
||||
- 开放设置选择器颜色及样式,适配深色模式
|
||||
- 更新省市区数据源,数据与政府官网最新公布的一致(参见:[行政区划代码](http://www.mca.gov.cn/article/sj/xzqh/2019/))
|
||||
- 支持将选择器添加到指定容器视图上(见BaseView.h文件,扩展一方法)
|
||||
- 支持将子视图添加到选择器上(见BaseView.h文件,扩展二方法)
|
||||
- 优化代码,配置Pod库的层级目录
|
||||
|
||||
#### 2018-04-27(V2.2.1):
|
||||
|
||||
- 修复bug,适配iPad和横屏显示。
|
||||
- 优化代码,提高框架适应性,降低内存消耗。
|
||||
|
||||
#### 2018-04-03(V2.2.0)
|
||||
|
||||
- 时间选择器新添加了7种显示类型(BRDatePickerMode),可根据自己项目的需求选择性使用。
|
||||
- 适配横屏,及 iPhoneX 底部安全区域。
|
||||
- 修改了最小时间和最大时间的参数名称(以前版本是传 NSString 类型, 现在传 NSDate 类型)
|
||||
- 修复比较时间大小时出现的bug。
|
||||
|
||||
#### 2018-03-19(V2.1.3)
|
||||
|
||||
- 修改地址选择器确认选择后的回调参数。
|
||||
- 现修改如下:可通过省市区的模型获取省市区的 name(名称)、code(id)、index(索引)`resultBlock:^(BRProvinceModel *province, BRCityModel *city, BRAreaModel *area) {}`
|
||||
- 去掉第三方依赖库 `MJExtension` ,修改为手动解析地址数据源。
|
||||
|
||||
#### 2018-03-11(V2.1.2)
|
||||
|
||||
- 重命名了Github用户名,更新项目相关的路径。(提示:pod之前的版本不受影响)
|
||||
|
||||
#### 2018-02-28(V2.1.1)
|
||||
|
||||
- 修复某些情况下无法用bundle加载本地数据源(BRCity.plist)bug。
|
||||
|
||||
#### 2018-01-26(V2.1.0)
|
||||
|
||||
- 给地址选择器添加了一个方法(见方法4),提供数据源参数,支持外部传入地区数据源。
|
||||
- 提示:要注意数据源格式,参考 BRCity.json。可以把 BRCity.json 文件的内容放到后台去维护,通过后台接口获取地区数据源(即 BRCity.json 文件的内容)。
|
||||
|
||||
#### 2018-01-25(V2.0.0)
|
||||
|
||||
- 更新了地址数据源(BRCity.plist),地区信息是2018年最新最全的,与微信的地区信息完全一致。
|
||||
- 支持自定义默认选择地址(格式:@[@"浙江省", @"杭州市", @"西湖区"]),支持下次点击进入地址选择器时,默认地址为上次选择的结果。
|
||||
- 修改了日期选择器、地址选择器、字符串选择器的接口方法(删除了之前的方法2)。
|
||||
- 添加了地址选择器显示类型,支持3种显示:只显示省份、显示省份和城市、显示省市区。
|
||||
|
||||
#### 2018-01-05(V1.3.0)
|
||||
|
||||
- 添加取消选择的回调方法(点击背景或取消按钮会执行 `cancelBlock` )
|
||||
- 合并了字符串选择器 数组数据源和plist数据源对应的方法,`dataSource` 参数支持两种类型:
|
||||
|
||||
#### 2018-01-02(V1.2.0)
|
||||
|
||||
- 添加支持自定义主题颜色的方法。
|
||||
|
||||
#### 2017-11-26(V1.1.0)
|
||||
|
||||
- 更换第三方依赖库。
|
||||
- 用MJExtension 替换了 原来的YYModel,以前没有注意导入YYModel,同时又导入YYKit会导致重复导入而冲突(另外使用YYModel时,手动导入和pod导入 其中的头文件和方法名也不一样,所以很容易出错)。
|
||||
|
||||
#### 2017-11-16(V1.0.0)
|
||||
|
||||
- 初始版本!
|
||||
|
||||
# 许可证
|
||||
|
||||
BRPickerView 使用 MIT 许可证,详情见 LICENSE 文件。
|
||||
|
|
@ -6,6 +6,16 @@ PODS:
|
|||
- AMapFoundation-NO-IDFA (>= 1.9.0)
|
||||
- AMapNavi-NO-IDFA (11.2.000):
|
||||
- AMapFoundation-NO-IDFA (>= 1.9.0)
|
||||
- BRPickerView (3.0.0):
|
||||
- BRPickerView/Default (= 3.0.0)
|
||||
- BRPickerView/Core (3.0.0)
|
||||
- BRPickerView/DatePicker (3.0.0):
|
||||
- BRPickerView/Core
|
||||
- BRPickerView/Default (3.0.0):
|
||||
- BRPickerView/DatePicker
|
||||
- BRPickerView/TextPicker
|
||||
- BRPickerView/TextPicker (3.0.0):
|
||||
- BRPickerView/Core
|
||||
- CocoaLumberjack/Core (3.9.1)
|
||||
- CocoaLumberjack/Swift (3.9.1):
|
||||
- CocoaLumberjack/Core
|
||||
|
|
@ -178,6 +188,7 @@ DEPENDENCIES:
|
|||
- AlipaySDK-iOS
|
||||
- AMapLocation-NO-IDFA
|
||||
- AMapNavi-NO-IDFA
|
||||
- BRPickerView
|
||||
- CocoaLumberjack/Swift
|
||||
- CocoaMQTT
|
||||
- GYSDK
|
||||
|
|
@ -220,6 +231,7 @@ SPEC REPOS:
|
|||
- AMapFoundation-NO-IDFA
|
||||
- AMapLocation-NO-IDFA
|
||||
- AMapNavi-NO-IDFA
|
||||
- BRPickerView
|
||||
- CocoaLumberjack
|
||||
- CocoaMQTT
|
||||
- Differentiator
|
||||
|
|
@ -284,6 +296,7 @@ SPEC CHECKSUMS:
|
|||
AMapFoundation-NO-IDFA: a2e3c895398d7ee757278e1a0a8f9359da4b146e
|
||||
AMapLocation-NO-IDFA: 7cd8fc837ea41edfbf4d937cd20572e277b77d18
|
||||
AMapNavi-NO-IDFA: d55b9b138c6e540f737c689975cae2c9dbd1026a
|
||||
BRPickerView: cd2e0e3aa87af062bc7a1b6f78d3dfd5f04f04bb
|
||||
CocoaLumberjack: e4ba3b414dfca8c1916c6303d37f63b3a95134c6
|
||||
CocoaMQTT: 1e2fa493d57045d66fb1eba2bb5ffb8d77039c60
|
||||
Differentiator: e8497ceab83c1b10ca233716d547b9af21b9344d
|
||||
|
|
@ -334,6 +347,6 @@ SPEC CHECKSUMS:
|
|||
YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54
|
||||
ZXSDK: 786338c0a18e98e03eda00699c3bfd2700b97117
|
||||
|
||||
PODFILE CHECKSUM: 4d254b7f0c48f2a2100703f9ac600d5d826b586a
|
||||
PODFILE CHECKSUM: 848cd9ba02b2f1c209ac9eef708dd2c43b005385
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1600"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "941104F296513E17138328984384286C"
|
||||
BuildableName = "BRPickerView.Privacy.bundle"
|
||||
BlueprintName = "BRPickerView-BRPickerView.Privacy"
|
||||
ReferencedContainer = "container:Pods.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
58
Pods/Pods.xcodeproj/xcuserdata/yanghong.xcuserdatad/xcschemes/BRPickerView.xcscheme
generated
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1600"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D505645C3F99EB1E8B6529D64D2C3E1C"
|
||||
BuildableName = "BRPickerView.framework"
|
||||
BlueprintName = "BRPickerView"
|
||||
ReferencedContainer = "container:Pods.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
|
|
@ -34,6 +34,16 @@
|
|||
<key>isShown</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>BRPickerView-BRPickerView.Privacy.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>BRPickerView.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>CocoaLumberjack-CocoaLumberjackPrivacy.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>${PODS_DEVELOPMENT_LANGUAGE}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
@interface PodsDummy_BRPickerView : NSObject
|
||||
@end
|
||||
@implementation PodsDummy_BRPickerView
|
||||
@end
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#ifdef __OBJC__
|
||||
#import <UIKit/UIKit.h>
|
||||
#else
|
||||
#ifndef FOUNDATION_EXPORT
|
||||
#if defined(__cplusplus)
|
||||
#define FOUNDATION_EXPORT extern "C"
|
||||
#else
|
||||
#define FOUNDATION_EXPORT extern
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#ifdef __OBJC__
|
||||
#import <UIKit/UIKit.h>
|
||||
#else
|
||||
#ifndef FOUNDATION_EXPORT
|
||||
#if defined(__cplusplus)
|
||||
#define FOUNDATION_EXPORT extern "C"
|
||||
#else
|
||||
#define FOUNDATION_EXPORT extern
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#import "BRPickerView.h"
|
||||
#import "BRPickerAlertView.h"
|
||||
#import "BRPickerStyle.h"
|
||||
#import "BRPickerViewMacro.h"
|
||||
#import "NSBundle+BRPickerView.h"
|
||||
#import "BRDatePickerView+BR.h"
|
||||
#import "BRDatePickerView.h"
|
||||
#import "NSDate+BRPickerView.h"
|
||||
#import "BRTextModel.h"
|
||||
#import "BRTextPickerView.h"
|
||||
|
||||
FOUNDATION_EXPORT double BRPickerViewVersionNumber;
|
||||
FOUNDATION_EXPORT const unsigned char BRPickerViewVersionString[];
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
||||
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/BRPickerView
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/BRPickerView
|
||||
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
SKIP_INSTALL = YES
|
||||
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
framework module BRPickerView {
|
||||
umbrella header "BRPickerView-umbrella.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
||||
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/BRPickerView
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/BRPickerView
|
||||
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
SKIP_INSTALL = YES
|
||||
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
|
||||
24
Pods/Target Support Files/BRPickerView/ResourceBundle-BRPickerView.Privacy-BRPickerView-Info.plist
generated
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>${PODS_DEVELOPMENT_LANGUAGE}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -64,6 +64,31 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|||
SOFTWARE.
|
||||
|
||||
|
||||
## BRPickerView
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 91renb
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
## CocoaLumberjack
|
||||
|
||||
BSD 3-Clause License
|
||||
|
|
|
|||
|
|
@ -105,6 +105,37 @@ SOFTWARE.
|
|||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>MIT License
|
||||
|
||||
Copyright (c) 2019 91renb
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>MIT</string>
|
||||
<key>Title</key>
|
||||
<string>BRPickerView</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>BSD 3-Clause License
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
${PODS_ROOT}/Target Support Files/Pods-QuickLocation/Pods-QuickLocation-frameworks.sh
|
||||
${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework
|
||||
${BUILT_PRODUCTS_DIR}/BRPickerView/BRPickerView.framework
|
||||
${BUILT_PRODUCTS_DIR}/CocoaLumberjack/CocoaLumberjack.framework
|
||||
${BUILT_PRODUCTS_DIR}/CocoaMQTT/CocoaMQTT.framework
|
||||
${BUILT_PRODUCTS_DIR}/Differentiator/Differentiator.framework
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BRPickerView.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CocoaLumberjack.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CocoaMQTT.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Differentiator.framework
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
${PODS_ROOT}/Target Support Files/Pods-QuickLocation/Pods-QuickLocation-frameworks.sh
|
||||
${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework
|
||||
${BUILT_PRODUCTS_DIR}/BRPickerView/BRPickerView.framework
|
||||
${BUILT_PRODUCTS_DIR}/CocoaLumberjack/CocoaLumberjack.framework
|
||||
${BUILT_PRODUCTS_DIR}/CocoaMQTT/CocoaMQTT.framework
|
||||
${BUILT_PRODUCTS_DIR}/Differentiator/Differentiator.framework
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BRPickerView.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CocoaLumberjack.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CocoaMQTT.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Differentiator.framework
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ code_sign_if_enabled() {
|
|||
|
||||
if [[ "$CONFIGURATION" == "Debug" ]]; then
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/BRPickerView/BRPickerView.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/CocoaLumberjack/CocoaLumberjack.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/CocoaMQTT/CocoaMQTT.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/Differentiator/Differentiator.framework"
|
||||
|
|
@ -223,6 +224,7 @@ if [[ "$CONFIGURATION" == "Debug" ]]; then
|
|||
fi
|
||||
if [[ "$CONFIGURATION" == "Release" ]]; then
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/BRPickerView/BRPickerView.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/CocoaLumberjack/CocoaLumberjack.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/CocoaMQTT/CocoaMQTT.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/Differentiator/Differentiator.framework"
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
|||
ARCHS = $(ARCHS_STANDARD)
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaMQTT" "${PODS_CONFIGURATION_BUILD_DIR}/Differentiator" "${PODS_CONFIGURATION_BUILD_DIR}/HXPHPicker" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardCore" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardNotification" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardReturnManager" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbar" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbarManager" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextInputViewNotification" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextView" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" "${PODS_CONFIGURATION_BUILD_DIR}/KingfisherWebP" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/Moya" "${PODS_CONFIGURATION_BUILD_DIR}/MqttCocoaAsyncSocket" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper" "${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDK" "${PODS_CONFIGURATION_BUILD_DIR}/Popover" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "${PODS_CONFIGURATION_BUILD_DIR}/RxDataSources" "${PODS_CONFIGURATION_BUILD_DIR}/RxGesture" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwiftExt" "${PODS_CONFIGURATION_BUILD_DIR}/SDCycleScrollView" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SGQRCode" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftDate" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftKeychainWrapper" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyUserDefaults" "${PODS_CONFIGURATION_BUILD_DIR}/TagListView" "${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator" "${PODS_CONFIGURATION_BUILD_DIR}/YBImageBrowser" "${PODS_CONFIGURATION_BUILD_DIR}/YYImage" "${PODS_CONFIGURATION_BUILD_DIR}/libwebp" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios" "${PODS_ROOT}/AlipaySDK-iOS" "${PODS_ROOT}/OpenIMSDKCore/Framework" "${PODS_ROOT}/WechatOpenSDK-XCFramework" "${PODS_ROOT}/YYImage/Vendor" "${PODS_XCFRAMEWORKS_BUILD_DIR}/AlipaySDK-iOS" "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenIMSDKCore" "${PODS_XCFRAMEWORKS_BUILD_DIR}/WechatOpenSDK-XCFramework"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/BRPickerView" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaMQTT" "${PODS_CONFIGURATION_BUILD_DIR}/Differentiator" "${PODS_CONFIGURATION_BUILD_DIR}/HXPHPicker" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardCore" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardNotification" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardReturnManager" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbar" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbarManager" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextInputViewNotification" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextView" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" "${PODS_CONFIGURATION_BUILD_DIR}/KingfisherWebP" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/Moya" "${PODS_CONFIGURATION_BUILD_DIR}/MqttCocoaAsyncSocket" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper" "${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDK" "${PODS_CONFIGURATION_BUILD_DIR}/Popover" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "${PODS_CONFIGURATION_BUILD_DIR}/RxDataSources" "${PODS_CONFIGURATION_BUILD_DIR}/RxGesture" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwiftExt" "${PODS_CONFIGURATION_BUILD_DIR}/SDCycleScrollView" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SGQRCode" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftDate" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftKeychainWrapper" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyUserDefaults" "${PODS_CONFIGURATION_BUILD_DIR}/TagListView" "${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator" "${PODS_CONFIGURATION_BUILD_DIR}/YBImageBrowser" "${PODS_CONFIGURATION_BUILD_DIR}/YYImage" "${PODS_CONFIGURATION_BUILD_DIR}/libwebp" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios" "${PODS_ROOT}/AlipaySDK-iOS" "${PODS_ROOT}/OpenIMSDKCore/Framework" "${PODS_ROOT}/WechatOpenSDK-XCFramework" "${PODS_ROOT}/YYImage/Vendor" "${PODS_XCFRAMEWORKS_BUILD_DIR}/AlipaySDK-iOS" "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenIMSDKCore" "${PODS_XCFRAMEWORKS_BUILD_DIR}/WechatOpenSDK-XCFramework"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack/CocoaLumberjack.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaMQTT/CocoaMQTT.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Differentiator/Differentiator.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/HXPHPicker/HXPHPicker.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardCore/IQKeyboardCore.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift/IQKeyboardManagerSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardNotification/IQKeyboardNotification.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardReturnManager/IQKeyboardReturnManager.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbar/IQKeyboardToolbar.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbarManager/IQKeyboardToolbarManager.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextInputViewNotification/IQTextInputViewNotification.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextView/IQTextView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/KingfisherWebP/KingfisherWebP.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel/MarqueeLabel.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Moya/Moya.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MqttCocoaAsyncSocket/MqttCocoaAsyncSocket.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper/ObjectMapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDK/OpenIMSDK.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Popover/Popover.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa/RxCocoa.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxDataSources/RxDataSources.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxGesture/RxGesture.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay/RxRelay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwiftExt/RxSwiftExt.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDCycleScrollView/SDCycleScrollView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SGQRCode/SGQRCode.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftDate/SwiftDate.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftKeychainWrapper/SwiftKeychainWrapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON/SwiftyJSON.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyUserDefaults/SwiftyUserDefaults.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/TagListView/TagListView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator/URLNavigator.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YBImageBrowser/YBImageBrowser.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YYImage/YYImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/libwebp/libwebp.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
|
||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/BRPickerView/BRPickerView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack/CocoaLumberjack.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaMQTT/CocoaMQTT.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Differentiator/Differentiator.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/HXPHPicker/HXPHPicker.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardCore/IQKeyboardCore.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift/IQKeyboardManagerSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardNotification/IQKeyboardNotification.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardReturnManager/IQKeyboardReturnManager.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbar/IQKeyboardToolbar.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbarManager/IQKeyboardToolbarManager.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextInputViewNotification/IQTextInputViewNotification.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextView/IQTextView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/KingfisherWebP/KingfisherWebP.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel/MarqueeLabel.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Moya/Moya.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MqttCocoaAsyncSocket/MqttCocoaAsyncSocket.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper/ObjectMapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDK/OpenIMSDK.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Popover/Popover.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa/RxCocoa.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxDataSources/RxDataSources.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxGesture/RxGesture.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay/RxRelay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwiftExt/RxSwiftExt.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDCycleScrollView/SDCycleScrollView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SGQRCode/SGQRCode.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftDate/SwiftDate.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftKeychainWrapper/SwiftKeychainWrapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON/SwiftyJSON.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyUserDefaults/SwiftyUserDefaults.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/TagListView/TagListView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator/URLNavigator.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YBImageBrowser/YBImageBrowser.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YYImage/YYImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/libwebp/libwebp.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift $(SDKROOT)/usr/lib/swift
|
||||
OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"iconv" -l"resolv" -l"sqlite3.0" -l"swiftCoreGraphics" -l"z" -framework "AVFoundation" -framework "Accelerate" -framework "AdSupport" -framework "Alamofire" -framework "AlipaySDK" -framework "AssetsLibrary" -framework "AudioToolbox" -framework "CFNetwork" -framework "CallKit" -framework "CocoaLumberjack" -framework "CocoaMQTT" -framework "Combine" -framework "CoreFoundation" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreMotion" -framework "CoreServices" -framework "CoreTelephony" -framework "CoreText" -framework "Differentiator" -framework "ExternalAccessory" -framework "Foundation" -framework "GLKit" -framework "HXPHPicker" -framework "IQKeyboardCore" -framework "IQKeyboardManagerSwift" -framework "IQKeyboardNotification" -framework "IQKeyboardReturnManager" -framework "IQKeyboardToolbar" -framework "IQKeyboardToolbarManager" -framework "IQTextInputViewNotification" -framework "IQTextView" -framework "ImageIO" -framework "Kingfisher" -framework "KingfisherWebP" -framework "Lottie" -framework "MBProgressHUD" -framework "MJExtension" -framework "MJRefresh" -framework "MarqueeLabel" -framework "Masonry" -framework "MobileCoreServices" -framework "Moya" -framework "MqttCocoaAsyncSocket" -framework "ObjectMapper" -framework "OpenGLES" -framework "OpenIMCore" -framework "OpenIMSDK" -framework "Photos" -framework "PhotosUI" -framework "Popover" -framework "QuartzCore" -framework "RxCocoa" -framework "RxDataSources" -framework "RxGesture" -framework "RxRelay" -framework "RxSwift" -framework "RxSwiftExt" -framework "SDCycleScrollView" -framework "SDWebImage" -framework "SGQRCode" -framework "Security" -framework "SnapKit" -framework "SwiftDate" -framework "SwiftKeychainWrapper" -framework "SwiftyJSON" -framework "SwiftyUserDefaults" -framework "SystemConfiguration" -framework "TagListView" -framework "UIKit" -framework "URLNavigator" -framework "WebKit" -framework "WechatOpenSDK" -framework "YBImageBrowser" -framework "YYImage" -framework "libwebp" -weak_framework "AppTrackingTransparency" -weak_framework "Combine" -weak_framework "Network" -weak_framework "SwiftUI"
|
||||
OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapFoundation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapLocation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapNavi-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "-F${PODS_CONFIGURATION_BUILD_DIR}/AlipaySDK-iOS" "-F${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack" "-F${PODS_CONFIGURATION_BUILD_DIR}/CocoaMQTT" "-F${PODS_CONFIGURATION_BUILD_DIR}/Differentiator" "-F${PODS_CONFIGURATION_BUILD_DIR}/GTCommonSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/GYSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/HXPHPicker" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardCore" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardNotification" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardReturnManager" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbar" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbarManager" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQTextInputViewNotification" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQTextView" "-F${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" "-F${PODS_CONFIGURATION_BUILD_DIR}/KingfisherWebP" "-F${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "-F${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel" "-F${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "-F${PODS_CONFIGURATION_BUILD_DIR}/Moya" "-F${PODS_CONFIGURATION_BUILD_DIR}/MqttCocoaAsyncSocket" "-F${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper" "-F${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDKCore" "-F${PODS_CONFIGURATION_BUILD_DIR}/Popover" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxDataSources" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxGesture" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxSwiftExt" "-F${PODS_CONFIGURATION_BUILD_DIR}/SDCycleScrollView" "-F${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "-F${PODS_CONFIGURATION_BUILD_DIR}/SGQRCode" "-F${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftDate" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftKeychainWrapper" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftyUserDefaults" "-F${PODS_CONFIGURATION_BUILD_DIR}/TagListView" "-F${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator" "-F${PODS_CONFIGURATION_BUILD_DIR}/WechatOpenSDK-XCFramework" "-F${PODS_CONFIGURATION_BUILD_DIR}/YBImageBrowser" "-F${PODS_CONFIGURATION_BUILD_DIR}/YYImage" "-F${PODS_CONFIGURATION_BUILD_DIR}/ZXSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/libwebp" "-F${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios"
|
||||
OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"iconv" -l"resolv" -l"sqlite3.0" -l"swiftCoreGraphics" -l"z" -framework "AVFoundation" -framework "Accelerate" -framework "AdSupport" -framework "Alamofire" -framework "AlipaySDK" -framework "AssetsLibrary" -framework "AudioToolbox" -framework "BRPickerView" -framework "CFNetwork" -framework "CallKit" -framework "CocoaLumberjack" -framework "CocoaMQTT" -framework "Combine" -framework "CoreFoundation" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreMotion" -framework "CoreServices" -framework "CoreTelephony" -framework "CoreText" -framework "Differentiator" -framework "ExternalAccessory" -framework "Foundation" -framework "GLKit" -framework "HXPHPicker" -framework "IQKeyboardCore" -framework "IQKeyboardManagerSwift" -framework "IQKeyboardNotification" -framework "IQKeyboardReturnManager" -framework "IQKeyboardToolbar" -framework "IQKeyboardToolbarManager" -framework "IQTextInputViewNotification" -framework "IQTextView" -framework "ImageIO" -framework "Kingfisher" -framework "KingfisherWebP" -framework "Lottie" -framework "MBProgressHUD" -framework "MJExtension" -framework "MJRefresh" -framework "MarqueeLabel" -framework "Masonry" -framework "MobileCoreServices" -framework "Moya" -framework "MqttCocoaAsyncSocket" -framework "ObjectMapper" -framework "OpenGLES" -framework "OpenIMCore" -framework "OpenIMSDK" -framework "Photos" -framework "PhotosUI" -framework "Popover" -framework "QuartzCore" -framework "RxCocoa" -framework "RxDataSources" -framework "RxGesture" -framework "RxRelay" -framework "RxSwift" -framework "RxSwiftExt" -framework "SDCycleScrollView" -framework "SDWebImage" -framework "SGQRCode" -framework "Security" -framework "SnapKit" -framework "SwiftDate" -framework "SwiftKeychainWrapper" -framework "SwiftyJSON" -framework "SwiftyUserDefaults" -framework "SystemConfiguration" -framework "TagListView" -framework "UIKit" -framework "URLNavigator" -framework "WebKit" -framework "WechatOpenSDK" -framework "YBImageBrowser" -framework "YYImage" -framework "libwebp" -weak_framework "AppTrackingTransparency" -weak_framework "Combine" -weak_framework "Network" -weak_framework "SwiftUI"
|
||||
OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapFoundation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapLocation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapNavi-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "-F${PODS_CONFIGURATION_BUILD_DIR}/AlipaySDK-iOS" "-F${PODS_CONFIGURATION_BUILD_DIR}/BRPickerView" "-F${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack" "-F${PODS_CONFIGURATION_BUILD_DIR}/CocoaMQTT" "-F${PODS_CONFIGURATION_BUILD_DIR}/Differentiator" "-F${PODS_CONFIGURATION_BUILD_DIR}/GTCommonSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/GYSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/HXPHPicker" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardCore" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardNotification" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardReturnManager" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbar" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbarManager" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQTextInputViewNotification" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQTextView" "-F${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" "-F${PODS_CONFIGURATION_BUILD_DIR}/KingfisherWebP" "-F${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "-F${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel" "-F${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "-F${PODS_CONFIGURATION_BUILD_DIR}/Moya" "-F${PODS_CONFIGURATION_BUILD_DIR}/MqttCocoaAsyncSocket" "-F${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper" "-F${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDKCore" "-F${PODS_CONFIGURATION_BUILD_DIR}/Popover" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxDataSources" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxGesture" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxSwiftExt" "-F${PODS_CONFIGURATION_BUILD_DIR}/SDCycleScrollView" "-F${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "-F${PODS_CONFIGURATION_BUILD_DIR}/SGQRCode" "-F${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftDate" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftKeychainWrapper" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftyUserDefaults" "-F${PODS_CONFIGURATION_BUILD_DIR}/TagListView" "-F${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator" "-F${PODS_CONFIGURATION_BUILD_DIR}/WechatOpenSDK-XCFramework" "-F${PODS_CONFIGURATION_BUILD_DIR}/YBImageBrowser" "-F${PODS_CONFIGURATION_BUILD_DIR}/YYImage" "-F${PODS_CONFIGURATION_BUILD_DIR}/ZXSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/libwebp" "-F${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
|||
ARCHS = $(ARCHS_STANDARD)
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaMQTT" "${PODS_CONFIGURATION_BUILD_DIR}/Differentiator" "${PODS_CONFIGURATION_BUILD_DIR}/HXPHPicker" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardCore" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardNotification" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardReturnManager" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbar" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbarManager" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextInputViewNotification" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextView" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" "${PODS_CONFIGURATION_BUILD_DIR}/KingfisherWebP" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/Moya" "${PODS_CONFIGURATION_BUILD_DIR}/MqttCocoaAsyncSocket" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper" "${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDK" "${PODS_CONFIGURATION_BUILD_DIR}/Popover" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "${PODS_CONFIGURATION_BUILD_DIR}/RxDataSources" "${PODS_CONFIGURATION_BUILD_DIR}/RxGesture" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwiftExt" "${PODS_CONFIGURATION_BUILD_DIR}/SDCycleScrollView" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SGQRCode" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftDate" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftKeychainWrapper" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyUserDefaults" "${PODS_CONFIGURATION_BUILD_DIR}/TagListView" "${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator" "${PODS_CONFIGURATION_BUILD_DIR}/YBImageBrowser" "${PODS_CONFIGURATION_BUILD_DIR}/YYImage" "${PODS_CONFIGURATION_BUILD_DIR}/libwebp" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios" "${PODS_ROOT}/AlipaySDK-iOS" "${PODS_ROOT}/OpenIMSDKCore/Framework" "${PODS_ROOT}/WechatOpenSDK-XCFramework" "${PODS_ROOT}/YYImage/Vendor" "${PODS_XCFRAMEWORKS_BUILD_DIR}/AlipaySDK-iOS" "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenIMSDKCore" "${PODS_XCFRAMEWORKS_BUILD_DIR}/WechatOpenSDK-XCFramework"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/BRPickerView" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaMQTT" "${PODS_CONFIGURATION_BUILD_DIR}/Differentiator" "${PODS_CONFIGURATION_BUILD_DIR}/HXPHPicker" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardCore" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardNotification" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardReturnManager" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbar" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbarManager" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextInputViewNotification" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextView" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" "${PODS_CONFIGURATION_BUILD_DIR}/KingfisherWebP" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/Moya" "${PODS_CONFIGURATION_BUILD_DIR}/MqttCocoaAsyncSocket" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper" "${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDK" "${PODS_CONFIGURATION_BUILD_DIR}/Popover" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "${PODS_CONFIGURATION_BUILD_DIR}/RxDataSources" "${PODS_CONFIGURATION_BUILD_DIR}/RxGesture" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwiftExt" "${PODS_CONFIGURATION_BUILD_DIR}/SDCycleScrollView" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SGQRCode" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftDate" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftKeychainWrapper" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyUserDefaults" "${PODS_CONFIGURATION_BUILD_DIR}/TagListView" "${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator" "${PODS_CONFIGURATION_BUILD_DIR}/YBImageBrowser" "${PODS_CONFIGURATION_BUILD_DIR}/YYImage" "${PODS_CONFIGURATION_BUILD_DIR}/libwebp" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios" "${PODS_ROOT}/AlipaySDK-iOS" "${PODS_ROOT}/OpenIMSDKCore/Framework" "${PODS_ROOT}/WechatOpenSDK-XCFramework" "${PODS_ROOT}/YYImage/Vendor" "${PODS_XCFRAMEWORKS_BUILD_DIR}/AlipaySDK-iOS" "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenIMSDKCore" "${PODS_XCFRAMEWORKS_BUILD_DIR}/WechatOpenSDK-XCFramework"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack/CocoaLumberjack.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaMQTT/CocoaMQTT.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Differentiator/Differentiator.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/HXPHPicker/HXPHPicker.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardCore/IQKeyboardCore.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift/IQKeyboardManagerSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardNotification/IQKeyboardNotification.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardReturnManager/IQKeyboardReturnManager.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbar/IQKeyboardToolbar.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbarManager/IQKeyboardToolbarManager.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextInputViewNotification/IQTextInputViewNotification.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextView/IQTextView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/KingfisherWebP/KingfisherWebP.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel/MarqueeLabel.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Moya/Moya.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MqttCocoaAsyncSocket/MqttCocoaAsyncSocket.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper/ObjectMapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDK/OpenIMSDK.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Popover/Popover.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa/RxCocoa.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxDataSources/RxDataSources.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxGesture/RxGesture.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay/RxRelay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwiftExt/RxSwiftExt.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDCycleScrollView/SDCycleScrollView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SGQRCode/SGQRCode.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftDate/SwiftDate.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftKeychainWrapper/SwiftKeychainWrapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON/SwiftyJSON.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyUserDefaults/SwiftyUserDefaults.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/TagListView/TagListView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator/URLNavigator.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YBImageBrowser/YBImageBrowser.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YYImage/YYImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/libwebp/libwebp.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
|
||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/BRPickerView/BRPickerView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack/CocoaLumberjack.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/CocoaMQTT/CocoaMQTT.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Differentiator/Differentiator.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/HXPHPicker/HXPHPicker.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardCore/IQKeyboardCore.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift/IQKeyboardManagerSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardNotification/IQKeyboardNotification.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardReturnManager/IQKeyboardReturnManager.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbar/IQKeyboardToolbar.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbarManager/IQKeyboardToolbarManager.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextInputViewNotification/IQTextInputViewNotification.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/IQTextView/IQTextView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/KingfisherWebP/KingfisherWebP.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJExtension/MJExtension.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel/MarqueeLabel.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Moya/Moya.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MqttCocoaAsyncSocket/MqttCocoaAsyncSocket.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper/ObjectMapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDK/OpenIMSDK.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Popover/Popover.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa/RxCocoa.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxDataSources/RxDataSources.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxGesture/RxGesture.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay/RxRelay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwiftExt/RxSwiftExt.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDCycleScrollView/SDCycleScrollView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage/SDWebImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SGQRCode/SGQRCode.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftDate/SwiftDate.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftKeychainWrapper/SwiftKeychainWrapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON/SwiftyJSON.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyUserDefaults/SwiftyUserDefaults.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/TagListView/TagListView.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator/URLNavigator.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YBImageBrowser/YBImageBrowser.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YYImage/YYImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/libwebp/libwebp.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift $(SDKROOT)/usr/lib/swift
|
||||
OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"iconv" -l"resolv" -l"sqlite3.0" -l"swiftCoreGraphics" -l"z" -framework "AVFoundation" -framework "Accelerate" -framework "AdSupport" -framework "Alamofire" -framework "AlipaySDK" -framework "AssetsLibrary" -framework "AudioToolbox" -framework "CFNetwork" -framework "CallKit" -framework "CocoaLumberjack" -framework "CocoaMQTT" -framework "Combine" -framework "CoreFoundation" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreMotion" -framework "CoreServices" -framework "CoreTelephony" -framework "CoreText" -framework "Differentiator" -framework "ExternalAccessory" -framework "Foundation" -framework "GLKit" -framework "HXPHPicker" -framework "IQKeyboardCore" -framework "IQKeyboardManagerSwift" -framework "IQKeyboardNotification" -framework "IQKeyboardReturnManager" -framework "IQKeyboardToolbar" -framework "IQKeyboardToolbarManager" -framework "IQTextInputViewNotification" -framework "IQTextView" -framework "ImageIO" -framework "Kingfisher" -framework "KingfisherWebP" -framework "Lottie" -framework "MBProgressHUD" -framework "MJExtension" -framework "MJRefresh" -framework "MarqueeLabel" -framework "Masonry" -framework "MobileCoreServices" -framework "Moya" -framework "MqttCocoaAsyncSocket" -framework "ObjectMapper" -framework "OpenGLES" -framework "OpenIMCore" -framework "OpenIMSDK" -framework "Photos" -framework "PhotosUI" -framework "Popover" -framework "QuartzCore" -framework "RxCocoa" -framework "RxDataSources" -framework "RxGesture" -framework "RxRelay" -framework "RxSwift" -framework "RxSwiftExt" -framework "SDCycleScrollView" -framework "SDWebImage" -framework "SGQRCode" -framework "Security" -framework "SnapKit" -framework "SwiftDate" -framework "SwiftKeychainWrapper" -framework "SwiftyJSON" -framework "SwiftyUserDefaults" -framework "SystemConfiguration" -framework "TagListView" -framework "UIKit" -framework "URLNavigator" -framework "WebKit" -framework "WechatOpenSDK" -framework "YBImageBrowser" -framework "YYImage" -framework "libwebp" -weak_framework "AppTrackingTransparency" -weak_framework "Combine" -weak_framework "Network" -weak_framework "SwiftUI"
|
||||
OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapFoundation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapLocation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapNavi-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "-F${PODS_CONFIGURATION_BUILD_DIR}/AlipaySDK-iOS" "-F${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack" "-F${PODS_CONFIGURATION_BUILD_DIR}/CocoaMQTT" "-F${PODS_CONFIGURATION_BUILD_DIR}/Differentiator" "-F${PODS_CONFIGURATION_BUILD_DIR}/GTCommonSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/GYSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/HXPHPicker" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardCore" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardNotification" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardReturnManager" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbar" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbarManager" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQTextInputViewNotification" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQTextView" "-F${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" "-F${PODS_CONFIGURATION_BUILD_DIR}/KingfisherWebP" "-F${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "-F${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel" "-F${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "-F${PODS_CONFIGURATION_BUILD_DIR}/Moya" "-F${PODS_CONFIGURATION_BUILD_DIR}/MqttCocoaAsyncSocket" "-F${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper" "-F${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDKCore" "-F${PODS_CONFIGURATION_BUILD_DIR}/Popover" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxDataSources" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxGesture" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxSwiftExt" "-F${PODS_CONFIGURATION_BUILD_DIR}/SDCycleScrollView" "-F${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "-F${PODS_CONFIGURATION_BUILD_DIR}/SGQRCode" "-F${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftDate" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftKeychainWrapper" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftyUserDefaults" "-F${PODS_CONFIGURATION_BUILD_DIR}/TagListView" "-F${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator" "-F${PODS_CONFIGURATION_BUILD_DIR}/WechatOpenSDK-XCFramework" "-F${PODS_CONFIGURATION_BUILD_DIR}/YBImageBrowser" "-F${PODS_CONFIGURATION_BUILD_DIR}/YYImage" "-F${PODS_CONFIGURATION_BUILD_DIR}/ZXSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/libwebp" "-F${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios"
|
||||
OTHER_LDFLAGS = $(inherited) -ObjC -l"c++" -l"iconv" -l"resolv" -l"sqlite3.0" -l"swiftCoreGraphics" -l"z" -framework "AVFoundation" -framework "Accelerate" -framework "AdSupport" -framework "Alamofire" -framework "AlipaySDK" -framework "AssetsLibrary" -framework "AudioToolbox" -framework "BRPickerView" -framework "CFNetwork" -framework "CallKit" -framework "CocoaLumberjack" -framework "CocoaMQTT" -framework "Combine" -framework "CoreFoundation" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreMotion" -framework "CoreServices" -framework "CoreTelephony" -framework "CoreText" -framework "Differentiator" -framework "ExternalAccessory" -framework "Foundation" -framework "GLKit" -framework "HXPHPicker" -framework "IQKeyboardCore" -framework "IQKeyboardManagerSwift" -framework "IQKeyboardNotification" -framework "IQKeyboardReturnManager" -framework "IQKeyboardToolbar" -framework "IQKeyboardToolbarManager" -framework "IQTextInputViewNotification" -framework "IQTextView" -framework "ImageIO" -framework "Kingfisher" -framework "KingfisherWebP" -framework "Lottie" -framework "MBProgressHUD" -framework "MJExtension" -framework "MJRefresh" -framework "MarqueeLabel" -framework "Masonry" -framework "MobileCoreServices" -framework "Moya" -framework "MqttCocoaAsyncSocket" -framework "ObjectMapper" -framework "OpenGLES" -framework "OpenIMCore" -framework "OpenIMSDK" -framework "Photos" -framework "PhotosUI" -framework "Popover" -framework "QuartzCore" -framework "RxCocoa" -framework "RxDataSources" -framework "RxGesture" -framework "RxRelay" -framework "RxSwift" -framework "RxSwiftExt" -framework "SDCycleScrollView" -framework "SDWebImage" -framework "SGQRCode" -framework "Security" -framework "SnapKit" -framework "SwiftDate" -framework "SwiftKeychainWrapper" -framework "SwiftyJSON" -framework "SwiftyUserDefaults" -framework "SystemConfiguration" -framework "TagListView" -framework "UIKit" -framework "URLNavigator" -framework "WebKit" -framework "WechatOpenSDK" -framework "YBImageBrowser" -framework "YYImage" -framework "libwebp" -weak_framework "AppTrackingTransparency" -weak_framework "Combine" -weak_framework "Network" -weak_framework "SwiftUI"
|
||||
OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapFoundation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapLocation-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/AMapNavi-NO-IDFA" "-F${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "-F${PODS_CONFIGURATION_BUILD_DIR}/AlipaySDK-iOS" "-F${PODS_CONFIGURATION_BUILD_DIR}/BRPickerView" "-F${PODS_CONFIGURATION_BUILD_DIR}/CocoaLumberjack" "-F${PODS_CONFIGURATION_BUILD_DIR}/CocoaMQTT" "-F${PODS_CONFIGURATION_BUILD_DIR}/Differentiator" "-F${PODS_CONFIGURATION_BUILD_DIR}/GTCommonSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/GYSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/HXPHPicker" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardCore" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardManagerSwift" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardNotification" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardReturnManager" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbar" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQKeyboardToolbarManager" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQTextInputViewNotification" "-F${PODS_CONFIGURATION_BUILD_DIR}/IQTextView" "-F${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" "-F${PODS_CONFIGURATION_BUILD_DIR}/KingfisherWebP" "-F${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJExtension" "-F${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "-F${PODS_CONFIGURATION_BUILD_DIR}/MarqueeLabel" "-F${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "-F${PODS_CONFIGURATION_BUILD_DIR}/Moya" "-F${PODS_CONFIGURATION_BUILD_DIR}/MqttCocoaAsyncSocket" "-F${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper" "-F${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/OpenIMSDKCore" "-F${PODS_CONFIGURATION_BUILD_DIR}/Popover" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxDataSources" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxGesture" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" "-F${PODS_CONFIGURATION_BUILD_DIR}/RxSwiftExt" "-F${PODS_CONFIGURATION_BUILD_DIR}/SDCycleScrollView" "-F${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "-F${PODS_CONFIGURATION_BUILD_DIR}/SGQRCode" "-F${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftDate" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftKeychainWrapper" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftyJSON" "-F${PODS_CONFIGURATION_BUILD_DIR}/SwiftyUserDefaults" "-F${PODS_CONFIGURATION_BUILD_DIR}/TagListView" "-F${PODS_CONFIGURATION_BUILD_DIR}/URLNavigator" "-F${PODS_CONFIGURATION_BUILD_DIR}/WechatOpenSDK-XCFramework" "-F${PODS_CONFIGURATION_BUILD_DIR}/YBImageBrowser" "-F${PODS_CONFIGURATION_BUILD_DIR}/YYImage" "-F${PODS_CONFIGURATION_BUILD_DIR}/ZXSDK" "-F${PODS_CONFIGURATION_BUILD_DIR}/libwebp" "-F${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
|
|
|
|||
|
|
@ -195,6 +195,17 @@
|
|||
30CCDE582FE39F8C00F5214A /* SOSView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE572FE39F8C00F5214A /* SOSView.swift */; };
|
||||
30CCDE5A2FE39F9D00F5214A /* SOSViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE592FE39F9D00F5214A /* SOSViewController.swift */; };
|
||||
30CCDE5C2FE3A1A800F5214A /* SOSPracticeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30CCDE5B2FE3A1A800F5214A /* SOSPracticeView.swift */; };
|
||||
30D74AAB2FE8C7700050EB2C /* GPSSignalHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AAA2FE8C7700050EB2C /* GPSSignalHelper.swift */; };
|
||||
30D74AAE2FEA13E00050EB2C /* ScheduleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AAD2FEA13E00050EB2C /* ScheduleView.swift */; };
|
||||
30D74AB02FEA13ED0050EB2C /* ScheduleVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AAF2FEA13ED0050EB2C /* ScheduleVC.swift */; };
|
||||
30D74AB22FEA1D5D0050EB2C /* ScheduleViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AB12FEA1D5D0050EB2C /* ScheduleViewModel.swift */; };
|
||||
30D74AB42FEA25B90050EB2C /* ViewedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AB32FEA25B90050EB2C /* ViewedModel.swift */; };
|
||||
30D74AB62FEA34FF0050EB2C /* ItineraryAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AB52FEA34FF0050EB2C /* ItineraryAPI.swift */; };
|
||||
30D74AB82FEA36A50050EB2C /* ItineraryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AB72FEA36A50050EB2C /* ItineraryService.swift */; };
|
||||
30D74ABA2FEA37AD0050EB2C /* ScheduleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AB92FEA37AD0050EB2C /* ScheduleModel.swift */; };
|
||||
30D74ABD2FEA67EA0050EB2C /* CreateScheduleVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74ABC2FEA67EA0050EB2C /* CreateScheduleVC.swift */; };
|
||||
30D74ABF2FEA67F30050EB2C /* CreateScheduleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74ABE2FEA67F30050EB2C /* CreateScheduleView.swift */; };
|
||||
30D74AC12FEA6EEF0050EB2C /* CreateSchedulePopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D74AC02FEA6EEF0050EB2C /* CreateSchedulePopView.swift */; };
|
||||
30D87CDB2FDFA9EE00E958FD /* MQTTService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D87CDA2FDFA9EE00E958FD /* MQTTService.swift */; };
|
||||
30D87CDD2FDFF07500E958FD /* InteractionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D87CDC2FDFF07500E958FD /* InteractionView.swift */; };
|
||||
30D87CDF2FDFF1A100E958FD /* QuickMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30D87CDE2FDFF1A100E958FD /* QuickMessageView.swift */; };
|
||||
|
|
@ -441,6 +452,17 @@
|
|||
30CCDE572FE39F8C00F5214A /* SOSView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOSView.swift; sourceTree = "<group>"; };
|
||||
30CCDE592FE39F9D00F5214A /* SOSViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOSViewController.swift; sourceTree = "<group>"; };
|
||||
30CCDE5B2FE3A1A800F5214A /* SOSPracticeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOSPracticeView.swift; sourceTree = "<group>"; };
|
||||
30D74AAA2FE8C7700050EB2C /* GPSSignalHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GPSSignalHelper.swift; sourceTree = "<group>"; };
|
||||
30D74AAD2FEA13E00050EB2C /* ScheduleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleView.swift; sourceTree = "<group>"; };
|
||||
30D74AAF2FEA13ED0050EB2C /* ScheduleVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleVC.swift; sourceTree = "<group>"; };
|
||||
30D74AB12FEA1D5D0050EB2C /* ScheduleViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleViewModel.swift; sourceTree = "<group>"; };
|
||||
30D74AB32FEA25B90050EB2C /* ViewedModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewedModel.swift; sourceTree = "<group>"; };
|
||||
30D74AB52FEA34FF0050EB2C /* ItineraryAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItineraryAPI.swift; sourceTree = "<group>"; };
|
||||
30D74AB72FEA36A50050EB2C /* ItineraryService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItineraryService.swift; sourceTree = "<group>"; };
|
||||
30D74AB92FEA37AD0050EB2C /* ScheduleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleModel.swift; sourceTree = "<group>"; };
|
||||
30D74ABC2FEA67EA0050EB2C /* CreateScheduleVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateScheduleVC.swift; sourceTree = "<group>"; };
|
||||
30D74ABE2FEA67F30050EB2C /* CreateScheduleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateScheduleView.swift; sourceTree = "<group>"; };
|
||||
30D74AC02FEA6EEF0050EB2C /* CreateSchedulePopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateSchedulePopView.swift; sourceTree = "<group>"; };
|
||||
30D87CDA2FDFA9EE00E958FD /* MQTTService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MQTTService.swift; sourceTree = "<group>"; };
|
||||
30D87CDC2FDFF07500E958FD /* InteractionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionView.swift; sourceTree = "<group>"; };
|
||||
30D87CDE2FDFF1A100E958FD /* QuickMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickMessageView.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -497,21 +519,29 @@
|
|||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
30CCDF8E2FE3E63B00F5214A /* sound */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
path = sound;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
30CCDF902FE3E63B00F5214A /* video */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
path = video;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
30CCE01E2FE3E64700F5214A /* lotties */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
path = lotties;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
30D87CEF2FDFF52100E958FD /* TTGTagCollectionView */ = {
|
||||
isa = PBXFileSystemSynchronizedRootGroup;
|
||||
exceptions = (
|
||||
);
|
||||
path = TTGTagCollectionView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
|
|
@ -551,6 +581,7 @@
|
|||
305A74CF2FCA8C7000227D26 /* UserAPI.swift */,
|
||||
30BAB8502FCD331C00C33B5C /* GroupAPI.swift */,
|
||||
30D891F42FE22E0600E958FD /* OrderAPI.swift */,
|
||||
30D74AB52FEA34FF0050EB2C /* ItineraryAPI.swift */,
|
||||
);
|
||||
path = API;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -950,6 +981,7 @@
|
|||
305A762A2FCA8C7000227D26 /* Home */,
|
||||
305A76352FCA8C7000227D26 /* Map */,
|
||||
305A76262FCA8C7000227D26 /* Group */,
|
||||
30D74AAC2FEA13BD0050EB2C /* Schedule */,
|
||||
305A76392FCA8C7000227D26 /* Mine */,
|
||||
305A798E2FCAC5F600227D26 /* InviteMember */,
|
||||
3062E8C52FCFD01000CEF511 /* VipRecharge */,
|
||||
|
|
@ -969,6 +1001,7 @@
|
|||
305A763C2FCA8C7000227D26 /* UserService.swift */,
|
||||
30BAB8522FCD337C00C33B5C /* GroupService.swift */,
|
||||
30D891F62FE22E6E00E958FD /* OrderService.swift */,
|
||||
30D74AB72FEA36A50050EB2C /* ItineraryService.swift */,
|
||||
);
|
||||
path = Service;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -995,6 +1028,7 @@
|
|||
305A76452FCA8C7000227D26 /* Tool */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
30D74AAA2FE8C7700050EB2C /* GPSSignalHelper.swift */,
|
||||
305A76412FCA8C7000227D26 /* AutoLayout */,
|
||||
305A76442FCA8C7000227D26 /* Router */,
|
||||
);
|
||||
|
|
@ -1241,6 +1275,29 @@
|
|||
path = SOS;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
30D74AAC2FEA13BD0050EB2C /* Schedule */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
30D74AAF2FEA13ED0050EB2C /* ScheduleVC.swift */,
|
||||
30D74AB12FEA1D5D0050EB2C /* ScheduleViewModel.swift */,
|
||||
30D74AAD2FEA13E00050EB2C /* ScheduleView.swift */,
|
||||
30D74AB32FEA25B90050EB2C /* ViewedModel.swift */,
|
||||
30D74AB92FEA37AD0050EB2C /* ScheduleModel.swift */,
|
||||
30D74ABB2FEA67CE0050EB2C /* CreateSchedule */,
|
||||
);
|
||||
path = Schedule;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
30D74ABB2FEA67CE0050EB2C /* CreateSchedule */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
30D74ABC2FEA67EA0050EB2C /* CreateScheduleVC.swift */,
|
||||
30D74ABE2FEA67F30050EB2C /* CreateScheduleView.swift */,
|
||||
30D74AC02FEA6EEF0050EB2C /* CreateSchedulePopView.swift */,
|
||||
);
|
||||
path = CreateSchedule;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
30D87CD52FDF9F1900E958FD /* MQTT */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -1498,14 +1555,10 @@
|
|||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-QuickLocation/Pods-QuickLocation-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-QuickLocation/Pods-QuickLocation-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-QuickLocation/Pods-QuickLocation-frameworks.sh\"\n";
|
||||
|
|
@ -1519,14 +1572,10 @@
|
|||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-QuickLocation/Pods-QuickLocation-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-QuickLocation/Pods-QuickLocation-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-QuickLocation/Pods-QuickLocation-resources.sh\"\n";
|
||||
|
|
@ -1542,6 +1591,7 @@
|
|||
305A76882FCA8C7000227D26 /* MoyaProvider+Rx.swift in Sources */,
|
||||
305A76892FCA8C7000227D26 /* Observable+Response.swift in Sources */,
|
||||
305A768A2FCA8C7000227D26 /* Single+Response.swift in Sources */,
|
||||
30D74AB62FEA34FF0050EB2C /* ItineraryAPI.swift in Sources */,
|
||||
305A768B2FCA8C7000227D26 /* API.swift in Sources */,
|
||||
30EFF3AE2FD7FF1400EB35D4 /* TextInputViewController.swift in Sources */,
|
||||
305A768C2FCA8C7000227D26 /* APIProvider.swift in Sources */,
|
||||
|
|
@ -1585,6 +1635,7 @@
|
|||
305A76A32FCA8C7000227D26 /* ControlEvents+Block.swift in Sources */,
|
||||
3062E8B72FCE6BFE00CEF511 /* ScanView.swift in Sources */,
|
||||
305A76A42FCA8C7000227D26 /* Date+Extension.swift in Sources */,
|
||||
30D74AAE2FEA13E00050EB2C /* ScheduleView.swift in Sources */,
|
||||
305A76A52FCA8C7000227D26 /* Dictionay+Extension.swift in Sources */,
|
||||
305A76A62FCA8C7000227D26 /* Int+Extension.swift in Sources */,
|
||||
30EFF3D62FDA8F0100EB35D4 /* EmergencyContactView.swift in Sources */,
|
||||
|
|
@ -1597,6 +1648,7 @@
|
|||
305A76AB2FCA8C7000227D26 /* ScaleType.swift in Sources */,
|
||||
30EFF3E72FDAA93D00EB35D4 /* PrivacyPolicyView.swift in Sources */,
|
||||
305A76AC2FCA8C7000227D26 /* String+Extension.swift in Sources */,
|
||||
30D74AB82FEA36A50050EB2C /* ItineraryService.swift in Sources */,
|
||||
30EFF3C62FDA433E00EB35D4 /* ChangePhoneView.swift in Sources */,
|
||||
305A76AD2FCA8C7000227D26 /* UIApplicationExtension.swift in Sources */,
|
||||
305A76AE2FCA8C7000227D26 /* UIButton+Extension.swift in Sources */,
|
||||
|
|
@ -1636,6 +1688,7 @@
|
|||
30C4C01D2FDBF557009215C1 /* RemoveMemberViewModel.swift in Sources */,
|
||||
305A76C52FCA8C7000227D26 /* Account.swift in Sources */,
|
||||
305A76C62FCA8C7000227D26 /* AppContextManager.swift in Sources */,
|
||||
30D74ABD2FEA67EA0050EB2C /* CreateScheduleVC.swift in Sources */,
|
||||
305A76C72FCA8C7000227D26 /* UserConfigModel.swift in Sources */,
|
||||
305A76C82FCA8C7000227D26 /* UserConfigResponse.swift in Sources */,
|
||||
305A76C92FCA8C7000227D26 /* ApiManager.swift in Sources */,
|
||||
|
|
@ -1644,6 +1697,7 @@
|
|||
30CCDE552FE2903100F5214A /* SignInModel.swift in Sources */,
|
||||
305A76CC2FCA8C7000227D26 /* FileTools.swift in Sources */,
|
||||
305A76CD2FCA8C7000227D26 /* Permission.swift in Sources */,
|
||||
30D74AB02FEA13ED0050EB2C /* ScheduleVC.swift in Sources */,
|
||||
305A76CE2FCA8C7000227D26 /* RouterManager.swift in Sources */,
|
||||
3062E8C72FCFD02F00CEF511 /* VipRechargeView.swift in Sources */,
|
||||
305A76CF2FCA8C7000227D26 /* CountDownService.swift in Sources */,
|
||||
|
|
@ -1668,10 +1722,12 @@
|
|||
305A76DE2FCA8C7000227D26 /* ObservableType+ObjectMapper.swift in Sources */,
|
||||
305A76DF2FCA8C7000227D26 /* Single+ObjectMapper.swift in Sources */,
|
||||
30DC18602FD12A020041DCD1 /* VipWaivePopView.swift in Sources */,
|
||||
30D74AAB2FE8C7700050EB2C /* GPSSignalHelper.swift in Sources */,
|
||||
305A76E02FCA8C7000227D26 /* GroupView.swift in Sources */,
|
||||
30EFF3BB2FD90D7600EB35D4 /* ConfirmPopVC.swift in Sources */,
|
||||
30BAB8512FCD331C00C33B5C /* GroupAPI.swift in Sources */,
|
||||
305A76E12FCA8C7000227D26 /* GroupViewController.swift in Sources */,
|
||||
30D74AB22FEA1D5D0050EB2C /* ScheduleViewModel.swift in Sources */,
|
||||
30EFF3B52FD8F1D000EB35D4 /* ReviewMemberListVC.swift in Sources */,
|
||||
30BAB84D2FCD2FDE00C33B5C /* InviteJoinView.swift in Sources */,
|
||||
30EFF3CF2FDA669800EB35D4 /* MyProfileVC.swift in Sources */,
|
||||
|
|
@ -1697,11 +1753,13 @@
|
|||
305A76EA2FCA8C7000227D26 /* OneTapLoginView.swift in Sources */,
|
||||
305A76EB2FCA8C7000227D26 /* CircleMember.swift in Sources */,
|
||||
30CCDE5A2FE39F9D00F5214A /* SOSViewController.swift in Sources */,
|
||||
30D74AB42FEA25B90050EB2C /* ViewedModel.swift in Sources */,
|
||||
305A76EC2FCA8C7000227D26 /* MemberAnnotation.swift in Sources */,
|
||||
305A76ED2FCA8C7000227D26 /* MemberAnnotationView.swift in Sources */,
|
||||
30BAB8532FCD337C00C33B5C /* GroupService.swift in Sources */,
|
||||
305A76EE2FCA8C7000227D26 /* MineView.swift in Sources */,
|
||||
305A76EF2FCA8C7000227D26 /* MineViewController.swift in Sources */,
|
||||
30D74ABF2FEA67F30050EB2C /* CreateScheduleView.swift in Sources */,
|
||||
305A76F02FCA8C7000227D26 /* MineViewModel.swift in Sources */,
|
||||
305A76F12FCA8C7000227D26 /* SystemService.swift in Sources */,
|
||||
30DC18522FD009CD0041DCD1 /* VipExpenseModel.swift in Sources */,
|
||||
|
|
@ -1740,6 +1798,7 @@
|
|||
305A77072FCA8C7000227D26 /* Helper.swift in Sources */,
|
||||
305A77082FCA8C7000227D26 /* PageCollectionViewFlowLayout.swift in Sources */,
|
||||
3062E8C42FCFC90F00CEF511 /* CreateGroupVipPopView.swift in Sources */,
|
||||
30D74ABA2FEA37AD0050EB2C /* ScheduleModel.swift in Sources */,
|
||||
30CCDE512FE2785D00F5214A /* SignInVC.swift in Sources */,
|
||||
305A77092FCA8C7000227D26 /* PageContentView.swift in Sources */,
|
||||
305A770A2FCA8C7000227D26 /* PageStyle.swift in Sources */,
|
||||
|
|
@ -1759,6 +1818,7 @@
|
|||
3062E8BA2FCEAC6500CEF511 /* CreateGroupView.swift in Sources */,
|
||||
30D891F72FE22E6E00E958FD /* OrderService.swift in Sources */,
|
||||
305A77192FCA8C7000227D26 /* CollectionHFlowLayout.swift in Sources */,
|
||||
30D74AC12FEA6EEF0050EB2C /* CreateSchedulePopView.swift in Sources */,
|
||||
305A771A2FCA8C7000227D26 /* JJPageControl.swift in Sources */,
|
||||
305A771B2FCA8C7000227D26 /* ReusableView.swift in Sources */,
|
||||
305A771C2FCA8C7000227D26 /* AppDelegate.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// ItineraryAPI.swift
|
||||
// QuickLocation
|
||||
//
|
||||
// Created by 八条 on 2026/6/23.
|
||||
//
|
||||
|
||||
import Moya
|
||||
import SwiftyUserDefaults
|
||||
internal import Alamofire
|
||||
|
||||
/// 行程API
|
||||
enum ItineraryAPI {
|
||||
/// 查询行程
|
||||
/// - Parameters:
|
||||
/// - follow: 只查看关注的行程
|
||||
/// - own: 只查看自己创建的行程
|
||||
/// - history: true查看历史行程,默认查看今天之后的行程
|
||||
/// - group_key: 过滤圈子查询
|
||||
case query(follow: Bool, own: Bool, history: Bool, group_key: String, page: Int)
|
||||
|
||||
}
|
||||
|
||||
extension ItineraryAPI: MultiTargetProtocol {
|
||||
|
||||
var path: String {
|
||||
switch self {
|
||||
case .query:
|
||||
return "mapi/itinerary/route"
|
||||
}
|
||||
}
|
||||
|
||||
var method: Moya.Method {
|
||||
switch self {
|
||||
case .query:
|
||||
return .get
|
||||
default:
|
||||
return .post
|
||||
}
|
||||
}
|
||||
|
||||
var task: Moya.Task {
|
||||
switch self {
|
||||
case let .query(follow, own, history, group_key, page):
|
||||
var params = Parameters()
|
||||
params["follow"] = follow
|
||||
params["own"] = own
|
||||
params["history"] = history
|
||||
params["group_key"] = group_key
|
||||
params["page"] = page
|
||||
params["limit"] = 20
|
||||
return .requestParameters(parameters: params, encoding: URLEncoding())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,9 @@ enum SystemAPI {
|
|||
|
||||
/// 微信客服
|
||||
case wechatService
|
||||
|
||||
/// SOS
|
||||
case sos(enable: Bool)
|
||||
}
|
||||
|
||||
extension SystemAPI: MultiTargetProtocol {
|
||||
|
|
@ -32,6 +35,8 @@ extension SystemAPI: MultiTargetProtocol {
|
|||
return "api/user/sms/code"
|
||||
case .wechatService:
|
||||
return "api/weixin/service"
|
||||
case .sos:
|
||||
return "mapi/sos/operate"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -39,7 +44,7 @@ extension SystemAPI: MultiTargetProtocol {
|
|||
switch self {
|
||||
case .userConfig, .wechatService:
|
||||
return .get
|
||||
case .sendCode:
|
||||
case .sendCode, .sos:
|
||||
return .post
|
||||
}
|
||||
}
|
||||
|
|
@ -56,6 +61,12 @@ extension SystemAPI: MultiTargetProtocol {
|
|||
|
||||
case .wechatService:
|
||||
return .requestParameters(parameters: parameters, encoding: URLEncoding())
|
||||
|
||||
case let .sos(enable):
|
||||
var params = Parameters()
|
||||
params["enable"] = enable
|
||||
return .requestParameters(parameters: params, encoding: JSONEncoding())
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,12 @@ enum UserAPI {
|
|||
/// - group_key:频道的key
|
||||
/// - emote_idx:表情符号的下标
|
||||
case sendEmote(emoteIdx: Int, groupKey: String, targetUid: String)
|
||||
|
||||
/// 公告
|
||||
case notice
|
||||
|
||||
/// 查看关注用户列表
|
||||
case followList
|
||||
}
|
||||
|
||||
extension UserAPI: MultiTargetProtocol {
|
||||
|
|
@ -90,12 +96,16 @@ extension UserAPI: MultiTargetProtocol {
|
|||
return "api/user/logout"
|
||||
case .sendEmote:
|
||||
return "mapi/user/sendemote"
|
||||
case .notice:
|
||||
return "api/user/notice"
|
||||
case .followList:
|
||||
return "mapi/user/followed"
|
||||
}
|
||||
}
|
||||
|
||||
var method: Moya.Method {
|
||||
switch self {
|
||||
case .userInfo, .signInInfo:
|
||||
case .userInfo, .signInInfo, .notice, .followList:
|
||||
return .get
|
||||
case .changePhone, .setGender:
|
||||
return .put
|
||||
|
|
@ -167,6 +177,12 @@ extension UserAPI: MultiTargetProtocol {
|
|||
params["group_key"] = groupKey
|
||||
params["target_uid"] = targetUid
|
||||
return .requestParameters(parameters: params, encoding: JSONEncoding())
|
||||
|
||||
case .notice:
|
||||
return .requestParameters(parameters: Parameters(), encoding: URLEncoding())
|
||||
|
||||
case .followList:
|
||||
return .requestParameters(parameters: Parameters(), encoding: URLEncoding())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group_2309@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group_2309@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 846 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "x@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "x@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 566 B |
|
After Width: | Height: | Size: 711 B |
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"provides-namespace" : true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group_2267@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group_2267@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group_2250@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group_2250@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group_2308@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group_2308@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group_2264@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group_2264@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
|
@ -28,6 +28,8 @@ extension Notification.Name {
|
|||
static let RefreshUserConfigNotification = Notification.Name("RefreshUserConfigNotification")
|
||||
/// 刷新用户圈子数据
|
||||
static let RefreshGroupInfoNotification = Notification.Name("RefreshGroupInfoNotification")
|
||||
/// 刷新IM圈子列表数据
|
||||
static let RefreshIMGroupListNotification = Notification.Name("RefreshIMGroupListNotification")
|
||||
/// 支付宝/微信支付结果回调
|
||||
static let RequestOrderPayStatusNotification = Notification.Name("RequestOrderPayStatusNotification")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ final class MainTabBarController: UITabBarController {
|
|||
|
||||
// MARK: - View Controllers
|
||||
private lazy var locationNav = BaseNavigationController(rootViewController: HomeViewController())
|
||||
private lazy var exploreNav = BaseNavigationController(rootViewController: ViewController())
|
||||
private lazy var exploreNav = BaseNavigationController(rootViewController: ScheduleVC())
|
||||
private lazy var circlesNav = BaseNavigationController(rootViewController: GroupViewController())
|
||||
private lazy var mineNav = BaseNavigationController(rootViewController: MineViewController())
|
||||
|
||||
|
|
@ -57,6 +57,14 @@ final class MainTabBarController: UITabBarController {
|
|||
|
||||
view.addSubview(customTabBar)
|
||||
customTabBar.delegate = self
|
||||
// 点击"探索"(index=1)时游客跳登录、不选中
|
||||
customTabBar.shouldSelectTab = { index in
|
||||
if index == 1, AppContextManager.shared.isGuest {
|
||||
AppRouter.push(Route.login)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
customTabBar.translatesAutoresizingMaskIntoConstraints = false
|
||||
let tabBarHeight = customTabBar.intrinsicContentSize.height
|
||||
|
|
@ -89,6 +97,11 @@ final class MainTabBarController: UITabBarController {
|
|||
// MARK: - QuickLocationTabBarDelegate
|
||||
extension MainTabBarController: QuickLocationTabBarDelegate {
|
||||
func tabBar(_ tabBar: QuickLocationTabBar, didSelectTabAt index: Int) {
|
||||
// 点击"探索"(index=1)时判断游客,是则跳登录、不选中
|
||||
if index == 1, AppContextManager.shared.isGuest {
|
||||
AppRouter.push(Route.login)
|
||||
return
|
||||
}
|
||||
selectedIndex = index
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ final class QuickLocationTabBar: UIView {
|
|||
|
||||
// MARK: - Properties
|
||||
weak var delegate: QuickLocationTabBarDelegate?
|
||||
/// 返回 false 阻止选中(用于游客拦截等)
|
||||
var shouldSelectTab: ((Int) -> Bool)?
|
||||
|
||||
private let items: [TabItem]
|
||||
private var tabViews: [UIView] = []
|
||||
|
|
@ -121,6 +123,7 @@ final class QuickLocationTabBar: UIView {
|
|||
guard let view = gesture.view else { return }
|
||||
let index = view.tag
|
||||
guard index != selectedIndex else { return }
|
||||
if shouldSelectTab?(index) == false { return }
|
||||
selectedIndex = index
|
||||
updateSelection(animated: true)
|
||||
delegate?.tabBar(self, didSelectTabAt: index)
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ enum Route: String {
|
|||
case privacyPolicy = "privacyPolicy"
|
||||
/// 权限检测
|
||||
case checkPermission = "checkPermission"
|
||||
/// 创建行程
|
||||
case createSchedule = "createSchedule"
|
||||
}
|
||||
|
||||
extension Route: RouterTarget {
|
||||
|
|
@ -257,6 +259,11 @@ extension AppRouter: AppRouterProtocol {
|
|||
AppRouter.register(Route.checkPermission) { url, parameters in
|
||||
CheckPermissionVC()
|
||||
}
|
||||
|
||||
// MARK: - 创建行程
|
||||
AppRouter.register(Route.createSchedule) { url, parameters in
|
||||
CreateScheduleVC()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ class CreateGroupViewModel {
|
|||
"description": desc,
|
||||
"labels": selectedTagList]).subscribe(onNext: { response in
|
||||
DLToast.showSuccess(text: "创建成功") {
|
||||
NotificationCenter.default.post(name: .RefreshGroupInfoNotification, object: nil)
|
||||
NotificationCenter.default.post(name: .RefreshIMGroupListNotification, object: nil)
|
||||
AppRouter.shared.popOrDismiss()
|
||||
}
|
||||
}, onError: { (error) in
|
||||
|
|
|
|||
|
|
@ -406,7 +406,7 @@ final class GroupChatVC: BaseViewController {
|
|||
}
|
||||
|
||||
guard let url = recordFileURL, recordDuration >= 1 else {
|
||||
DLToast.show(text: "说话时间太短")
|
||||
self.dl.show(text: "说话时间太短")
|
||||
if let url = recordFileURL { try? FileManager.default.removeItem(at: url) }
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,10 +39,10 @@ class GroupInfoVC: BaseViewController {
|
|||
// MARK: - API
|
||||
private func requestOperateGroup() {
|
||||
guard let model = groupInModel else { return }
|
||||
DLToast.showLoading()
|
||||
dl.showLoading()
|
||||
GroupService.operate(opType: "join",
|
||||
requestData: ["share_code" : model.share_code]).subscribe(onNext: { response in
|
||||
DLToast.show(text: "申请成功")
|
||||
self.dl.show(text: "申请成功")
|
||||
}, onError: { (error) in }).disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -168,20 +168,20 @@ class GroupSettingVC: BaseViewController {
|
|||
}
|
||||
|
||||
private func requestLeaveGroup() {
|
||||
DLToast.showLoading()
|
||||
dl.showLoading()
|
||||
GroupService.leave(requestData: ["group_key": viewModel.groupId]).subscribe { response in
|
||||
DLToast.dismiss()
|
||||
DLToast.show(text: "成功退出") {
|
||||
self.dl.dismiss()
|
||||
self.dl.show(text: "成功退出") {
|
||||
AppRouter.shared.popToRoot()
|
||||
}
|
||||
}.disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
private func requestDismissGroup() {
|
||||
DLToast.showLoading()
|
||||
dl.showLoading()
|
||||
GroupService.dismiss(requestData: ["group_key": viewModel.groupId]).subscribe { response in
|
||||
DLToast.dismiss()
|
||||
DLToast.show(text: "成功解散") {
|
||||
self.dl.dismiss()
|
||||
self.dl.show(text: "成功解散") {
|
||||
AppRouter.shared.popToRoot()
|
||||
}
|
||||
}.disposed(by: disposeBag)
|
||||
|
|
|
|||
|
|
@ -141,6 +141,13 @@ final class GroupViewController: BaseViewController {
|
|||
})
|
||||
.disposed(by: disposeBag)
|
||||
|
||||
// MQTT join/leave/dismiss 后刷新群列表
|
||||
NotificationCenter.default.rx.notification(.RefreshIMGroupListNotification)
|
||||
.subscribe(onNext: { [weak self] _ in
|
||||
self?.requestGroupInfo()
|
||||
})
|
||||
.disposed(by: disposeBag)
|
||||
|
||||
NotificationCenter.default.rx.notification(.RefreshUserConfigNotification)
|
||||
.subscribe(onNext: { [weak self] _ in
|
||||
self?.requestRecommandGroup()
|
||||
|
|
|
|||
|
|
@ -30,6 +30,14 @@ class JoinGroupVC: BaseViewController {
|
|||
rootView.submitBtn.rx.tap.subscribe(onNext: { _ in
|
||||
self.requestOperateGroup()
|
||||
}).disposed(by: disposeBag)
|
||||
|
||||
rootView.scanBtn.rx.tap.subscribe(onNext: { _ in
|
||||
let vc = ScanVC { code in
|
||||
self.rootView.textField.text = code
|
||||
self.rootView.textField.resignFirstResponder()
|
||||
}
|
||||
AppRouter.push(vc)
|
||||
}).disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
|
|
@ -43,9 +51,9 @@ class JoinGroupVC: BaseViewController {
|
|||
DLToast.show(text: "请填写完整的邀请码")
|
||||
return
|
||||
}
|
||||
DLToast.showLoading()
|
||||
dl.showLoading()
|
||||
GroupService.operate(opType: "join", requestData: ["share_code" : rootView.inviteCode]).subscribe(onNext: { response in
|
||||
DLToast.showSuccess(text: "申请成功") {
|
||||
self.dl.showSuccess(text: "申请成功") {
|
||||
AppRouter.shared.popOrDismiss()
|
||||
}
|
||||
}).disposed(by: disposeBag)
|
||||
|
|
|
|||
|
|
@ -55,9 +55,7 @@ class JoinGroupView: UIView {
|
|||
AppRouter.shared.popOrDismiss()
|
||||
}).disposed(by: disposeBag)
|
||||
|
||||
scanBtn.rx.tap.subscribe(onNext: { _ in
|
||||
AppRouter.push(Route.scan)
|
||||
}).disposed(by: disposeBag)
|
||||
|
||||
}
|
||||
|
||||
private func setupUI() {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import RxCocoa
|
|||
import Lottie
|
||||
#if !targetEnvironment(simulator)
|
||||
import AMapNaviKit
|
||||
import MarqueeLabel
|
||||
#endif
|
||||
|
||||
class HomeView: UIView {
|
||||
|
|
@ -23,6 +24,16 @@ class HomeView: UIView {
|
|||
|
||||
let interactionView = InteractionView(frame: CGRectMake(0, kScreenHeight, kScreenWidth, 384))
|
||||
|
||||
var gpsSignalViewList: [UIView] = []
|
||||
|
||||
/// 根据信号格数更新信号条颜色
|
||||
func updateGPSSignal(bars: Int) {
|
||||
let filled = max(0, min(bars, gpsSignalViewList.count))
|
||||
for (i, view) in gpsSignalViewList.enumerated() {
|
||||
view.backgroundColor = i < filled ? UIColor(hexStr: "#4ED178") : UIColor(hexStr: "#E0E0E0")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - groupMemberView 拖拽
|
||||
private var groupMemberTopConstraint: NSLayoutConstraint?
|
||||
private var groupMemberUpLimit: CGFloat = 0
|
||||
|
|
@ -91,11 +102,7 @@ class HomeView: UIView {
|
|||
}
|
||||
})
|
||||
.disposed(by: disposeBag)
|
||||
|
||||
// 收回互动view
|
||||
quickMessageView.closeBtn.rx.tap.subscribe(onNext: { _ in
|
||||
self.dismissMemberPanel()
|
||||
}).disposed(by: disposeBag)
|
||||
|
||||
}
|
||||
|
||||
private func setupUI() {
|
||||
|
|
@ -175,7 +182,7 @@ class HomeView: UIView {
|
|||
.edgesHorzontal(15)
|
||||
|
||||
toolsView.layoutChain
|
||||
.left(23)
|
||||
.left(15)
|
||||
.bottom(kScreenHeight / 2 - 58)
|
||||
.width(40)
|
||||
|
||||
|
|
@ -279,6 +286,13 @@ class HomeView: UIView {
|
|||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
noticeView.layoutIfNeeded()
|
||||
noticeInfoView.setGradientLayer(frame: noticeInfoView.bounds,
|
||||
startPoint: CGPoint(x: 0, y: 0.5),
|
||||
endPoint: CGPoint(x: 1, y: 0.5),
|
||||
colors: [UIColor(hexStr: "#FFFFFF", alpha: 0), UIColor(hexStr: "#FFFFFF"), UIColor(hexStr: "#FFFFFF", alpha: 0)],
|
||||
locations: [0, 0.5, 1])
|
||||
|
||||
if !isGroupMemberLimitsSet {
|
||||
isGroupMemberLimitsSet = true
|
||||
groupMemberDownLimit = groupMemberView.frame.minY
|
||||
|
|
@ -438,25 +452,153 @@ class HomeView: UIView {
|
|||
}()
|
||||
|
||||
lazy var messageStackView: UIStackView = {
|
||||
let view = UIStackView(arrangedSubviews: [noticeView, messageBubbleView])
|
||||
let view = UIStackView(arrangedSubviews: [tipsView, messageBubbleView])
|
||||
view.axis = .vertical
|
||||
view.alignment = .leading
|
||||
view.spacing = 15
|
||||
view.spacing = 5
|
||||
view.backgroundColor = .clear
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var tipsView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .clear
|
||||
view.layoutChain.height(22)
|
||||
|
||||
view.addSubview(gpsSignalView)
|
||||
gpsSignalView.layoutChain
|
||||
.left()
|
||||
.centerY()
|
||||
|
||||
view.addSubview(noticeView)
|
||||
noticeView.layoutChain
|
||||
.leftToRightOfView(gpsSignalView, offset: 0)
|
||||
.right(15)
|
||||
.edgesVertical()
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
// MARK: - 卫星信号
|
||||
lazy var gpsSignalView: UIView = {
|
||||
let view = UIView()
|
||||
view.cornerRadius = 5
|
||||
view.backgroundColor = .black.withAlphaComponent(0.4)
|
||||
|
||||
let signalView1 = UIView()
|
||||
signalView1.backgroundColor = UIColor(hexStr: "#E6E6E6")
|
||||
view.addSubview(signalView1)
|
||||
signalView1.layoutChain
|
||||
.left(7)
|
||||
.bottom(5)
|
||||
.width(3)
|
||||
.height(4)
|
||||
|
||||
let signalView2 = UIView()
|
||||
signalView2.backgroundColor = UIColor(hexStr: "#E6E6E6")
|
||||
view.addSubview(signalView2)
|
||||
signalView2.layoutChain
|
||||
.leftToRightOfView(signalView1, offset: 2)
|
||||
.bottomToView(signalView1)
|
||||
.width(3)
|
||||
.height(6)
|
||||
|
||||
let signalView3 = UIView()
|
||||
signalView3.backgroundColor = UIColor(hexStr: "#E6E6E6")
|
||||
view.addSubview(signalView3)
|
||||
signalView3.layoutChain
|
||||
.leftToRightOfView(signalView2, offset: 2)
|
||||
.bottomToView(signalView1)
|
||||
.width(3)
|
||||
.height(8)
|
||||
|
||||
let signalView4 = UIView()
|
||||
signalView4.backgroundColor = UIColor(hexStr: "#E6E6E6")
|
||||
view.addSubview(signalView4)
|
||||
signalView4.layoutChain
|
||||
.leftToRightOfView(signalView3, offset: 2)
|
||||
.bottomToView(signalView1)
|
||||
.width(3)
|
||||
.height(10)
|
||||
|
||||
let label = UILabel()
|
||||
label.text = "卫星信号"
|
||||
label.font = .systemFont(ofSize: 10, weight: .medium)
|
||||
label.textColor = .white
|
||||
view.addSubview(label)
|
||||
label.layoutChain
|
||||
.leftToRightOfView(signalView4, offset: 2)
|
||||
.edgesVertical(4)
|
||||
.right(7)
|
||||
|
||||
gpsSignalViewList = [signalView1, signalView2, signalView3, signalView4]
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
// MARK: - 公告
|
||||
lazy var noticeView: UIView = {
|
||||
let view = UIView()
|
||||
view.isHidden = true
|
||||
view.backgroundColor = .clear
|
||||
|
||||
view.layoutChain
|
||||
.height(22)
|
||||
view.addSubview(noticeInfoView)
|
||||
noticeInfoView.layoutChain
|
||||
.left()
|
||||
.right()
|
||||
.edgesVertical()
|
||||
|
||||
view.addSubview(noticeCloseBtn)
|
||||
noticeCloseBtn.layoutChain
|
||||
.right()
|
||||
.width(16)
|
||||
.height(16)
|
||||
.centerY()
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var noticeInfoView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .clear
|
||||
|
||||
// let titleLab = UILabel()
|
||||
// titleLab.text = "公告信息"
|
||||
// titleLab.font = .systemFont(ofSize: 10, weight: .medium)
|
||||
// titleLab.textColor = UIColor(hexStr: "#0F2948")
|
||||
// view.addSubview(titleLab)
|
||||
// titleLab.layoutChain
|
||||
// .left(16)
|
||||
// .centerY()
|
||||
// .width(40)
|
||||
|
||||
view.addSubview(noticeLab)
|
||||
noticeLab.layoutChain
|
||||
.left(16)
|
||||
.centerY()
|
||||
.right(24)
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var noticeLab: CallbackMarqueeLabel = {
|
||||
let label = CallbackMarqueeLabel()
|
||||
label.font = .systemFont(ofSize: 10, weight: .medium)
|
||||
label.textColor = UIColor(hexStr: "#0F2948")
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var noticeCloseBtn: UIButton = {
|
||||
let btn = UIButton()
|
||||
btn.setImage(UIImage(named: "Common/x_black"), for: .normal)
|
||||
btn.backgroundColor = .white
|
||||
btn.cornerRadius = 8
|
||||
btn.extendEdgeInsets = UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15)
|
||||
btn.rx.tap.subscribe(onNext: { [weak self] _ in
|
||||
self?.noticeView.isHidden = true
|
||||
}).disposed(by: disposeBag)
|
||||
return btn
|
||||
}()
|
||||
|
||||
// MARK: - 消息气泡
|
||||
lazy var messageBubbleView: UIView = {
|
||||
let view = UIView()
|
||||
|
|
@ -654,3 +796,24 @@ extension HomeView: UIGestureRecognizerDelegate {
|
|||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - CallbackMarqueeLabel
|
||||
class CallbackMarqueeLabel: MarqueeLabel {
|
||||
// 闭包回调对外抛出事件
|
||||
var onScrollLoopComplete: (() -> Void)?
|
||||
var onScrollStart: (() -> Void)?
|
||||
|
||||
// 滚动开始
|
||||
override func labelWillBeginScroll() {
|
||||
super.labelWillBeginScroll()
|
||||
onScrollStart?()
|
||||
}
|
||||
|
||||
// 单次滚动一圈完成
|
||||
override func labelReturnedToHome(_ finished: Bool) {
|
||||
super.labelReturnedToHome(finished)
|
||||
// 只处理正常滚动结束,过滤中途重置
|
||||
guard finished else { return }
|
||||
onScrollLoopComplete?()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import SwiftyUserDefaults
|
|||
import AMapNaviKit
|
||||
import CocoaMQTT
|
||||
import Lottie
|
||||
import AVFAudio
|
||||
import MarqueeLabel
|
||||
#endif
|
||||
|
||||
class HomeViewController: BaseViewController {
|
||||
|
|
@ -52,6 +52,8 @@ class HomeViewController: BaseViewController {
|
|||
private var offlineCheckTimer: Timer?
|
||||
|
||||
private var sosPlayerKey: UInt8 = 0
|
||||
private var groupRefreshWorkItem: DispatchWorkItem?
|
||||
private var groupSwitchWorkItem: DispatchWorkItem?
|
||||
|
||||
override func loadView() {
|
||||
#if !targetEnvironment(simulator)
|
||||
|
|
@ -71,7 +73,7 @@ class HomeViewController: BaseViewController {
|
|||
reactiveAction()
|
||||
|
||||
requestUserConfig()
|
||||
|
||||
|
||||
rootView.quickMessageView.tagListView.delegate = self
|
||||
// MQTT 位置上报
|
||||
UIDevice.current.isBatteryMonitoringEnabled = true
|
||||
|
|
@ -250,6 +252,8 @@ class HomeViewController: BaseViewController {
|
|||
self.requestUserInfo { [weak self] in
|
||||
self?.requestGroupInfo()
|
||||
}
|
||||
// 首页公告
|
||||
self.requestNotice()
|
||||
}).disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
|
|
@ -274,10 +278,13 @@ class HomeViewController: BaseViewController {
|
|||
}.disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
private func requestGroupInfo() {
|
||||
private func requestGroupInfo(isDefaultGroup: Bool=true) {
|
||||
GroupService.groupInfo().subscribe { response in
|
||||
guard let model = response.model else { return }
|
||||
self.viewModel.groupModel = model
|
||||
NotificationCenter.default.post(name: .RefreshIMGroupListNotification, object: nil)
|
||||
|
||||
guard isDefaultGroup else { return }
|
||||
self.rootView.groupMemberView.setupCountData(self.viewModel.memberCount, 1)
|
||||
self.rootView.groupNameLab.text = self.viewModel.groupName
|
||||
self.syncMemberAnnotations(model.select_group_employee)
|
||||
|
|
@ -291,6 +298,22 @@ class HomeViewController: BaseViewController {
|
|||
}.disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
private func requestNotice() {
|
||||
UserService.notice().subscribe { response in
|
||||
self.rootView.noticeLab.text = ""
|
||||
guard let data = response.data, let noticeList = data["notice"] as? [String] else { return }
|
||||
self.rootView.noticeView.isHidden = noticeList.count == 0
|
||||
self.rootView.noticeLab.text = noticeList.joined(separator: " ") + " "
|
||||
if let loop = data["loop"] as? Bool {
|
||||
self.rootView.noticeLab.type = loop ? .continuous : .leftRight
|
||||
self.rootView.noticeLab.onScrollLoopComplete = {
|
||||
guard loop == false else { return }
|
||||
self.rootView.noticeView.isHidden = true
|
||||
}
|
||||
}
|
||||
}.disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
// MARK: - Map Setup
|
||||
private func setupMap() {
|
||||
#if !targetEnvironment(simulator)
|
||||
|
|
@ -423,6 +446,24 @@ class HomeViewController: BaseViewController {
|
|||
|
||||
// MARK: - MQTT
|
||||
extension HomeViewController {
|
||||
/// join/leave/dismiss 防抖刷新(500ms 内多次触发只调一次)
|
||||
private func debounceGroupSwitch(groupKey: String) {
|
||||
groupSwitchWorkItem?.cancel()
|
||||
let work = DispatchWorkItem { [weak self] in
|
||||
self?.requestOperateGroup(groupKey: groupKey)
|
||||
}
|
||||
groupSwitchWorkItem = work
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: work)
|
||||
}
|
||||
|
||||
private func debounceGroupRefresh() {
|
||||
groupRefreshWorkItem?.cancel()
|
||||
let work = DispatchWorkItem { [weak self] in
|
||||
self?.requestGroupInfo()
|
||||
}
|
||||
groupRefreshWorkItem = work
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: work)
|
||||
}
|
||||
/// 切换圈子时刷新 MQTT 订阅
|
||||
private func refreshMQTTSubscriptions(_ members: [GroupMemberModel]) {
|
||||
// let currentId = AppContextManager.shared.userId
|
||||
|
|
@ -544,7 +585,10 @@ extension HomeViewController {
|
|||
}
|
||||
}
|
||||
}
|
||||
case "sos":
|
||||
case "sos": // 求助
|
||||
self.requestGroupInfo(isDefaultGroup: false)
|
||||
guard let userId = msg.data?.user_id,
|
||||
userId != AppContextManager.shared.userId else { return }
|
||||
playSOSAlarm()
|
||||
rootView.sosPopView.isHidden = false
|
||||
rootView.sosPopView.play(toFrame: 30.0) { completed in
|
||||
|
|
@ -552,6 +596,55 @@ extension HomeViewController {
|
|||
self.rootView.sosPopView.stop()
|
||||
self.rootView.sosPopView.isHidden = true
|
||||
}
|
||||
case "join": // 圈子有成员加入
|
||||
guard let gk = msg.data?.group_key,
|
||||
let defaultGk = self.viewModel.groupModel?.default_group_key,
|
||||
gk == defaultGk else {
|
||||
self.requestGroupInfo(isDefaultGroup: false)
|
||||
return
|
||||
}
|
||||
debounceGroupRefresh()
|
||||
case "leave": // 圈子有成员离开
|
||||
guard let userId = msg.data?.user_id, let gk = msg.data?.group_key,
|
||||
let defaultGk = self.viewModel.groupModel?.default_group_key,
|
||||
defaultGk.hasPrefix(gk) else {
|
||||
self.requestGroupInfo(isDefaultGroup: false)
|
||||
return
|
||||
}
|
||||
// 是当前选中圈子就移除成员
|
||||
if userId == AppContextManager.shared.userId { // 当前用户就切换到第一个圈子
|
||||
guard let model = self.viewModel.groupModel,
|
||||
let groupInfoModel = model.groups.first else { return }
|
||||
if model.groups.count > 1 {
|
||||
self.debounceGroupSwitch(groupKey: groupInfoModel.group_key)
|
||||
}
|
||||
else {
|
||||
debounceGroupRefresh()
|
||||
}
|
||||
}
|
||||
else { // 移除成员
|
||||
guard self.viewModel.memberIsExist(userId: userId) else { return }
|
||||
self.viewModel.removeMember(userId: userId)
|
||||
self.removeAnnotation(userId: userId)
|
||||
self.rootView.groupMemberView.setupCountData(self.viewModel.memberList.count, 1)
|
||||
MQTTService.shared.unsubscribe(topic: "smartdrive/\(userId)")
|
||||
}
|
||||
case "dismiss": // 圈子解散
|
||||
guard let gk = msg.data?.group_key,
|
||||
let defaultGk = self.viewModel.groupModel?.default_group_key,
|
||||
gk == defaultGk,
|
||||
let model = self.viewModel.groupModel,
|
||||
let groupInfoModel = model.groups.first else {
|
||||
self.requestGroupInfo(isDefaultGroup: false)
|
||||
return
|
||||
}
|
||||
if model.groups.count > 1 {
|
||||
self.debounceGroupSwitch(groupKey: groupInfoModel.group_key)
|
||||
}
|
||||
else {
|
||||
debounceGroupRefresh()
|
||||
}
|
||||
|
||||
default:
|
||||
print("📩 未处理 type=\(msg.type ?? "")")
|
||||
}
|
||||
|
|
@ -638,6 +731,12 @@ extension HomeViewController: MAMapViewDelegate {
|
|||
|
||||
func mapView(_ mapView: MAMapView!, didUpdate userLocation: MAUserLocation!, updatingLocation: Bool) {
|
||||
guard updatingLocation, let location = userLocation.location else { return }
|
||||
|
||||
// 卫星信号
|
||||
let strength = gpsSignalStrength(from: location)
|
||||
rootView.updateGPSSignal(bars: strength.barCount)
|
||||
|
||||
// 地图标注
|
||||
lastLocation = location
|
||||
let coordinate = location.coordinate
|
||||
guard CLLocationCoordinate2DIsValid(coordinate) else { return }
|
||||
|
|
@ -662,6 +761,10 @@ extension HomeViewController {
|
|||
}
|
||||
|
||||
private func playSOSAlarm() {
|
||||
// 停止上一次报警
|
||||
sosPlayer?.stop()
|
||||
sosPlayer = nil
|
||||
|
||||
guard let url = Bundle.main.url(forResource: "sos", withExtension: "mp3") ?? Bundle.main.url(forResource: "sos", withExtension: "mp3", subdirectory: "sound") else {
|
||||
print("❌ SOS: sos.mp3 not found in bundle")
|
||||
return
|
||||
|
|
@ -677,11 +780,11 @@ extension HomeViewController {
|
|||
return
|
||||
}
|
||||
print("✅ SOS: playing alarm")
|
||||
player.numberOfLoops = -1
|
||||
player.numberOfLoops = 0
|
||||
player.volume = 1.0
|
||||
player.play()
|
||||
self.sosPlayer = player
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 30) { [weak self] in
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 15) { [weak self] in
|
||||
self?.sosPlayer?.stop()
|
||||
self?.sosPlayer = nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,6 +114,19 @@ class HomeViewModel {
|
|||
updated[idx].last_active_time = lastUpdateTime
|
||||
memberList = updated // 触发 didSet → 排序 + 重发 sectionedItems
|
||||
}
|
||||
|
||||
/// 成员是否存在
|
||||
func memberIsExist(userId: String) -> Bool {
|
||||
(memberList.first(where: { $0.user_id == userId }) != nil)
|
||||
}
|
||||
|
||||
/// 移除成员
|
||||
func removeMember(userId: String) {
|
||||
guard let idx = memberList.firstIndex(where: { $0.user_id == userId }) else { return }
|
||||
var updated = memberList
|
||||
updated.remove(at: idx)
|
||||
memberList = updated
|
||||
}
|
||||
|
||||
// MARK: - Init
|
||||
init() {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ class SOSView: UIView {
|
|||
|
||||
var sosPracticeView: SOSPracticeView = SOSPracticeView()
|
||||
|
||||
var didSendSOS: ((Bool) -> Void)?
|
||||
|
||||
var countDownFinish: Bool = false
|
||||
|
||||
private func setupRx() {
|
||||
|
|
@ -37,6 +39,9 @@ class SOSView: UIView {
|
|||
self.countDownLottieView.play()
|
||||
self.countDownTipsLab.text = "已将你的SOS和位置发送到你的圈子和紧急联系人。\n\n您的 SOS 将发送给5个人"
|
||||
self.countDownFinish = true
|
||||
if let didSendSOS = self.didSendSOS {
|
||||
didSendSOS(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -57,7 +62,9 @@ class SOSView: UIView {
|
|||
case .ended:
|
||||
if self.sliderIcon.frame.minX >= maxX - 5 {
|
||||
if countDownFinish {
|
||||
|
||||
if let didSendSOS = self.didSendSOS {
|
||||
didSendSOS(false)
|
||||
}
|
||||
}
|
||||
else {
|
||||
self.countDownView.alpha = 0
|
||||
|
|
@ -313,16 +320,6 @@ class SOSView: UIView {
|
|||
|
||||
let isHidden = Defaults[\.sosIsPracticeList].first(where: { $0 == AppContextManager.shared.userId }) != nil
|
||||
sosPracticeView.isHidden = isHidden
|
||||
|
||||
guard AppContextManager.shared.status == 1 else { return }
|
||||
countDownView.alpha = 1
|
||||
countDownFinish = true
|
||||
if let path = Bundle.main.path(forResource: "red-exclamation", ofType: "json") {
|
||||
self.countDownLottieView.animation = LottieAnimation.filepath(path)
|
||||
self.countDownLottieView.loopMode = .loop
|
||||
self.countDownLottieView.play()
|
||||
self.countDownTipsLab.text = "已将你的SOS和位置发送到你的圈子和紧急联系人。\n\n您的 SOS 将发送给5个人"
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import RxSwift
|
||||
import Lottie
|
||||
|
||||
class SOSViewController: BaseViewController {
|
||||
|
||||
|
|
@ -21,17 +23,37 @@ class SOSViewController: BaseViewController {
|
|||
|
||||
// Do any additional setup after loading the view.
|
||||
fd_interactivePopDisabled = true
|
||||
// requestUserInfo()
|
||||
|
||||
rootView.didSendSOS = { status in
|
||||
self.requestSOS(status)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// MARK: - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
// Get the new view controller using segue.destination.
|
||||
// Pass the selected object to the new view controller.
|
||||
private func requestUserInfo(completion: (() -> Void)? = nil) {
|
||||
UserService.userInfo().subscribe { response in
|
||||
guard let model = response.model else { return }
|
||||
AppContextManager.shared.saveAccount(model)
|
||||
|
||||
guard model.status == 1 else { return }
|
||||
self.rootView.countDownView.alpha = 1
|
||||
self.rootView.countDownFinish = true
|
||||
if let path = Bundle.main.path(forResource: "red-exclamation", ofType: "json") {
|
||||
self.rootView.countDownLottieView.animation = LottieAnimation.filepath(path)
|
||||
self.rootView.countDownLottieView.loopMode = .loop
|
||||
self.rootView.countDownLottieView.play()
|
||||
self.rootView.countDownTipsLab.text = "已将你的SOS和位置发送到你的圈子和紧急联系人。\n\n您的 SOS 将发送给5个人"
|
||||
}
|
||||
|
||||
}.disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
private func requestSOS(_ enable: Bool) {
|
||||
dl.showLoading()
|
||||
SystemService.sos(enable: enable).subscribe(onNext: { response in
|
||||
self.dl.show(text: enable ? "发送成功" : "取消成功") {
|
||||
AppRouter.shared.popOrDismiss()
|
||||
}
|
||||
}, onError: { (error) in }).disposed(by: disposeBag)
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,17 +31,17 @@ class SignInVC: BaseViewController {
|
|||
requestSignInInfo()
|
||||
|
||||
rootView.signInLottieView.rx.tapGesture.subscribe(onNext: { [weak self] _ in
|
||||
self?.dl.showLoading()
|
||||
guard let self = self, let loc = self.lastLocation, isSignIn == false else { return }
|
||||
DLToast.showLoading()
|
||||
self.geocoder.reverseGeocodeLocation(loc) { [weak self] placemarks, error in
|
||||
DLToast.dismiss()
|
||||
self?.dl.dismiss()
|
||||
guard let self = self else { return }
|
||||
let address = placemarks?.first?.name
|
||||
?? placemarks?.first?.thoroughfare
|
||||
?? placemarks?.first?.locality
|
||||
?? ""
|
||||
MQTTService.shared.reportSignIn(lat: loc.coordinate.latitude, lon: loc.coordinate.longitude, addr: address)
|
||||
DLToast.show(text: "签到成功") {
|
||||
self.dl.show(text: "签到成功") {
|
||||
self.requestSignInInfo()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ class ScanVC: BaseViewController {
|
|||
view = rootView
|
||||
}
|
||||
|
||||
private let scanDoneAction: ((String) -> Void)?
|
||||
|
||||
private var captureSession: AVCaptureSession!
|
||||
private var previewLayer: AVCaptureVideoPreviewLayer!
|
||||
private var isScanning = false
|
||||
|
|
@ -51,6 +53,15 @@ class ScanVC: BaseViewController {
|
|||
}
|
||||
rootView.scanLineView.layer.removeAllAnimations()
|
||||
}
|
||||
|
||||
init(scanDoneAction: ((String) -> Void)? = nil) {
|
||||
self.scanDoneAction = scanDoneAction
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private func handleScanResult(text: String) {
|
||||
guard !isScanning else { return }
|
||||
|
|
@ -58,15 +69,18 @@ class ScanVC: BaseViewController {
|
|||
captureSession.stopRunning()
|
||||
rootView.scanLineView.alpha = 0
|
||||
rootView.scanLineView.layer.removeAllAnimations()
|
||||
requestJoinGroup(code: text)
|
||||
if let scanDoneAction = scanDoneAction {
|
||||
scanDoneAction(text)
|
||||
AppRouter.shared.popOrDismiss()
|
||||
}
|
||||
// requestJoinGroup(code: text)
|
||||
}
|
||||
|
||||
// MARK: - API
|
||||
private func requestJoinGroup(code: String) {
|
||||
DLToast.showLoading()
|
||||
dl.showLoading()
|
||||
GroupService.operate(opType: "join", requestData: ["share_code" : code]).subscribe(onNext: { response in
|
||||
DLToast.show(text: "申请成功") {
|
||||
NotificationCenter.default.post(name: .RefreshGroupInfoNotification, object: nil)
|
||||
self.dl.show(text: "申请成功") {
|
||||
AppRouter.shared.popOrDismiss()
|
||||
}
|
||||
}, onError: { [weak self] (error) in
|
||||
|
|
|
|||
|
|
@ -0,0 +1,447 @@
|
|||
//
|
||||
// CreateSchedulePopView.swift
|
||||
// QuickLocation
|
||||
//
|
||||
// Created by 八条 on 2026/6/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import RxSwift
|
||||
import RxCocoa
|
||||
import RxDataSources
|
||||
import BRPickerView
|
||||
|
||||
// MARK: - 行程点编辑模型
|
||||
struct SchedulePointItem: IdentifiableType, Equatable {
|
||||
let identity: String = UUID().uuidString
|
||||
var locationName: String = ""
|
||||
var address: String = ""
|
||||
var expectedTime: Date?
|
||||
var remark: String = ""
|
||||
}
|
||||
|
||||
typealias SchedulePointSection = SectionModel<String, SchedulePointItem>
|
||||
|
||||
// MARK: - CreateSchedulePopView
|
||||
|
||||
class CreateSchedulePopView: UIView {
|
||||
|
||||
var disposeBag = DisposeBag()
|
||||
|
||||
let pointsRelay = BehaviorRelay<[SchedulePointItem]>(value: [SchedulePointItem()])
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
private func setupRx() {
|
||||
dateLab.rx.tapGesture.subscribe { _ in
|
||||
let picker = BRDatePickerView(pickerMode: .YMD)
|
||||
picker.minDate = Date()
|
||||
picker.maxDate = Calendar.current.date(byAdding: .day, value: 6, to: Date())
|
||||
let style = BRPickerStyle()
|
||||
style.selectRowTextColor = UIColor(hexStr: "#16B3FF")
|
||||
picker.pickerStyle = style
|
||||
picker.resultBlock = { [weak self] selectDate, value in
|
||||
guard let date = selectDate else { return }
|
||||
let fmt = DateFormatter()
|
||||
fmt.dateFormat = "yyyy年MM月dd日"
|
||||
self?.dateLab.text = fmt.string(from: date)
|
||||
}
|
||||
picker.show()
|
||||
}.disposed(by: disposeBag)
|
||||
|
||||
// 新增行程点
|
||||
addBtn.rx.tap
|
||||
.subscribe(onNext: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
var list = self.pointsRelay.value
|
||||
list.append(SchedulePointItem(
|
||||
locationName: "",
|
||||
address: "",
|
||||
expectedTime: nil,
|
||||
remark: ""
|
||||
))
|
||||
self.pointsRelay.accept(list)
|
||||
})
|
||||
.disposed(by: disposeBag)
|
||||
|
||||
// 绑定 tableView
|
||||
pointsRelay
|
||||
.observe(on: MainScheduler.asyncInstance)
|
||||
.map { [SchedulePointSection(model: "", items: $0)] }
|
||||
.bind(to: tableView.rx.items(dataSource: dataSource))
|
||||
.disposed(by: disposeBag)
|
||||
|
||||
// 动态更新 tableView 高度
|
||||
pointsRelay
|
||||
.subscribe(onNext: { [weak self] items in
|
||||
guard let self = self else { return }
|
||||
let rowHeight: CGFloat = 122
|
||||
var h = CGFloat(items.count) * rowHeight
|
||||
h = max(h, rowHeight)
|
||||
self.tableView.layoutChain.height(h)
|
||||
})
|
||||
.disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
private lazy var dataSource: RxTableViewSectionedReloadDataSource<SchedulePointSection> = {
|
||||
RxTableViewSectionedReloadDataSource<SchedulePointSection>(
|
||||
configureCell: { [weak self] _, tv, indexPath, item in
|
||||
let cell: SchedulePointCell = tv.dequeueReusableCell(for: indexPath)
|
||||
cell.configure(item: item,
|
||||
index: indexPath.row,
|
||||
total: self?.pointsRelay.value.count ?? 0,
|
||||
onDelete: { [weak self] in
|
||||
guard let self = self else { return }
|
||||
var list = self.pointsRelay.value
|
||||
guard indexPath.row < list.count else { return }
|
||||
list.remove(at: indexPath.row)
|
||||
self.pointsRelay.accept(list)
|
||||
})
|
||||
return cell
|
||||
})
|
||||
}()
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
private func setupUI() {
|
||||
addSubview(lineView)
|
||||
addSubview(dateView)
|
||||
addSubview(detailView)
|
||||
addSubview(scrollView)
|
||||
|
||||
lineView.layoutChain
|
||||
.top(15)
|
||||
.centerX()
|
||||
.width(36)
|
||||
.height(4)
|
||||
|
||||
dateView.layoutChain
|
||||
.topToBottomOfView(lineView, offset: 19)
|
||||
.edgesHorzontal()
|
||||
.height(22)
|
||||
|
||||
detailView.layoutChain
|
||||
.topToBottomOfView(dateView, offset: 20)
|
||||
.edgesHorzontal()
|
||||
.height(22)
|
||||
|
||||
scrollView.layoutChain
|
||||
.topToBottomOfView(detailView, offset: 15)
|
||||
.edges(excludingEdge: .top)
|
||||
}
|
||||
|
||||
// MARK: - Views
|
||||
|
||||
lazy var lineView: UIView = {
|
||||
let v = UIView()
|
||||
v.backgroundColor = UIColor(hexStr: "#EBEBEB")
|
||||
v.cornerRadius = 2
|
||||
return v
|
||||
}()
|
||||
|
||||
lazy var dateView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .clear
|
||||
let titleLab = UILabel()
|
||||
titleLab.text = "行程日期:"
|
||||
titleLab.font = .systemFont(ofSize: 14, weight: .medium)
|
||||
titleLab.textColor = ThemeManager.shared.color.titleAuxColor
|
||||
view.addSubview(titleLab)
|
||||
titleLab.layoutChain.left(15).centerY()
|
||||
view.addSubview(dateLab)
|
||||
dateLab.layoutChain.leftToRightOfView(titleLab).centerY()
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var dateLab: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .systemFont(ofSize: 14, weight: .medium)
|
||||
label.textColor = UIColor(hexStr: "#16B3FF")
|
||||
label.isUserInteractionEnabled = true
|
||||
let fmt = DateFormatter()
|
||||
fmt.dateFormat = "yyyy年MM月dd日"
|
||||
label.text = fmt.string(from: Date())
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var detailView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .clear
|
||||
let titleLab = UILabel()
|
||||
titleLab.text = "行程详情"
|
||||
titleLab.font = .systemFont(ofSize: 14, weight: .medium)
|
||||
titleLab.textColor = ThemeManager.shared.color.titleAuxColor
|
||||
view.addSubview(titleLab)
|
||||
titleLab.layoutChain.left(15).centerY()
|
||||
view.addSubview(addBtn)
|
||||
addBtn.layoutChain.right(15).centerY().width(18).height(18)
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var addBtn: UIButton = {
|
||||
let btn = UIButton(type: .custom)
|
||||
btn.setImage(UIImage(named: "Schedule/add"), for: .normal)
|
||||
btn.backgroundColor = .clear
|
||||
btn.extendEdgeInsets = UIEdgeInsets(top: 30, left: 10, bottom: 10, right: 15)
|
||||
return btn
|
||||
}()
|
||||
|
||||
lazy var scrollView: UIScrollView = {
|
||||
let view = UIScrollView()
|
||||
view.backgroundColor = .white
|
||||
view.showsHorizontalScrollIndicator = false
|
||||
view.bounces = false
|
||||
|
||||
let contentView = UIView()
|
||||
contentView.backgroundColor = .clear
|
||||
view.addSubview(contentView)
|
||||
contentView.layoutChain
|
||||
.edges().widthToView(view)
|
||||
|
||||
contentView.addSubview(tableView)
|
||||
tableView.layoutChain
|
||||
.top()
|
||||
.edgesHorzontal()
|
||||
|
||||
contentView.addSubview(createBtn)
|
||||
createBtn.layoutChain
|
||||
.topToBottomOfView(tableView, offset: 30)
|
||||
.edgesHorzontal(30)
|
||||
.height(50)
|
||||
.bottom(kSafeBottomMargin + 10)
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var tableView: UITableView = {
|
||||
let tv = UITableView(frame: .zero, style: .plain)
|
||||
tv.backgroundColor = .clear
|
||||
tv.separatorStyle = .none
|
||||
tv.estimatedRowHeight = 122
|
||||
tv.isScrollEnabled = false
|
||||
tv.showsVerticalScrollIndicator = false
|
||||
tv.bounces = false
|
||||
tv.register(SchedulePointCell.self)
|
||||
return tv
|
||||
}()
|
||||
|
||||
lazy var createBtn: UIButton = {
|
||||
let btn = UIButton(type: .custom)
|
||||
btn.setTitle("立即创建", for: .normal)
|
||||
btn.setTitleColor(.white, for: .normal)
|
||||
btn.titleLabel?.font = .systemFont(ofSize: 16, weight: .medium)
|
||||
btn.setBackgroundImage(UIImage(named: "Common/button_bg_2"), for: .normal)
|
||||
btn.cornerRadius = 25
|
||||
return btn
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
backgroundColor = .white
|
||||
setupUI()
|
||||
setupRx()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
layoutIfNeeded()
|
||||
setCornerRadius(corners: [.topLeft, .topRight], withCornerRadii: CGSize(width: 30, height: 30))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - SchedulePointCell
|
||||
|
||||
class SchedulePointCell: UITableViewCell {
|
||||
|
||||
var disposeBag = DisposeBag()
|
||||
|
||||
func configure(item: SchedulePointItem, index: Int, total: Int, onDelete: @escaping () -> Void) {
|
||||
disposeBag = DisposeBag()
|
||||
indexLabel.text = "\(index + 1)"
|
||||
locationLabel.text = item.locationName.isEmpty ? "点击选择地点" : item.locationName
|
||||
|
||||
if let expectedTime = item.expectedTime {
|
||||
timeLabel.text = formatTime(expectedTime)
|
||||
}
|
||||
else {
|
||||
timeLabel.text = "请选择到达时间"
|
||||
}
|
||||
|
||||
// 左侧竖线:仅有一条时不显示虚线,首条顶部不画、末条底部不画
|
||||
topDashView.isHidden = total <= 1 || index == 0
|
||||
bottomDashView.isHidden = total <= 1 || index == total - 1
|
||||
|
||||
// 删除
|
||||
deleteBtn.rx.tap
|
||||
.subscribe(onNext: { onDelete() })
|
||||
.disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
private func formatTime(_ date: Date) -> String {
|
||||
let fmt = DateFormatter()
|
||||
fmt.dateFormat = "HH:mm"
|
||||
return fmt.string(from: date)
|
||||
}
|
||||
|
||||
// MARK: - Init
|
||||
|
||||
override init(style: CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
selectionStyle = .none
|
||||
backgroundColor = .clear
|
||||
setupViews()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
|
||||
|
||||
private func setupViews() {
|
||||
contentView.addSubview(topDashView)
|
||||
contentView.addSubview(pointIcon)
|
||||
contentView.addSubview(bottomDashView)
|
||||
|
||||
contentView.addSubview(cardView)
|
||||
cardView.addSubview(cardCornerView)
|
||||
cardCornerView.addSubview(indexLabel)
|
||||
cardCornerView.addSubview(locationLabel)
|
||||
cardCornerView.addSubview(timeLabel)
|
||||
cardCornerView.addSubview(remarkTF)
|
||||
cardCornerView.addSubview(deleteBtn)
|
||||
|
||||
topDashView.layoutChain
|
||||
.top().width(2)
|
||||
|
||||
pointIcon.layoutChain
|
||||
.centerY()
|
||||
.left(22)
|
||||
.width(18).height(18)
|
||||
|
||||
topDashView.layoutChain
|
||||
.centerX(pointIcon)
|
||||
.bottomToTopOfView(pointIcon, offset: -10)
|
||||
|
||||
bottomDashView.layoutChain
|
||||
.topToBottomOfView(pointIcon, offset: 10)
|
||||
.centerX(pointIcon)
|
||||
.width(2)
|
||||
.bottom()
|
||||
|
||||
// 右侧卡片
|
||||
cardView.layoutChain
|
||||
.top(15)
|
||||
.leftToRightOfView(pointIcon, offset: 20)
|
||||
.right(15)
|
||||
.height(92)
|
||||
.bottom(15)
|
||||
|
||||
cardCornerView.layoutChain.edges()
|
||||
|
||||
indexLabel.layoutChain
|
||||
.top().left()
|
||||
.width(30).height(20)
|
||||
|
||||
locationLabel.layoutChain
|
||||
.topToBottomOfView(indexLabel, offset: 10)
|
||||
.left(10)
|
||||
|
||||
timeLabel.layoutChain
|
||||
.centerY(locationLabel)
|
||||
.leftToRightOfView(locationLabel, offset: 38)
|
||||
|
||||
deleteBtn.layoutChain
|
||||
.bottom(15).right(15)
|
||||
.width(14).height(14)
|
||||
|
||||
remarkTF.layoutChain
|
||||
.topToBottomOfView(locationLabel, offset: 15)
|
||||
.leftToView(locationLabel)
|
||||
.rightToLeftOfView(deleteBtn, offset: -10)
|
||||
}
|
||||
|
||||
// MARK: - Views
|
||||
private let topDashView: UIView = {
|
||||
let v = UIView()
|
||||
v.backgroundColor = UIColor(hexStr: "#E0E0E0")
|
||||
v.isHidden = true
|
||||
return v
|
||||
}()
|
||||
|
||||
private let pointIcon: UIImageView = {
|
||||
let iv = UIImageView(image: UIImage(named: "Schedule/point"))
|
||||
iv.contentMode = .scaleAspectFit
|
||||
return iv
|
||||
}()
|
||||
|
||||
private let bottomDashView: UIView = {
|
||||
let v = UIView()
|
||||
v.backgroundColor = UIColor(hexStr: "#E0E0E0")
|
||||
v.isHidden = true
|
||||
return v
|
||||
}()
|
||||
|
||||
private let cardView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .clear
|
||||
view.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.05).cgColor
|
||||
view.layer.shadowOffset = CGSize(width: 0, height: 0)
|
||||
view.layer.shadowOpacity = 1
|
||||
view.layer.shadowRadius = 8
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var cardCornerView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .white
|
||||
view.cornerRadius = 10
|
||||
return view
|
||||
}()
|
||||
|
||||
private let indexLabel: UILabel = {
|
||||
let l = UILabel()
|
||||
l.backgroundColor = UIColor(hexStr: "#DCF4FF")
|
||||
l.textColor = UIColor(hexStr: "#176F9B")
|
||||
l.font = .systemFont(ofSize: 12, weight: .medium)
|
||||
l.textAlignment = .center
|
||||
return l
|
||||
}()
|
||||
|
||||
private let locationLabel: UILabel = {
|
||||
let l = UILabel()
|
||||
l.font = .systemFont(ofSize: 14, weight: .medium)
|
||||
l.textColor = UIColor(hexStr: "#333333")
|
||||
l.lineBreakMode = .byTruncatingTail
|
||||
return l
|
||||
}()
|
||||
|
||||
private let timeLabel: UILabel = {
|
||||
let l = UILabel()
|
||||
l.font = .systemFont(ofSize: 12, weight: .medium)
|
||||
l.textColor = UIColor(hexStr: "#333333")
|
||||
l.isUserInteractionEnabled = true
|
||||
return l
|
||||
}()
|
||||
|
||||
lazy var remarkTF: UITextField = {
|
||||
let tf = UITextField()
|
||||
tf.font = .systemFont(ofSize: 12)
|
||||
tf.placeholder = "在此添加备注..."
|
||||
tf.returnKeyType = .done
|
||||
return tf
|
||||
}()
|
||||
|
||||
private let deleteBtn: UIButton = {
|
||||
let btn = UIButton(type: .custom)
|
||||
btn.setImage(UIImage(named: "Schedule/delete"), for: .normal)
|
||||
btn.extendEdgeInsets = UIEdgeInsets(top: 10, left: 15, bottom: 15, right: 15)
|
||||
return btn
|
||||
}()
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
cardCornerView.layoutIfNeeded()
|
||||
indexLabel.setCornerRadius(corners: [.bottomRight], withCornerRadii: CGSize(width: 10, height: 10))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// CreateScheduleVC.swift
|
||||
// QuickLocation
|
||||
//
|
||||
// Created by 八条 on 2026/6/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class CreateScheduleVC: BaseViewController {
|
||||
|
||||
fileprivate var rootView: CreateScheduleView!
|
||||
|
||||
override func loadView() {
|
||||
rootView = CreateScheduleView(frame: UIScreen.main.bounds)
|
||||
view = rootView
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// MARK: - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
// Get the new view controller using segue.destination.
|
||||
// Pass the selected object to the new view controller.
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
//
|
||||
// CreateScheduleView.swift
|
||||
// QuickLocation
|
||||
//
|
||||
// Created by 八条 on 2026/6/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import RxSwift
|
||||
import RxCocoa
|
||||
#if !targetEnvironment(simulator)
|
||||
import AMapNaviKit
|
||||
#endif
|
||||
|
||||
class CreateScheduleView: UIView {
|
||||
|
||||
var disposeBag = DisposeBag()
|
||||
|
||||
let createSchedulePopView = CreateSchedulePopView()
|
||||
|
||||
// MARK: - PopView 拖拽
|
||||
private var popTopConstraint: NSLayoutConstraint?
|
||||
private var popUpLimit: CGFloat = 0
|
||||
private var popDownLimit: CGFloat = 0
|
||||
private var isLimitsSet = false
|
||||
private var panStartTop: CGFloat = 0
|
||||
private var isSubCanScroll = false
|
||||
|
||||
private func setupRx() {
|
||||
backBtn.rx.tap.subscribe(onNext: { _ in
|
||||
AppRouter.shared.popOrDismiss()
|
||||
}).disposed(by: disposeBag)
|
||||
|
||||
// tableView 到达顶部继续下拉时,改由 PopView 的 pan 手势接管
|
||||
createSchedulePopView.scrollView.rx.contentOffset
|
||||
.subscribe(onNext: { [weak self] offset in
|
||||
guard let self = self else { return }
|
||||
if self.isSubCanScroll {
|
||||
if offset.y <= 0 {
|
||||
self.isSubCanScroll = false
|
||||
self.createSchedulePopView.scrollView.setContentOffset(.zero, animated: false)
|
||||
}
|
||||
} else if offset.y != 0 {
|
||||
self.createSchedulePopView.scrollView.setContentOffset(.zero, animated: false)
|
||||
}
|
||||
})
|
||||
.disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
private func setupUI() {
|
||||
#if !targetEnvironment(simulator)
|
||||
addSubview(mapView)
|
||||
#endif
|
||||
addSubview(navBgView)
|
||||
addSubview(navBarView)
|
||||
navBarView.addSubview(backBtn)
|
||||
navBarView.addSubview(navTitleLabel)
|
||||
addSubview(createSchedulePopView)
|
||||
|
||||
navBgView.layoutChain
|
||||
.edges(excludingEdge: .bottom)
|
||||
.heightToWidth(160/375)
|
||||
|
||||
navBarView.layoutChain
|
||||
.edges(excludingEdge: .bottom)
|
||||
.height(kNaviHeight)
|
||||
|
||||
backBtn.layoutChain
|
||||
.centerY(navTitleLabel)
|
||||
.left(15)
|
||||
.width(24).height(24)
|
||||
|
||||
navTitleLabel.layoutChain
|
||||
.top(kStatusBarHeight + 12)
|
||||
.centerX()
|
||||
|
||||
#if !targetEnvironment(simulator)
|
||||
mapView.layoutChain
|
||||
.top()
|
||||
.edgesHorzontal()
|
||||
.bottom()
|
||||
#endif
|
||||
|
||||
// PopView: 初始底部 1/3,最大滑到 navBar 底部
|
||||
createSchedulePopView.layoutChain
|
||||
.edgesHorzontal()
|
||||
.bottom()
|
||||
.top(kScreenHeight / 3 * 2)
|
||||
|
||||
popTopConstraint = createSchedulePopView.jh_constraint(
|
||||
.top, toAttribute: .top, otherView: createSchedulePopView.superview, relation: .equal
|
||||
)
|
||||
|
||||
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePopPan(_:)))
|
||||
pan.delegate = self
|
||||
createSchedulePopView.addGestureRecognizer(pan)
|
||||
}
|
||||
|
||||
// MARK: - Pan Gesture
|
||||
|
||||
@objc private func handlePopPan(_ pan: UIPanGestureRecognizer) {
|
||||
guard isLimitsSet, let topConstraint = popTopConstraint else { return }
|
||||
|
||||
switch pan.state {
|
||||
case .began:
|
||||
layoutIfNeeded()
|
||||
panStartTop = createSchedulePopView.frame.minY
|
||||
|
||||
case .changed:
|
||||
let newTop = panStartTop + pan.translation(in: self).y
|
||||
|
||||
if isSubCanScroll {
|
||||
let tableViewOffset = self.createSchedulePopView.scrollView.contentOffset.y
|
||||
if tableViewOffset > 0, newTop >= popUpLimit {
|
||||
return
|
||||
}
|
||||
isSubCanScroll = false
|
||||
panStartTop = createSchedulePopView.frame.minY
|
||||
}
|
||||
|
||||
let clamped = max(popUpLimit, min(popDownLimit, newTop))
|
||||
topConstraint.constant = clamped
|
||||
|
||||
case .ended, .cancelled:
|
||||
let velocity = pan.velocity(in: self)
|
||||
let isNearUp = abs(createSchedulePopView.frame.minY - popUpLimit) < abs(createSchedulePopView.frame.minY - popDownLimit)
|
||||
let target: CGFloat
|
||||
if abs(velocity.y) > 200 {
|
||||
target = velocity.y < 0 ? popUpLimit : popDownLimit
|
||||
} else {
|
||||
target = isNearUp ? popUpLimit : popDownLimit
|
||||
}
|
||||
topConstraint.constant = target
|
||||
|
||||
UIView.animate(withDuration: 0.2, delay: 0,
|
||||
options: [.curveEaseInOut, .allowUserInteraction]) {
|
||||
self.layoutIfNeeded()
|
||||
} completion: { _ in
|
||||
let atTop = target == self.popUpLimit
|
||||
self.isSubCanScroll = atTop
|
||||
if !atTop {
|
||||
self.createSchedulePopView.scrollView.contentOffset.y = 0
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
if !isLimitsSet {
|
||||
isLimitsSet = true
|
||||
popDownLimit = kScreenHeight / 3 * 2
|
||||
popUpLimit = navBarView.frame.maxY
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Views
|
||||
lazy var navBgView: UIImageView = {
|
||||
let iv = UIImageView()
|
||||
iv.image = UIImage(named: "Common/navBar_bg_2")
|
||||
iv.contentMode = .scaleAspectFill
|
||||
return iv
|
||||
}()
|
||||
|
||||
lazy var navBarView: UIView = {
|
||||
let v = UIView()
|
||||
v.backgroundColor = .clear
|
||||
return v
|
||||
}()
|
||||
|
||||
lazy var backBtn: UIButton = {
|
||||
let btn = UIButton(type: .custom)
|
||||
btn.setImage(UIImage(named: "Common/back"), for: .normal)
|
||||
btn.extendEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 30)
|
||||
return btn
|
||||
}()
|
||||
|
||||
lazy var navTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .systemFont(ofSize: 18, weight: .medium)
|
||||
label.textColor = ThemeManager.shared.color.titleAuxColor
|
||||
label.text = "创建行程"
|
||||
return label
|
||||
}()
|
||||
|
||||
#if !targetEnvironment(simulator)
|
||||
lazy var mapView: MAMapView = {
|
||||
let mv = MAMapView()
|
||||
mv.zoomLevel = 14
|
||||
mv.showsUserLocation = false
|
||||
mv.showsCompass = false
|
||||
mv.userTrackingMode = .none
|
||||
return mv
|
||||
}()
|
||||
#endif
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
backgroundColor = .clear
|
||||
setupUI()
|
||||
setupRx()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - UIGestureRecognizerDelegate
|
||||
extension CreateScheduleView: UIGestureRecognizerDelegate {
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
|
||||
shouldRecognizeSimultaneouslyWith other: UIGestureRecognizer) -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
//
|
||||
// ScheduleModel.swift
|
||||
// QuickLocation
|
||||
//
|
||||
// Created by 八条 on 2026/6/23.
|
||||
//
|
||||
import ObjectMapper
|
||||
import RxDataSources
|
||||
|
||||
// 分页查询行程
|
||||
struct ScheduleListResponse: BaseModelProtocol, ListModelType {
|
||||
var pagination: PaginationModel?
|
||||
// 当前页索引
|
||||
var pageIndex = 1
|
||||
// 每页大小
|
||||
var pageSize = 20
|
||||
// 总条数
|
||||
var count = 0
|
||||
// 总页数
|
||||
var page_count = -99
|
||||
// 返回码
|
||||
var code: String?
|
||||
// 返回信息
|
||||
var message: String?
|
||||
// 行程列表
|
||||
var list: [ScheduleModel] = []
|
||||
|
||||
init() {}
|
||||
|
||||
init?(map: Map) {
|
||||
|
||||
}
|
||||
|
||||
mutating func mapping(map: Map) {
|
||||
code <- map["code"]
|
||||
message <- map["msg"]
|
||||
list <- map["data"]
|
||||
count = list.count
|
||||
pagination = PaginationModel(pageIndex: pageIndex,
|
||||
pageSize: pageSize,
|
||||
totalNum: count,
|
||||
totalPage: page_count)
|
||||
}
|
||||
}
|
||||
|
||||
struct ScheduleModel: Mappable, Equatable {
|
||||
var uuid: String = UUID().uuidString
|
||||
/// 行程id
|
||||
var id: String = ""
|
||||
/// 创建人id
|
||||
var creator_id: String = ""
|
||||
/// 行程创建者名称
|
||||
var nick_name: String = ""
|
||||
var head_pic: String = ""
|
||||
/// 头像
|
||||
var userIcon: UIImage {
|
||||
UIImage(named: "UserIcon/\(head_pic)") ?? UIImage()
|
||||
}
|
||||
/// 时间戳
|
||||
var timestamp: Int64 = 0
|
||||
/// 是否关注该行程
|
||||
var is_follow: Bool = false
|
||||
/// 是否是行程创建者
|
||||
var is_own: Bool = false
|
||||
/// 行程点
|
||||
var points: [SchedulePointModel] = []
|
||||
/// 圈子名
|
||||
// var group_name: String = ""
|
||||
/// 圈子key
|
||||
// var group_key: String = ""
|
||||
|
||||
init?(map: Map) {
|
||||
|
||||
}
|
||||
|
||||
mutating func mapping(map: Map) {
|
||||
id <- map["id"]
|
||||
creator_id <- map["creator_id"]
|
||||
nick_name <- map["nick_name"]
|
||||
head_pic <- map["head_pic"]
|
||||
timestamp <- map["timestamp"]
|
||||
is_follow <- map["is_follow"]
|
||||
is_own <- map["is_own"]
|
||||
points <- map["points"]
|
||||
// group_name <- map["groups.group_name"]
|
||||
// group_key <- map["groups.group_key"]
|
||||
}
|
||||
}
|
||||
|
||||
extension ScheduleModel: IdentifiableType {
|
||||
public typealias Identity = String
|
||||
|
||||
public var identity: String {
|
||||
return id
|
||||
}
|
||||
}
|
||||
|
||||
/// 行程点
|
||||
struct SchedulePointModel: Mappable, Equatable {
|
||||
/// 行程点id
|
||||
var id: String = ""
|
||||
|
||||
/// 节点类型:0起点 1中间点 2终点
|
||||
var type: Int = 0
|
||||
/// 期望到达的毫秒时间戳
|
||||
var expected_timestamp: Int64 = 0
|
||||
/// 经度
|
||||
var longitude: Double?
|
||||
/// 纬度
|
||||
var latitude: Double?
|
||||
/// 详细地址
|
||||
var province: String = ""
|
||||
var district: String = ""
|
||||
var country: String = ""
|
||||
var street: String = ""
|
||||
var city: String = ""
|
||||
var formatted_address: String = ""
|
||||
/// 备注
|
||||
var remark: String = ""
|
||||
/// 事件
|
||||
var eventText: String = ""
|
||||
/// 节点顺序
|
||||
var sequence: Int = 0
|
||||
|
||||
init?(map: Map) {
|
||||
|
||||
}
|
||||
|
||||
mutating func mapping(map: Map) {
|
||||
id <- map["id"]
|
||||
type <- map["type"]
|
||||
expected_timestamp <- map["expected_timestamp"]
|
||||
longitude <- map["location.longitude"]
|
||||
latitude <- map["location.latitude"]
|
||||
remark <- map["remark"]
|
||||
eventText <- map["events.text"]
|
||||
province <- map["address.province"]
|
||||
district <- map["address.district"]
|
||||
country <- map["address.country"]
|
||||
street <- map["address.street"]
|
||||
city <- map["address.city"]
|
||||
formatted_address <- map["address.formatted_address"]
|
||||
sequence <- map["sequence"]
|
||||
}
|
||||
}
|
||||
|
||||
extension SchedulePointModel: IdentifiableType {
|
||||
public typealias Identity = String
|
||||
|
||||
public var identity: String {
|
||||
return id
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// ScheduleVC.swift
|
||||
// QuickLocation
|
||||
//
|
||||
// Created by 八条 on 2026/6/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import RxSwift
|
||||
import RxCocoa
|
||||
import RxDataSources
|
||||
import MJRefresh
|
||||
|
||||
class ScheduleVC: BaseViewController {
|
||||
|
||||
fileprivate var rootView: ScheduleView!
|
||||
|
||||
override func loadView() {
|
||||
rootView = ScheduleView(frame: UIScreen.main.bounds)
|
||||
view = rootView
|
||||
}
|
||||
|
||||
private var viewModel = ScheduleViewModel()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
setupTableViewHeaderFooter()
|
||||
bindViewModel()
|
||||
reactiveAction()
|
||||
|
||||
requestData()
|
||||
requestFollowList()
|
||||
}
|
||||
|
||||
private func bindViewModel() {
|
||||
viewModel.output.sectionedItems
|
||||
.bind(to: rootView.collectionView.rx.items(dataSource: dataSource))
|
||||
.disposed(by: disposeBag)
|
||||
|
||||
viewModel.output.scheduleSectionedItems
|
||||
.bind(to: rootView.tableView.rx.items(dataSource: tableViewDataSource))
|
||||
.disposed(by: disposeBag)
|
||||
|
||||
viewModel.output.refreshResult.subscribe(onNext: { [weak self] (status, isEmpty) in
|
||||
guard let self = self else { return }
|
||||
self.dl.dismiss()
|
||||
self.rootView.tableView.refresh(status: status, isEmpty: isEmpty)
|
||||
}).disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
private func reactiveAction() {
|
||||
|
||||
}
|
||||
|
||||
private func setupTableViewHeaderFooter() {
|
||||
// 设置刷新header/footer
|
||||
let header = MJRefreshNormalHeader(refreshingBlock: { [weak self] in
|
||||
self?.viewModel.refresh()
|
||||
})
|
||||
header.addFeedbackGenerator()
|
||||
header.stateLabel?.isHidden = true
|
||||
rootView.tableView.mj_header = header
|
||||
|
||||
let footer = MJRefreshAutoNormalFooter(refreshingBlock: viewModel.loadMore)
|
||||
footer.isHidden = true
|
||||
rootView.tableView.mj_footer = footer
|
||||
}
|
||||
|
||||
// MARK: - API
|
||||
private func requestFollowList() {
|
||||
dl.showLoading()
|
||||
UserService.followList().subscribe(onNext: { response in
|
||||
self.dl.dismiss()
|
||||
self.viewModel.loadViewedData(response.list)
|
||||
}, onError: { _ in }).disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
// MARK: - API 行程列表
|
||||
private func requestData() {
|
||||
dl.showLoading()
|
||||
viewModel.refresh()
|
||||
}
|
||||
|
||||
// MARK: - dataSource
|
||||
private lazy var dataSource: RxCollectionViewSectionedReloadDataSource<ViewedListSectionModel> = {
|
||||
RxCollectionViewSectionedReloadDataSource<ViewedListSectionModel> { datasource, collectionView, indexPath, model in
|
||||
let cell: ViewedCell = collectionView.dequeueReusableCell(for: indexPath)
|
||||
cell.configure(model)
|
||||
return cell
|
||||
}
|
||||
}()
|
||||
|
||||
// MARK: - UITableViewDataSource
|
||||
lazy private var tableViewDataSource: RxTableViewSectionedReloadDataSource<ScheduleListSectionModel> = {
|
||||
return RxTableViewSectionedReloadDataSource<ScheduleListSectionModel>(
|
||||
configureCell: { (_, tableView, indexPath, model) in
|
||||
let cell: ScheduleListPopCell = tableView.dequeueReusableCell(for: indexPath)
|
||||
cell.configure(model)
|
||||
return cell
|
||||
}
|
||||
)
|
||||
}()
|
||||
}
|
||||
|
|
@ -0,0 +1,422 @@
|
|||
//
|
||||
// ScheduleView.swift
|
||||
// QuickLocation
|
||||
//
|
||||
// Created by 八条 on 2026/6/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import RxSwift
|
||||
import RxCocoa
|
||||
|
||||
class ScheduleView: UIView {
|
||||
|
||||
var disposeBag = DisposeBag()
|
||||
|
||||
private func setupRx() {
|
||||
createBtn.rx.tap.subscribe(onNext: { _ in
|
||||
AppRouter.push(Route.createSchedule)
|
||||
}).disposed(by: disposeBag)
|
||||
}
|
||||
|
||||
private func setupUI() {
|
||||
addSubview(navBgView)
|
||||
addSubview(navBarView)
|
||||
navBarView.addSubview(navTitleLabel)
|
||||
addSubview(headerView)
|
||||
addSubview(travelRouteView)
|
||||
addSubview(tableView)
|
||||
|
||||
addSubview(createBtn)
|
||||
|
||||
navBgView.layoutChain
|
||||
.edges(excludingEdge: .bottom)
|
||||
.height(kNaviHeight)
|
||||
|
||||
navBarView.layoutChain
|
||||
.edges(excludingEdge: .bottom)
|
||||
.height(kNaviHeight)
|
||||
|
||||
navTitleLabel.layoutChain
|
||||
.top(kStatusBarHeight + 12)
|
||||
.centerX()
|
||||
|
||||
headerView.layoutChain
|
||||
.topToBottomOfView(navBarView)
|
||||
.edgesHorzontal()
|
||||
// .height(147)
|
||||
|
||||
travelRouteView.layoutChain
|
||||
.topToBottomOfView(headerView)
|
||||
.edgesHorzontal()
|
||||
|
||||
tableView.layoutChain
|
||||
.topToBottomOfView(travelRouteView)
|
||||
.edges(excludingEdge: .top)
|
||||
|
||||
createBtn.layoutChain
|
||||
.bottom(kSafeBottomMargin + 102)
|
||||
.right(10)
|
||||
.width(60)
|
||||
.heightToWidth(1)
|
||||
}
|
||||
|
||||
lazy var navBgView: UIImageView = {
|
||||
let iv = UIImageView()
|
||||
iv.image = UIImage(named: "Common/navBar_bg_1")
|
||||
iv.contentMode = .scaleAspectFill
|
||||
return iv
|
||||
}()
|
||||
|
||||
lazy var navBarView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .clear
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var navTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.text = "行程"
|
||||
label.font = .systemFont(ofSize: 18, weight: .medium)
|
||||
label.textColor = ThemeManager.shared.color.titleAuxColor
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
/// 谁看过我
|
||||
lazy var headerView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .clear
|
||||
|
||||
let titleLab = UILabel()
|
||||
titleLab.text = "谁看过我"
|
||||
titleLab.font = .systemFont(ofSize: 16, weight: .medium)
|
||||
titleLab.textColor = ThemeManager.shared.color.titleAuxColor
|
||||
view.addSubview(titleLab)
|
||||
titleLab.layoutChain
|
||||
.top(15)
|
||||
|
||||
let dotView = UIView()
|
||||
dotView.backgroundColor = UIColor(hexStr: "#16B3FF")
|
||||
dotView.cornerRadius = 2
|
||||
view.addSubview(dotView)
|
||||
dotView.layoutChain
|
||||
.left(15)
|
||||
.centerY(titleLab)
|
||||
.width(4)
|
||||
.height(11)
|
||||
|
||||
titleLab.layoutChain.leftToRightOfView(dotView, offset: 5)
|
||||
|
||||
let historyBtn = UIButton()
|
||||
historyBtn.setTitle("历史行程", for: .normal)
|
||||
historyBtn.setTitleColor(ThemeManager.shared.color.titleAuxColor, for: .normal)
|
||||
historyBtn.titleLabel?.font = .systemFont(ofSize: 12, weight: .medium)
|
||||
view.addSubview(historyBtn)
|
||||
historyBtn.layoutChain
|
||||
.right(15)
|
||||
.centerY(titleLab)
|
||||
historyBtn.sizeToFit()
|
||||
|
||||
view.addSubview(collectionView)
|
||||
collectionView.layoutChain
|
||||
.topToBottomOfView(titleLab, offset: 15)
|
||||
.edgesHorzontal()
|
||||
.height(80)
|
||||
.bottom(15)
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var collectionView: UICollectionView = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.scrollDirection = .horizontal
|
||||
layout.itemSize = CGSize(width: 80, height: 80)
|
||||
layout.minimumLineSpacing = 15
|
||||
layout.sectionInset = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)
|
||||
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
|
||||
cv.backgroundColor = .clear
|
||||
cv.showsHorizontalScrollIndicator = false
|
||||
cv.register(ViewedCell.self)
|
||||
return cv
|
||||
}()
|
||||
|
||||
/// 行程路线
|
||||
lazy var travelRouteView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .clear
|
||||
|
||||
let titleLab = UILabel()
|
||||
titleLab.text = "行程路线"
|
||||
titleLab.font = .systemFont(ofSize: 16, weight: .medium)
|
||||
titleLab.textColor = ThemeManager.shared.color.titleAuxColor
|
||||
view.addSubview(titleLab)
|
||||
titleLab.layoutChain
|
||||
.top(15)
|
||||
.edgesVertical(5)
|
||||
|
||||
let dotView = UIView()
|
||||
dotView.backgroundColor = UIColor(hexStr: "#16B3FF")
|
||||
dotView.cornerRadius = 2
|
||||
view.addSubview(dotView)
|
||||
dotView.layoutChain
|
||||
.left(15)
|
||||
.centerY(titleLab)
|
||||
.width(4)
|
||||
.height(11)
|
||||
|
||||
titleLab.layoutChain.leftToRightOfView(dotView, offset: 5)
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var tableView: UITableView = {
|
||||
let tableView = UITableView(frame: .zero, style: .plain)
|
||||
tableView.backgroundColor = .clear
|
||||
tableView.separatorStyle = .none
|
||||
tableView.estimatedRowHeight = 80
|
||||
tableView.register(ScheduleListPopCell.self)
|
||||
return tableView
|
||||
}()
|
||||
|
||||
lazy var createBtn: UIButton = {
|
||||
let btn = UIButton()
|
||||
btn.setImage(UIImage(named: "Schedule/create"), for: .normal)
|
||||
return btn
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: .zero)
|
||||
backgroundColor = .white
|
||||
setupUI()
|
||||
setupRx()
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ViewedCell
|
||||
final class ViewedCell: UICollectionViewCell {
|
||||
|
||||
func configure(_ model: ViewedModel) {
|
||||
iconView.image = model.userIcon
|
||||
|
||||
// 会员权益
|
||||
blurView.isHidden = AppContextManager.shared.vip > 1
|
||||
lockView.isHidden = AppContextManager.shared.vip > 1
|
||||
viewedCountLab.text = "看了\(model.count)次"
|
||||
}
|
||||
|
||||
lazy var iconView: UIImageView = {
|
||||
let iv = UIImageView()
|
||||
iv.contentMode = .scaleAspectFill
|
||||
iv.cornerRadius = 40
|
||||
iv.clipsToBounds = true
|
||||
iv.backgroundColor = .clear
|
||||
iv.addSubview(blurView)
|
||||
blurView.layoutChain.edges()
|
||||
|
||||
return iv
|
||||
}()
|
||||
|
||||
lazy var blurView: UIVisualEffectView = {
|
||||
let blurEffect = UIBlurEffect(style: .systemUltraThinMaterialLight)
|
||||
let view = UIVisualEffectView(effect: blurEffect)
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var lockView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .clear
|
||||
|
||||
let lockIcon = UIImageView(image: UIImage(named: "Common/lock_white"))
|
||||
lockIcon.contentMode = .scaleAspectFill
|
||||
view.addSubview(lockIcon)
|
||||
lockIcon.layoutChain
|
||||
.top(17)
|
||||
.centerX()
|
||||
|
||||
view.addSubview(viewedCountLab)
|
||||
viewedCountLab.layoutChain
|
||||
.bottom(17)
|
||||
.edgesHorzontal()
|
||||
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var viewedCountLab: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .systemFont(ofSize: 12, weight: .medium)
|
||||
label.textColor = .white
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
contentView.addSubview(iconView)
|
||||
contentView.addSubview(lockView)
|
||||
|
||||
iconView.layoutChain
|
||||
.edges()
|
||||
|
||||
lockView.layoutChain
|
||||
.edges()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - ScheduleListPopCell
|
||||
class ScheduleListPopCell: UITableViewCell {
|
||||
|
||||
func configure(_ model: ScheduleModel) {
|
||||
nameLab.text = model.nick_name + " 的行程路线"
|
||||
monthLab.text = getDateInterval2String(date: "\(model.timestamp/1000)", dateFormat: "MM月")
|
||||
|
||||
if model.is_own {
|
||||
editBtn.isHidden = false
|
||||
followBtn.isHidden = true
|
||||
}
|
||||
else {
|
||||
editBtn.isHidden = true
|
||||
followBtn.isHidden = model.is_follow ? true : false
|
||||
}
|
||||
|
||||
guard let pointModel = model.points.last else { return }
|
||||
dateLab.text = getDateInterval2String(date: "\(pointModel.expected_timestamp/1000)", dateFormat: "MM.dd")
|
||||
}
|
||||
|
||||
override init(style: CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
selectionStyle = .none
|
||||
backgroundColor = .clear
|
||||
setupSubviews()
|
||||
}
|
||||
|
||||
private func setupSubviews() {
|
||||
contentView.addSubview(bgView)
|
||||
bgView.addSubview(cornerView)
|
||||
cornerView.addSubview(nameLab)
|
||||
cornerView.addSubview(monthLab)
|
||||
cornerView.addSubview(dateLab)
|
||||
cornerView.addSubview(editBtn)
|
||||
cornerView.addSubview(followBtn)
|
||||
|
||||
bgView.layoutChain
|
||||
.edgesVertical(15)
|
||||
.edgesHorzontal(15)
|
||||
.height(80)
|
||||
|
||||
cornerView.layoutChain.edges()
|
||||
|
||||
monthLab.layoutChain
|
||||
.bottomToCenterYOfView(cornerView)
|
||||
.left(11)
|
||||
|
||||
dateLab.layoutChain
|
||||
.topToBottomOfView(monthLab)
|
||||
.leftToView(monthLab)
|
||||
|
||||
nameLab.layoutChain
|
||||
.centerY()
|
||||
.leftToRightOfView(monthLab, offset: 15)
|
||||
|
||||
editBtn.layoutChain
|
||||
.right(10)
|
||||
.centerY()
|
||||
.width(56)
|
||||
.height(28)
|
||||
|
||||
followBtn.layoutChain
|
||||
.topToView(editBtn)
|
||||
.rightToView(editBtn)
|
||||
.width(56)
|
||||
.height(28)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
// Initialization code
|
||||
}
|
||||
|
||||
override func setSelected(_ selected: Bool, animated: Bool) {
|
||||
super.setSelected(selected, animated: animated)
|
||||
|
||||
// Configure the view for the selected state
|
||||
}
|
||||
|
||||
lazy var bgView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .clear
|
||||
view.layer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.05).cgColor
|
||||
view.layer.shadowOffset = CGSize(width: 0, height: 0)
|
||||
view.layer.shadowOpacity = 1
|
||||
view.layer.shadowRadius = 8
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var cornerView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .white
|
||||
view.cornerRadius = 10
|
||||
return view
|
||||
}()
|
||||
|
||||
lazy var monthLab: UILabel = {
|
||||
let label = UILabel()
|
||||
label.textColor = ThemeManager.shared.color.titleAuxColor
|
||||
label.font = .systemFont(ofSize: 14, weight: .medium)
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var dateLab: UILabel = {
|
||||
let label = UILabel()
|
||||
label.textColor = ThemeManager.shared.color.subTitleColor
|
||||
label.font = .systemFont(ofSize: 12, weight: .regular)
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var nameLab: UILabel = {
|
||||
let label = UILabel()
|
||||
label.textColor = ThemeManager.shared.color.titleAuxColor
|
||||
label.font = .systemFont(ofSize: 14, weight: .medium)
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var editBtn: UIButton = {
|
||||
let btn = UIButton()
|
||||
btn.isHidden = true
|
||||
btn.setTitle("编辑", for: .normal)
|
||||
btn.titleLabel?.font = .systemFont(ofSize: 12, weight: .medium)
|
||||
btn.setTitleColor(UIColor(hexStr: "#0F2846"), for: .normal)
|
||||
btn.backgroundColor = UIColor(hexStr: "#EEFAFF")
|
||||
btn.borderWidth = 0.5
|
||||
btn.borderColor = UIColor(hexStr: "#16B3FF")
|
||||
btn.cornerRadius = 14
|
||||
return btn
|
||||
}()
|
||||
|
||||
lazy var followBtn: UIButton = {
|
||||
let btn = UIButton()
|
||||
btn.isHidden = true
|
||||
btn.setTitle("关注", for: .normal)
|
||||
btn.titleLabel?.font = .systemFont(ofSize: 12, weight: .medium)
|
||||
btn.setTitleColor(UIColor(hexStr: "#16B3FF"), for: .normal)
|
||||
btn.backgroundColor = .white
|
||||
btn.borderWidth = 0.5
|
||||
btn.borderColor = UIColor(hexStr: "#16B3FF")
|
||||
btn.cornerRadius = 14
|
||||
return btn
|
||||
}()
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// ScheduleViewModel.swift
|
||||
// QuickLocation
|
||||
//
|
||||
// Created by 八条 on 2026/6/23.
|
||||
//
|
||||
|
||||
import RxSwift
|
||||
import RxCocoa
|
||||
import RxDataSources
|
||||
import MJRefresh
|
||||
|
||||
typealias ViewedListSectionModel = SectionModel<String, ViewedModel>
|
||||
typealias ScheduleListSectionModel = AnimatableSectionModel<String, ScheduleModel>
|
||||
|
||||
class ScheduleViewModel: ViewModelType {
|
||||
|
||||
struct Input {}
|
||||
|
||||
struct Output {
|
||||
var sectionedItems: Observable<[ViewedListSectionModel]>
|
||||
var scheduleSectionedItems: Observable<[ScheduleListSectionModel]>
|
||||
var refreshResult: Observable<RefreshResult>
|
||||
var pagination: Observable<PaginationModel?>
|
||||
var error: Observable<Error>
|
||||
}
|
||||
|
||||
let input: Input
|
||||
let output: Output
|
||||
|
||||
private var listService: ListService<ScheduleListResponse>
|
||||
private let sectionedItems = PublishSubject<[ViewedListSectionModel]>()
|
||||
private let scheduleSectionedItems = PublishSubject<[ScheduleListSectionModel]>()
|
||||
|
||||
var refresh: MJRefreshComponentAction {
|
||||
return {
|
||||
self.listService.request.onNext(.refresh)
|
||||
}
|
||||
}
|
||||
var loadMore: MJRefreshComponentAction {
|
||||
return {
|
||||
self.listService.request.onNext(.more)
|
||||
}
|
||||
}
|
||||
|
||||
func loadViewedData(_ list: [ViewedModel]) {
|
||||
sectionedItems.onNext(list.mapSection())
|
||||
}
|
||||
|
||||
// MARK: - init
|
||||
init() {
|
||||
listService = ItineraryService.query()
|
||||
|
||||
input = Input()
|
||||
output = Output(
|
||||
sectionedItems: sectionedItems.asObservable(),
|
||||
scheduleSectionedItems: listService.animatableSectionedItems,
|
||||
refreshResult: listService.refreshResult,
|
||||
pagination: listService.pagination,
|
||||
error: listService.error
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// ViewedModel.swift
|
||||
// QuickLocation
|
||||
//
|
||||
// Created by 八条 on 2026/6/23.
|
||||
//
|
||||
|
||||
import ObjectMapper
|
||||
import RxDataSources
|
||||
|
||||
/// 看过我列表
|
||||
struct ViewedListResponse: BaseModelProtocol {
|
||||
// 状态码
|
||||
var code: String?
|
||||
// 消息
|
||||
var message: String?
|
||||
//
|
||||
var list: [ViewedModel] = []
|
||||
|
||||
init?(map: Map) {}
|
||||
|
||||
mutating func mapping(map: Map) {
|
||||
code <- map["code"]
|
||||
message <- map["msg"]
|
||||
list <- map["data"]
|
||||
}
|
||||
}
|
||||
|
||||
struct ViewedModel: Mappable, Equatable {
|
||||
var uuid: String = UUID().uuidString
|
||||
///
|
||||
var user_id: String = ""
|
||||
var nick_name: String = ""
|
||||
var head_pic: String = ""
|
||||
/// 头像
|
||||
var userIcon: UIImage {
|
||||
UIImage(named: "UserIcon/\(head_pic)") ?? UIImage()
|
||||
}
|
||||
/// 查看次数
|
||||
var count: Int = 0
|
||||
|
||||
init?(map: Map) {
|
||||
|
||||
}
|
||||
|
||||
mutating func mapping(map: Map) {
|
||||
user_id <- map["user_id"]
|
||||
nick_name <- map["nick_name"]
|
||||
head_pic <- map["head_pic"]
|
||||
count <- map["count"]
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewedModel: IdentifiableType {
|
||||
public typealias Identity = String
|
||||
|
||||
public var identity: String {
|
||||
return user_id
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// ItineraryService.swift
|
||||
// QuickLocation
|
||||
//
|
||||
// Created by 八条 on 2026/6/23.
|
||||
//
|
||||
|
||||
import RxSwift
|
||||
import Moya
|
||||
|
||||
struct ItineraryService {
|
||||
static let disposeBag = DisposeBag()
|
||||
|
||||
/// 查询行程
|
||||
/// - Parameters:
|
||||
/// - follow: 只查看关注的行程
|
||||
/// - own: 只查看自己创建的行程
|
||||
/// - history: true查看历史行程,默认查看今天之后的行程
|
||||
/// - group_key: 过滤圈子查询
|
||||
static func query(follow: Bool=false,
|
||||
own: Bool=false,
|
||||
history: Bool=false,
|
||||
group_key: String="") -> ListService<ScheduleListResponse> {
|
||||
ListService(newPaging: true) {
|
||||
ItineraryAPI.query(follow: follow,
|
||||
own: own,
|
||||
history: history,
|
||||
group_key: group_key,
|
||||
page: $0).multiTarget
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -33,4 +33,12 @@ struct SystemService {
|
|||
.map(ResponseModel.self)
|
||||
.asObservable()
|
||||
}
|
||||
|
||||
/// SOS
|
||||
static func sos(enable: Bool) -> Observable<ResponseModel> {
|
||||
let api = SystemAPI.sos(enable: enable).multiTarget
|
||||
return APIProvider.request(token: api)
|
||||
.map(ResponseModel.self)
|
||||
.asObservable()
|
||||
}
|
||||
}
|
||||
|
|
|
|||