243 lines
8.4 KiB
Plaintext
243 lines
8.4 KiB
Plaintext
//
|
||
// EPMineHeaderView.m
|
||
// YuMi
|
||
//
|
||
// Created by AI on 2025-10-09.
|
||
// Copyright © 2025 YuMi. All rights reserved.
|
||
//
|
||
|
||
#import "EPMineHeaderView.h"
|
||
#import <Masonry/Masonry.h>
|
||
#import <SDWebImage/SDWebImage.h>
|
||
#import "EPEmotionColorStorage.h"
|
||
|
||
@interface EPMineHeaderView ()
|
||
|
||
/// 头像视图
|
||
@property (nonatomic, strong) UIImageView *avatarImageView;
|
||
|
||
/// 呼吸光晕层
|
||
@property (nonatomic, strong) CALayer *glowLayer;
|
||
|
||
/// 昵称标签
|
||
@property (nonatomic, strong) UILabel *nicknameLabel;
|
||
|
||
/// ID 标签
|
||
@property (nonatomic, strong) UILabel *idLabel;
|
||
|
||
/// 设置按钮
|
||
@property (nonatomic, strong) UIButton *settingsButton;
|
||
|
||
@end
|
||
|
||
@implementation EPMineHeaderView
|
||
|
||
- (instancetype)initWithFrame:(CGRect)frame {
|
||
if (self = [super initWithFrame:frame]) {
|
||
[self setupUI];
|
||
}
|
||
return self;
|
||
}
|
||
|
||
- (void)layoutSubviews {
|
||
[super layoutSubviews];
|
||
|
||
// 更新光晕层 frame(跟随头像位置)
|
||
if (self.glowLayer) {
|
||
self.glowLayer.frame = CGRectInset(self.avatarImageView.frame, -8, -8);
|
||
}
|
||
}
|
||
|
||
- (void)setupUI {
|
||
// 大圆形头像
|
||
self.avatarImageView = [[UIImageView alloc] init];
|
||
self.avatarImageView.layer.cornerRadius = 60;
|
||
self.avatarImageView.layer.masksToBounds = NO; // 改为 NO 以显示阴影
|
||
self.avatarImageView.layer.borderWidth = 0; // 移除边框
|
||
self.avatarImageView.backgroundColor = [UIColor whiteColor];
|
||
self.avatarImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||
|
||
// 为了同时显示圆角和阴影,需要设置 clipsToBounds
|
||
self.avatarImageView.clipsToBounds = YES;
|
||
|
||
[self addSubview:self.avatarImageView];
|
||
|
||
[self.avatarImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.centerX.equalTo(self);
|
||
make.top.equalTo(self).offset(60);
|
||
make.size.mas_equalTo(CGSizeMake(120, 120));
|
||
}];
|
||
|
||
// 昵称
|
||
self.nicknameLabel = [[UILabel alloc] init];
|
||
self.nicknameLabel.font = [UIFont boldSystemFontOfSize:24];
|
||
self.nicknameLabel.textColor = [UIColor whiteColor];
|
||
self.nicknameLabel.textAlignment = NSTextAlignmentCenter;
|
||
[self addSubview:self.nicknameLabel];
|
||
|
||
[self.nicknameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.centerX.equalTo(self);
|
||
make.top.equalTo(self.avatarImageView.mas_bottom).offset(16);
|
||
}];
|
||
|
||
// ID
|
||
self.idLabel = [[UILabel alloc] init];
|
||
self.idLabel.font = [UIFont systemFontOfSize:14];
|
||
self.idLabel.textColor = [UIColor whiteColor];
|
||
self.idLabel.alpha = 0.8;
|
||
self.idLabel.textAlignment = NSTextAlignmentCenter;
|
||
[self addSubview:self.idLabel];
|
||
|
||
[self.idLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.centerX.equalTo(self);
|
||
make.top.equalTo(self.nicknameLabel.mas_bottom).offset(8);
|
||
}];
|
||
|
||
// 设置按钮(右上角)
|
||
self.settingsButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||
[self.settingsButton setImage:[UIImage systemImageNamed:@"gearshape"] forState:UIControlStateNormal];
|
||
self.settingsButton.tintColor = [UIColor whiteColor];
|
||
self.settingsButton.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.2];
|
||
self.settingsButton.layer.cornerRadius = 20;
|
||
[self.settingsButton addTarget:self action:@selector(settingsButtonTapped) forControlEvents:UIControlEventTouchUpInside];
|
||
[self addSubview:self.settingsButton];
|
||
|
||
[self.settingsButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||
make.top.equalTo(self).offset(50);
|
||
make.trailing.equalTo(self).offset(-20);
|
||
make.size.mas_equalTo(CGSizeMake(40, 40));
|
||
}];
|
||
}
|
||
|
||
- (void)updateWithUserInfo:(NSDictionary *)userInfoDict {
|
||
// 更新昵称
|
||
NSString *nickname = userInfoDict[@"nickname"] ?: YMLocalizedString(@"user.nickname_not_set");
|
||
self.nicknameLabel.text = nickname;
|
||
|
||
// 更新 ID
|
||
NSString *uid = userInfoDict[@"uid"] ?: @"";
|
||
self.idLabel.text = [NSString stringWithFormat:@"ID:%@", uid];
|
||
|
||
// 加载头像
|
||
NSString *avatarURL = userInfoDict[@"avatar"];
|
||
if (avatarURL && avatarURL.length > 0) {
|
||
[self.avatarImageView sd_setImageWithURL:[NSURL URLWithString:avatarURL]
|
||
placeholderImage:[UIImage imageNamed:@"default_avatar"]];
|
||
} else {
|
||
// 使用默认头像
|
||
self.avatarImageView.image = [UIImage imageNamed:@"default_avatar"];
|
||
}
|
||
|
||
// 应用用户专属情绪颜色
|
||
[self applyUserSignatureColor];
|
||
}
|
||
|
||
/// 应用用户专属情绪颜色到头像边框和阴影
|
||
- (void)applyUserSignatureColor {
|
||
NSString *signatureColor = [EPEmotionColorStorage userSignatureColor];
|
||
|
||
if (signatureColor) {
|
||
// 有专属颜色,使用该颜色
|
||
UIColor *color = [self colorFromHex:signatureColor];
|
||
|
||
// 取消边框
|
||
self.avatarImageView.layer.borderWidth = 0;
|
||
|
||
// 设置阴影(使用情绪颜色)
|
||
self.avatarImageView.layer.shadowColor = color.CGColor;
|
||
self.avatarImageView.layer.shadowOffset = CGSizeMake(0, 4);
|
||
self.avatarImageView.layer.shadowOpacity = 0.6;
|
||
self.avatarImageView.layer.shadowRadius = 12;
|
||
|
||
NSLog(@"[EPMineHeaderView] 应用专属颜色: %@", signatureColor);
|
||
|
||
// 应用呼吸光晕动效 ⭐
|
||
[self applyBreathingGlow];
|
||
} else {
|
||
// 没有专属颜色,保持无边框
|
||
self.avatarImageView.layer.borderWidth = 0;
|
||
|
||
// 默认轻微阴影
|
||
self.avatarImageView.layer.shadowColor = [UIColor blackColor].CGColor;
|
||
self.avatarImageView.layer.shadowOffset = CGSizeMake(0, 2);
|
||
self.avatarImageView.layer.shadowOpacity = 0.2;
|
||
self.avatarImageView.layer.shadowRadius = 8;
|
||
|
||
// 移除光晕层
|
||
if (self.glowLayer) {
|
||
[self.glowLayer removeFromSuperlayer];
|
||
self.glowLayer = nil;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 应用呼吸光晕动效
|
||
- (void)applyBreathingGlow {
|
||
NSString *signatureColor = [EPEmotionColorStorage userSignatureColor];
|
||
if (!signatureColor) return;
|
||
|
||
UIColor *color = [self colorFromHex:signatureColor];
|
||
|
||
// 创建光晕层(如果不存在)
|
||
if (!self.glowLayer) {
|
||
self.glowLayer = [CALayer layer];
|
||
self.glowLayer.frame = CGRectInset(self.avatarImageView.frame, -8, -8); // 比头像大 16pt
|
||
self.glowLayer.cornerRadius = 68; // 头像 60 + 扩展 8
|
||
self.glowLayer.backgroundColor = [color colorWithAlphaComponent:0.75].CGColor; // 大幅加深
|
||
|
||
// 插入到头像 layer 下方
|
||
[self.layer insertSublayer:self.glowLayer below:self.avatarImageView.layer];
|
||
} else {
|
||
// 更新颜色
|
||
self.glowLayer.backgroundColor = [color colorWithAlphaComponent:0.75].CGColor; // 大幅加深
|
||
}
|
||
|
||
// 移除旧动画
|
||
[self.glowLayer removeAllAnimations];
|
||
|
||
// 创建呼吸动画组
|
||
CAAnimationGroup *breathingGroup = [CAAnimationGroup animation];
|
||
breathingGroup.duration = 1.8; // 加速
|
||
breathingGroup.repeatCount = HUGE_VALF; // 无限循环
|
||
breathingGroup.autoreverses = YES;
|
||
breathingGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
||
|
||
// 动画 1:透明度变化(呼吸亮度)
|
||
CABasicAnimation *opacityAnim = [CABasicAnimation animationWithKeyPath:@"opacity"];
|
||
opacityAnim.fromValue = @(0.65);
|
||
opacityAnim.toValue = @(1.0); // 接近完全不透明,颜色饱和
|
||
|
||
// 动画 2:缩放变化(呼吸扩散)
|
||
CABasicAnimation *scaleAnim = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
|
||
scaleAnim.fromValue = @(1.0);
|
||
scaleAnim.toValue = @(1.1);
|
||
|
||
breathingGroup.animations = @[opacityAnim, scaleAnim];
|
||
|
||
[self.glowLayer addAnimation:breathingGroup forKey:@"breathing"];
|
||
|
||
NSLog(@"[EPMineHeaderView] 启动呼吸光晕动效");
|
||
}
|
||
|
||
/// Hex 转 UIColor
|
||
- (UIColor *)colorFromHex:(NSString *)hexString {
|
||
unsigned rgbValue = 0;
|
||
NSScanner *scanner = [NSScanner scannerWithString:hexString];
|
||
[scanner setScanLocation:1]; // 跳过 #
|
||
[scanner scanHexInt:&rgbValue];
|
||
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0
|
||
green:((rgbValue & 0xFF00) >> 8)/255.0
|
||
blue:(rgbValue & 0xFF)/255.0
|
||
alpha:1.0];
|
||
}
|
||
|
||
- (void)settingsButtonTapped {
|
||
NSLog(@"[EPMineHeaderView] 设置按钮点击");
|
||
// 使用 block 回调
|
||
if (self.onSettingsButtonTapped) {
|
||
self.onSettingsButtonTapped();
|
||
}
|
||
}
|
||
|
||
@end
|