Files
xj-ios/XinjiangProject/XinjiangProject/Project/HomeV2/View/XJHomeWatchDataView.m
T
NSArray 2c2f307247 feat: HomeV2 手表数据区高度动态调整 & 绑定弹窗姓名工号布局优化
- XJHomeWatchDataView 新增 heightChangeBlock,无数据/未登录高度 104,有数据高度 200
- XJHomePageV2HeardView 初始高度改为 104,绑定回调动态更新约束带动画
- BindWatchPopView 姓名工号同行布局,工号固定右侧优先显示,姓名占满剩余空间
2026-03-19 16:50:19 +08:00

723 lines
27 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// XJHomeWatchDataView.m
// XinjiangProject
//
// Created by Apple on 2026/3/2.
//
#import "XJHomeWatchDataView.h"
#import "XJHomeWatchCollectionViewCell.h"
#import <Masonry/Masonry.h>
// ── 布局常量 ──────────────────────────────────────────────
static CGFloat const kHeaderHeight = 92.0; // 头部保留高度(外部自行填充)
static CGFloat const kTabScrollH = 52.0; // Tab ScrollView 高度
static CGFloat const kButtonH = 30.0; // 按钮高度
static CGFloat const kButtonPadX = 10.0; // 按钮左右内边距
static CGFloat const kButtonGap = 10.0; // 按钮间距
// ── Private ───────────────────────────────────────────────
@interface XJHomeWatchDataView ()<UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
@property (nonatomic, strong) YYLabel *watchNumberLabel; //
//@property (nonatomic, strong) UIScrollView *tabScrollView;
@property (nonatomic, strong) UIView *tabContentView;
@property (nonatomic, strong) NSMutableArray<UIButton *> *tabButtons;
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) UILabel *emptyLabel; // 无数据占位
@property (nonatomic, strong) UIView *emptyView; // 空状态占位整体容器
@property (nonatomic, strong) UIView *devView; // 紧急开发中占位
@property (nonatomic, assign) NSInteger selectedIndex; // 当前选中的 Tab 下标
@property (nonatomic, assign) NSInteger carouselPage; // collectionView 当前轮播页码(与 Tab 无关)
@property (nonatomic, strong) NSTimer *autoScrollTimer; // 轮播定时器
@property (nonatomic, strong) UIView *
timeView;
@property (nonatomic, strong) UIButton *
preBtn;
@property (nonatomic, strong) UIButton *
nextBtn;
@property (nonatomic, strong) UILabel *
weekLabel;
@property (nonatomic, strong) NSDate * currentDayDate; // 当前选中的日
@end
// ─────────────────────────────────────────────────────────
@implementation XJHomeWatchDataView
#pragma mark - Init
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
self.backgroundColor = KWhiteColor;
self.layer.cornerRadius = 12;
self.layer.masksToBounds = true;
if (self) [self p_setupUI];
return self;
}
#pragma mark - UI Setup
- (void)p_setupUI {
_selectedIndex = 0;
_tabButtons = [NSMutableArray array];
self.currentDayDate = [NSDate date];
UIImageView * heaedImg = [[UIImageView alloc] init];
heaedImg.image = [UIImage imageNamed:@"heaedTitleBackImg"];
heaedImg.userInteractionEnabled = true;
[self addSubview:heaedImg];
[heaedImg mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.top.mas_offset(0);
make.height.mas_offset(40);
}];
UILabel * todayLabel = [[UILabel alloc] init];
todayLabel.text = @"健康监测";
todayLabel.textAlignment = NSTextAlignmentLeft;
todayLabel.textColor = CFontColor1;
todayLabel.font = BOLDSYSTEMFONT(16);
[heaedImg addSubview:todayLabel];
[todayLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_offset(13);
make.top.bottom.mas_offset(0);
}];
UIButton * moreBtn = [[UIButton alloc] init];
[moreBtn setImage:[UIImage imageNamed:@"wacthRightAccow"] forState:UIControlStateNormal];
[moreBtn addTarget:self action:@selector(moreClick) forControlEvents:UIControlEventTouchUpInside];
[heaedImg addSubview:moreBtn];
[moreBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_offset(-8);
make.centerY.mas_equalTo(heaedImg);
make.width.height.mas_offset(30);
}];
// YYLabel * morelabel = [[YYLabel alloc] init];
// morelabel.text = @">";
// morelabel.textAlignment = NSTextAlignmentRight;
// morelabel.textColor = UIColorHex(#999999);
// morelabel.font = SYSTEMFONT(14);
// MJWeakSelf
// [morelabel setTextTapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
// if (self.watchMoreBlock) {
// self.watchMoreBlock();
// }
// }];
// [heaedImg addSubview:morelabel];
//
// [morelabel mas_makeConstraints:^(MASConstraintMaker *make) {
// make.right.mas_offset(-13);
// make.centerY.mas_equalTo(heaedImg);
// make.width.height.mas_offset(20);
// }];
//
self.watchNumberLabel = [[YYLabel alloc] init];
self.watchNumberLabel.text = @"";
self.watchNumberLabel.textAlignment = NSTextAlignmentLeft;
self.watchNumberLabel.textColor = UIColorHex(#14BEBE);
self.watchNumberLabel.font = MEDIUMFONT(13);
[heaedImg addSubview:self.watchNumberLabel];
[self.watchNumberLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(moreBtn.mas_left);
make.top.mas_offset(0);
make.height.mas_offset(40);
}];
MJWeakSelf
[self.watchNumberLabel setTextTapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
if (weakSelf.bindDeviceBlock) {
weakSelf.bindDeviceBlock(weakSelf.watchModel.watchNo);
}
}];
//日期切换
// self.timeView = [[UIView alloc] init];
// self.timeView.backgroundColor = KWhiteColor;
// [self addSubview:self.timeView];
//
// [self.timeView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.left.right.mas_offset(0);
// make.top.mas_equalTo(heaedImg.mas_bottom);
// make.height.mas_offset(52);
// }];
//
// UIButton *preBtn = [[UIButton alloc] init];
// [preBtn setTitle:@"上一天" forState:UIControlStateNormal];
// [preBtn setImage:[UIImage imageNamed:@"blackLeftAccow"] forState:UIControlStateNormal];
// [preBtn setTitleColor:UIColorHex(#333333) forState:UIControlStateNormal];
// preBtn.titleLabel.font = MEDIUMFONT(12);
// preBtn.titleEdgeInsets = UIEdgeInsetsMake(0, -8, 0, 8); // 左边多 4px 间距
// self.preBtn = preBtn;
// [preBtn addTarget:self action:@selector(previousWeekAction) forControlEvents:UIControlEventTouchUpInside];
// [self.timeView addSubview:preBtn];
//
// [preBtn mas_makeConstraints:^(MASConstraintMaker *make) {
// make.left.mas_equalTo(@46);
// make.width.mas_offset(60); // 注意宽度要能容纳文字+图片
// make.centerY.mas_equalTo(self.timeView);
// }];
// preBtn.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
//
//
// UIButton *rightBtn = [[UIButton alloc] init];
// [rightBtn setImage:[UIImage imageNamed:@"blackRightAccow"] forState:UIControlStateNormal];
// [rightBtn setTitle:@"下一天" forState:UIControlStateNormal];
// [rightBtn setTitleColor:UIColorHex(#333333) forState:UIControlStateNormal];
// rightBtn.titleLabel.font = MEDIUMFONT(12);
// rightBtn.titleEdgeInsets = UIEdgeInsetsMake(0, 8, 0, 0); // 左边多 4px 间距
// self.nextBtn = rightBtn;
// [rightBtn addTarget:self action:@selector(nextWeekAction) forControlEvents:UIControlEventTouchUpInside];
// [self.timeView addSubview:rightBtn];
// [rightBtn mas_makeConstraints:^(MASConstraintMaker *make) {
// make.right.mas_equalTo(@-46);
// make.width.mas_offset(60); // 记得宽度要能容下文字+图片
// make.centerY.mas_equalTo(self.timeView);
// }];
//
// self.weekLabel = [[UILabel alloc] init];
// self.weekLabel.textAlignment = NSTextAlignmentCenter;
// self.weekLabel.textColor = UIColorHex(#333333);
// self.weekLabel.font = MEDIUMFONT(12);
// [self.timeView addSubview: self.weekLabel];
//
// [self.weekLabel mas_makeConstraints:^(MASConstraintMaker *make) {
// make.right.mas_equalTo(rightBtn.mas_left);
// make.left.mas_equalTo(preBtn.mas_right);
// make.centerY.mas_equalTo(self.timeView);
// make.top.mas_offset(0);
// }];
//
// [self updateWeekLabelWithType];
//
// ── Tab ScrollView ───────────────────────────────────
// _tabScrollView = [[UIScrollView alloc] init];
// _tabScrollView.showsHorizontalScrollIndicator = NO;
// _tabScrollView.showsVerticalScrollIndicator = NO;
// [self addSubview:_tabScrollView];
//
// [_tabScrollView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.top.equalTo(heaedImg.mas_bottom);
// make.left.right.equalTo(self);
// make.height.mas_equalTo(kTabScrollH);
// }];
// scrollView 内的容器 viewMasonry 驱动 contentSize
// _tabContentView = [[UIView alloc] init];
// [_tabScrollView addSubview:_tabContentView];
//
// [_tabContentView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.edges.equalTo(_tabScrollView); // 四边贴 scrollView
// make.height.equalTo(_tabScrollView); // 固定高度 = scrollView,只横向滚动
// }];
// ── 底部 CollectionView ──────────────────────────────
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
layout.minimumLineSpacing = 0;
layout.minimumInteritemSpacing = 0;
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero
collectionViewLayout:layout];
_collectionView.backgroundColor = UIColor.clearColor;
_collectionView.showsHorizontalScrollIndicator = NO;
_collectionView.pagingEnabled = YES;
_collectionView.delegate = self;
_collectionView.dataSource = self;
[_collectionView registerClass:[XJHomeWatchCollectionViewCell class]
forCellWithReuseIdentifier:NSStringFromClass([XJHomeWatchCollectionViewCell class])];
[self addSubview:_collectionView];
[_collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(@40);
make.left.right.bottom.equalTo(self);
}];
// ── 未登录占位 Label ─────────────────────────────────────────
_emptyLabel = [[UILabel alloc] init];
_emptyLabel.text = @" 暂未登录 ";
_emptyLabel.textAlignment = NSTextAlignmentCenter;
_emptyLabel.textColor = [UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1.0];
_emptyLabel.font = [UIFont systemFontOfSize:15.0];
_emptyLabel.hidden = YES;
[self.collectionView addSubview:_emptyLabel];
[_emptyLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.collectionView);
}];
// ── 无设备占位 View(已登录但未绑定设备时显示)────────────────
_emptyView = [[UIView alloc] init];
_emptyView.backgroundColor = KWhiteColor;
_emptyView.hidden = YES;
[self addSubview:_emptyView];
[_emptyView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(@40);
make.left.right.bottom.equalTo(self);
}];
// // 空状态图标,宽高 59,居中,距 Tab 切换 View 底部 16
// UIImageView *emptyImageView = [[UIImageView alloc] init];
// emptyImageView.image = [UIImage imageNamed:@"ic_watch_empty"];
// emptyImageView.contentMode = UIViewContentModeScaleAspectFit;
// [_emptyView addSubview:emptyImageView];
//
// [emptyImageView mas_makeConstraints:^(MASConstraintMaker *make) {
// make.top.mas_offset(16);
// make.centerX.equalTo(_emptyView);
// make.width.height.mas_offset(59);
// }];
//
// // 提示文字:~ 暂无数据 ~,字号 11 regular,颜色 #B6B6B6
// UILabel *emptyHintLabel = [[UILabel alloc] init];
// emptyHintLabel.text = @"~ 暂无数据 ~";
// emptyHintLabel.textAlignment = NSTextAlignmentCenter;
// emptyHintLabel.textColor = UIColorHex(#B6B6B6);
// emptyHintLabel.font = [UIFont systemFontOfSize:11];
// [_emptyView addSubview:emptyHintLabel];
//
// [emptyHintLabel mas_makeConstraints:^(MASConstraintMaker *make) {
// make.top.equalTo(emptyImageView.mas_bottom).offset(8);
// make.centerX.equalTo(_emptyView);
// }];
// 去绑定按钮:宽 80 高 24medium 13,颜色 #21BEBD,圆角 12,白底边框 1
UIButton *bindBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[bindBtn setTitle:@"去绑定" forState:UIControlStateNormal];
[bindBtn setTitleColor:UIColorHex(#21BEBD) forState:UIControlStateNormal];
bindBtn.titleLabel.font = MEDIUMFONT(13);
bindBtn.backgroundColor = KWhiteColor;
bindBtn.layer.cornerRadius = 12;
bindBtn.layer.borderWidth = 1;
bindBtn.layer.borderColor = UIColorHex(#21BEBD).CGColor;
bindBtn.layer.masksToBounds = YES;
[bindBtn addTarget:self action:@selector(bindButtonClick) forControlEvents:UIControlEventTouchUpInside];
[_emptyView addSubview:bindBtn];
[bindBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_offset(20);
make.centerX.equalTo(_emptyView);
make.width.mas_offset(82);
make.height.mas_offset(24);
}];
if ([HQCommonUtils isLogin]) {
// 已登录,等待数据回调
} else {
// 未登录:显示"暂未登录"文字,emptyView 保持隐藏
_emptyLabel.hidden = NO;
_collectionView.hidden = NO;
}
}
- (void)bindButtonClick {
if (self.bindDeviceBlock) {
self.bindDeviceBlock(@"");
}
}
- (void)moreClick {
if (![HQCommonUtils isLogin]) {
KPostNotification(KNotificationLoginStateChange, @NO);
return;
}
if (self.watchModel.hasWatch == true) {
if (self.watchMoreBlock) {
self.watchMoreBlock();
}
}else {
if (self.bindDeviceBlock) {
self.bindDeviceBlock(@"");
}
}
}
- (void)setWatchModel:(XJHomeWatchModel *)watchModel {
_watchModel = watchModel;
if (_watchModel.hasWatch == true) {
//有手表
self.watchNumberLabel.text = [NSString stringWithFormat:@"监测工具编码:%@",_watchModel.watchNo];
self.watchNumberLabel.textColor = UIColorHex(#14BEBE);
}else
{
self.watchNumberLabel.text = @"监测工具编码:暂无信息";
self.watchNumberLabel.textColor = UIColorHex(#808080);
self.dataList = @[];
}
}
#pragma mark - Tab Titles Setter
- (void)setTabTitles:(NSArray<NSString *> *)tabTitles {
_tabTitles = [tabTitles copy];
_selectedIndex = 0;
// 清除旧按钮
for (UIButton *btn in _tabButtons) [btn removeFromSuperview];
[_tabButtons removeAllObjects];
UIFont *font = [UIFont systemFontOfSize:14 weight:UIFontWeightBold];
UIButton *prevBtn = nil;
for (NSInteger i = 0; i < (NSInteger)tabTitles.count; i++) {
NSString *title = tabTitles[i];
BOOL isSelected = (i == 0);
// 计算文字宽度,得到按钮宽度
CGFloat textW = ceil([title boundingRectWithSize:CGSizeMake(MAXFLOAT, kButtonH)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName: font}
context:nil].size.width);
CGFloat btnW = textW + kRealValue(kButtonPadX) * 2;
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.tag = i;
btn.titleLabel.font = font;
btn.layer.cornerRadius = kButtonH / 2.0;
btn.clipsToBounds = YES;
btn.backgroundColor = isSelected ? UIColorHex(#14BEBE) : UIColorHex(#F6F7FB);
[btn setTitle:title forState:UIControlStateNormal];
btn.titleLabel.font = isSelected ? BOLDSYSTEMFONT(15) : [UIFont systemFontOfSize:14 weight:UIFontWeightRegular];
[btn setTitleColor:isSelected ? KWhiteColor : UIColorHex(#808080)
forState:UIControlStateNormal];
[btn addTarget:self
action:@selector(p_tabButtonTapped:)
forControlEvents:UIControlEventTouchUpInside];
[_tabContentView addSubview:btn];
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(_tabContentView);
make.height.mas_equalTo(kButtonH);
make.width.mas_equalTo(btnW);
if (prevBtn) {
make.left.equalTo(prevBtn.mas_right).offset(kButtonGap);
} else {
make.left.equalTo(_tabContentView).offset(kButtonGap);
}
// 最后一个按钮右边贴 contentView(撑开 scrollView contentSize
if (i == (NSInteger)tabTitles.count - 1) {
make.right.equalTo(_tabContentView).offset(-kButtonGap);
}
}];
[_tabButtons addObject:btn];
prevBtn = btn;
}
}
#pragma mark - Button Tap
- (void)p_tabButtonTapped:(UIButton *)sender {
NSInteger index = sender.tag;
[self selectTabAtIndex:index];
// 用户主动点击,重置轮播计时器
[self p_restartAutoScroll];
}
#pragma mark - Public: Select Tab
//- (void)selectTabAtIndex:(NSInteger)index {
// if (index < 0 || index >= (NSInteger)_tabButtons.count) return;
// if (![HQCommonUtils isLogin]) {
// KPostNotification(KNotificationLoginStateChange, @NO);
// return;
// }
//
// // 恢复旧 Tab 样式
// UIButton *oldBtn = _tabButtons[_selectedIndex];
// oldBtn.backgroundColor = UIColorHex(#F6F7FB);
// oldBtn.titleLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightRegular];
// [oldBtn setTitleColor:UIColorHex(#808080) forState:UIControlStateNormal];
//
// // 设置新 Tab 样式
// _selectedIndex = index;
// UIButton *newBtn = _tabButtons[index];
// newBtn.backgroundColor = UIColorHex(#14BEBE);
// newBtn.titleLabel.font = BOLDSYSTEMFONT(14);
// [newBtn setTitleColor:KWhiteColor forState:UIControlStateNormal];
//
// [self p_scrollToButton:newBtn];
//
// // tab 0:显示 CollectionView 并恢复轮播;其他:显示"紧急开发中"并暂停轮播
// BOOL isFirst = (index == 0);
// _collectionView.hidden = !isFirst;
// _devView.hidden = isFirst;
//
// if (isFirst) {
// // 切换回第一个 Tab,重新根据数据状态显示 emptyView
// BOOL isEmpty = (_dataList.count == 0);
// _emptyView.hidden = !isEmpty;
// [self p_restartAutoScroll];
// } else {
// // 切换到其他 Tab,隐藏 emptyView
// _emptyView.hidden = YES;
// [self p_stopAutoScroll];
// }
//
// // 通知外部高度变化
// if (self.tabSelectBlock) {
// self.tabSelectBlock(index, _tabTitles[index]);
// }
//}
///// 若按钮中心超过可视区一半,则滚动将其居中
//- (void)p_scrollToButton:(UIButton *)btn {
// // layoutIfNeeded 保证 frame 已计算
// [_tabScrollView layoutIfNeeded];
//
// CGFloat scrollW = _tabScrollView.bounds.size.width;
// CGFloat contentW = _tabScrollView.contentSize.width;
// CGFloat btnCenterX = CGRectGetMidX(btn.frame);
//
// CGFloat offsetX = 0;
// if (btnCenterX > scrollW / 2.0) {
// offsetX = btnCenterX - scrollW / 2.0;
// offsetX = MIN(offsetX, MAX(contentW - scrollW, 0));
// }
//
// [_tabScrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
//}
#pragma mark - DataList Setter
- (void)setDataList:(NSArray *)dataList {
_dataList = [dataList copy];
// 未登录:显示 emptyLabel,隐藏 emptyView 及内容区
if (![HQCommonUtils isLogin]) {
_emptyLabel.text = @" 暂未登录 ";
_emptyLabel.hidden = NO;
_emptyView.hidden = YES;
_collectionView.hidden = YES;
return;
}
// 已登录:隐藏 emptyLabel,显示内容区
_emptyLabel.hidden = YES;
_collectionView.hidden = NO;
// 无设备数据:显示 emptyView(图标 + 提示 + 去绑定按钮)
BOOL isEmpty = (_dataList.count == 0);
_emptyView.hidden = !isEmpty;
[_collectionView reloadData];
// 有多条数据才启动轮播
if (_dataList.count > 1) {
[self p_startAutoScroll];
} else {
[self p_stopAutoScroll];
}
// 通知外部更新高度:无数据/未登录 104,有数据 205
BOOL needSmall = (isEmpty || ![HQCommonUtils isLogin]);
CGFloat newHeight = needSmall ? 104.0 : 200.0;
if (self.heightChangeBlock) {
self.heightChangeBlock(newHeight);
}
}
#pragma mark - UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.dataList.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
XJHomeWatchCollectionViewCell *cell =
[collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([XJHomeWatchCollectionViewCell class])
forIndexPath:indexPath];
// 用 dataList 里对应位置的 model 填充
if (indexPath.item < (NSInteger)_dataList.count) {
[cell configureWithData:_dataList[indexPath.item]];
}
// // item 下标即数据类型:0=心率 1=血氧 2=压力 3=体温
// [cell updateTabIndex:indexPath.item];
return cell;
}
#pragma mark - UICollectionViewDelegateFlowLayout
- (CGSize)collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout *)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
// cell 宽 = 整个 view 宽;cell 高 = collectionView 自身高度
return CGSizeMake(self.bounds.size.width, collectionView.bounds.size.height);
}
#pragma mark - UICollectionViewDelegate
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
// 预留:外部如需监听 cell 点击可在此通过 block 回调
}
#pragma mark - UIScrollViewDelegate(手动滑动同步 Tab
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
if (scrollView != _collectionView) return;
// 更新轮播页码(与 Tab selectedIndex 无关)
_carouselPage = (NSInteger)(scrollView.contentOffset.x / MAX(scrollView.bounds.size.width, 1));
[self p_restartAutoScroll];
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
if (scrollView != _collectionView) return;
// 手指触碰时暂停自动轮播,避免与手势冲突
[self p_stopAutoScroll];
}
#pragma mark - 轮播
/// 启动自动轮播(3 秒一次)
- (void)p_startAutoScroll {
[self p_stopAutoScroll];
if (_dataList.count <= 1) return;
_autoScrollTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:@selector(p_autoScrollToNext)
userInfo:nil
repeats:YES];
// 加入 NSRunLoopCommonModes,防止父 ScrollView 滚动时定时器暂停
[[NSRunLoop mainRunLoop] addTimer:_autoScrollTimer forMode:NSRunLoopCommonModes];
}
/// 停止自动轮播
- (void)p_stopAutoScroll {
[_autoScrollTimer invalidate];
_autoScrollTimer = nil;
}
/// 重置定时器(用户交互后调用)
- (void)p_restartAutoScroll {
if (_dataList.count > 1) [self p_startAutoScroll];
}
/// 滚到下一页,最后一页→第一页不用动画,避免明显跳动
- (void)p_autoScrollToNext {
if (_dataList.count == 0) return;
NSInteger next = (_carouselPage + 1) % _dataList.count;
BOOL animated = (next != 0);
[self p_scrollCollectionToIndex:next animated:animated];
}
/// 滚动 collectionView 到指定页,只更新 carouselPage,不影响 Tab
- (void)p_scrollCollectionToIndex:(NSInteger)index animated:(BOOL)animated {
if (index < 0 || index >= (NSInteger)_dataList.count) return;
_carouselPage = index;
NSIndexPath *ip = [NSIndexPath indexPathForItem:index inSection:0];
[_collectionView scrollToItemAtIndexPath:ip
atScrollPosition:UICollectionViewScrollPositionLeft
animated:animated];
}
/// 离开父视图时停止轮播,防止 timer 持有 self 造成内存泄漏
- (void)willMoveToSuperview:(UIView *)newSuperview {
[super willMoveToSuperview:newSuperview];
if (!newSuperview) [self p_stopAutoScroll];
}
#pragma mark - 上一日/上一周、下一日/下一周
// 上一日/上一周
- (void)previousWeekAction {
self.currentDayDate = [self dateByAddingDays:-1 toDate:self.currentDayDate];
[self updateWeekLabelWithType];
[self checkNextButtonState];
}
// 下一日/下一周
- (void)nextWeekAction {
self.currentDayDate = [self dateByAddingDays:1 toDate:self.currentDayDate];
[self updateWeekLabelWithType];
[self checkNextButtonState];
}
- (void)updateWeekLabelWithType {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd";
self.weekLabel.text = [formatter stringFromDate:self.currentDayDate];
if (self.changeTimeClickBlock) {
NSString *dayYMD = [self formatDateToYMDString:self.currentDayDate];
self.changeTimeClickBlock(dayYMD); //
}
}
// 日期加减
- (NSDate *)dateByAddingDays:(NSInteger)days toDate:(NSDate *)date {
return [date dateByAddingTimeInterval:days*24*60*60];
}
- (NSString *)formatDateToYMDString:(NSDate *)date {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd"];
return [formatter stringFromDate:date];
}
#pragma mark - 检查下一天/下一周按钮状态
- (void)checkNextButtonState {
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setFirstWeekday:2]; // 周一为第一天
NSDate *today = [NSDate date];
NSDate *currentOnly = [self dateByRemovingTime:self.currentDayDate];
NSDate *todayOnly = [self dateByRemovingTime:today];
self.nextBtn.enabled = ([currentOnly compare:todayOnly] == NSOrderedAscending);
}
// 去掉时分秒
- (NSDate *)dateByRemovingTime:(NSDate *)date {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay
fromDate:date];
return [calendar dateFromComponents:components];
}
@end