This commit is contained in:
2025-11-10 19:22:31 +08:00
parent 8069b08fab
commit 1dc9560a1f
46 changed files with 691 additions and 33 deletions

View File

@@ -179,7 +179,7 @@
- (UILabel *)peopleLabel {
if (!_peopleLabel) {
_peopleLabel = [UILabel new];
_peopleLabel.textColor = [UIColor colorWithHex:0x02BEAC];
_peopleLabel.textColor = [UIColor colorWithHex:KBColor];
_peopleLabel.font = [UIFont systemFontOfSize:10 weight:UIFontWeightRegular];
_peopleLabel.textAlignment = NSTextAlignmentCenter;
_peopleLabel.numberOfLines = 2;

View File

@@ -445,13 +445,19 @@
_dragArrowImageView.contentMode = UIViewContentModeScaleAspectFit;
// Short
_dragArrowImageView.image = [UIImage imageNamed:@"home_up_arrow"];
// /
_dragArrowImageView.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(kb_onTapDragArrow)];
[_dragArrowImageView addGestureRecognizer:tap];
}
return _dragArrowImageView;
}
//
- (void)kb_updateDragArrowForState:(PresentationState)state {
NSString *imgName = (state == PresentationStateMedium) ? @"home_down_arrow" : @"home_up_arrow";
// Medium Long Long
BOOL isAtTop = (state == PresentationStateMedium || state == PresentationStateLong);
NSString *imgName = isAtTop ? @"home_down_arrow" : @"home_up_arrow";
UIImage *img = [UIImage imageNamed:imgName];
if (img && self.dragArrowImageView.image != img) {
//
@@ -464,6 +470,22 @@
}
}
///
/// - Medium
/// - Short
- (void)kb_onTapDragArrow {
//
PresentationState state = self.hw_presentationState;
BOOL isAtTop = (state == PresentationStateMedium || state == PresentationStateLong);
if (isAtTop) {
// ->
[self hw_panModalTransitionTo:PresentationStateShort];
} else {
// ->
[self hw_panModalTransitionTo:PresentationStateMedium];
}
}
- (UIImageView *)leftBgImageView{
if (!_leftBgImageView) {

View File

@@ -0,0 +1,22 @@
//
// KBMyHeaderView.h
// keyBoard
//
// 顶部头部视图:标题 + 头像行 + 两张卡片
// Masonry 约束,懒加载,中文注释
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface KBMyHeaderView : UIView
@property (nonatomic, strong, readonly) UILabel *titleLabel; // “Settings” 标题
@property (nonatomic, strong, readonly) UIButton *keyboardBtn; // 右上角“ My Keyboard ”按钮
@property (nonatomic, strong, readonly) UIImageView *avatarView; // 头像
@property (nonatomic, strong, readonly) UILabel *nameLabel; // 名称/提示
@property (nonatomic, strong, readonly) UIView *cardLeft; // 左卡片
@property (nonatomic, strong, readonly) UIView *cardRight; // 右卡片
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,142 @@
//
// KBMyHeaderView.m
// keyBoard
//
#import "KBMyHeaderView.h"
#import <Masonry/Masonry.h>
#import "UIColor+Extension.h"
@interface KBMyHeaderView ()
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIButton *keyboardBtn;
@property (nonatomic, strong) UIImageView *avatarView;
@property (nonatomic, strong) UILabel *nameLabel;
@property (nonatomic, strong) UIImageView *cardLeft;
@property (nonatomic, strong) UIImageView *cardRight;
@end
@implementation KBMyHeaderView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor colorWithHex:0xF2F6FA]; //
[self addSubview:self.titleLabel];
[self addSubview:self.keyboardBtn];
[self addSubview:self.avatarView];
[self addSubview:self.nameLabel];
[self addSubview:self.cardLeft];
[self addSubview:self.cardRight];
//
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self).offset(26);
make.bottom.equalTo(self.avatarView.mas_top).offset(-35); //
}];
[self.keyboardBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.titleLabel);
make.right.equalTo(self).offset(-20);
make.height.mas_equalTo(34);
make.width.mas_greaterThanOrEqualTo(126);
}];
[self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self).offset(26);
make.bottom.equalTo(self.cardLeft.mas_top).offset(-23);
make.width.height.mas_equalTo(70);
}];
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.avatarView);
make.left.equalTo(self.avatarView.mas_right).offset(12);
make.right.lessThanOrEqualTo(self).offset(-20);
}];
// 166 99
// w ?
CGFloat height = 99 * (KB_SCREEN_WIDTH - 2 * 16 - 10) * 0.5 / 166;
[self.cardLeft mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self).offset(16);
make.bottom.equalTo(self).offset(-30);
make.right.equalTo(self.mas_centerX).offset(-5);
make.height.mas_equalTo(height);
}];
[self.cardRight mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self).offset(-16);
make.bottom.equalTo(self).offset(-30);
make.left.equalTo(self.mas_centerX).offset(5);
make.height.equalTo(self.cardLeft);
}];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
//
self.avatarView.layer.cornerRadius = self.avatarView.bounds.size.height * 0.5;
self.avatarView.layer.masksToBounds = YES;
}
+ (void)kb_applyGradientTo:(UIView *)view colors:(NSArray *)colors {
// setNeedsLayout
NSMutableArray<CALayer *> *remove = [NSMutableArray array];
for (CALayer *l in view.layer.sublayers) {
if ([l isKindOfClass:[CAGradientLayer class]]) { [remove addObject:l]; }
}
for (CALayer *l in remove) { [l removeFromSuperlayer]; }
CAGradientLayer *g = [CAGradientLayer layer];
g.colors = colors;
g.startPoint = CGPointMake(0, 0.5);
g.endPoint = CGPointMake(1, 0.5);
g.frame = view.bounds;
[view.layer insertSublayer:g atIndex:0];
}
#pragma mark - Lazy UI
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [UILabel new];
_titleLabel.text = @"Settings"; //
_titleLabel.font = [UIFont systemFontOfSize:30 weight:UIFontWeightBold];
_titleLabel.textColor = [UIColor colorWithHex:0x1B1F1A];
}
return _titleLabel;
}
- (UIButton *)keyboardBtn {
if (!_keyboardBtn) {
_keyboardBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_keyboardBtn setTitle:@" My Keyboard " forState:UIControlStateNormal];
_keyboardBtn.titleLabel.font = [UIFont systemFontOfSize:10 weight:UIFontWeightSemibold];
[_keyboardBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
_keyboardBtn.backgroundColor = [UIColor colorWithHex:KBColor];
_keyboardBtn.layer.cornerRadius = 17;
_keyboardBtn.layer.masksToBounds = YES;
}
return _keyboardBtn;
}
- (UIImageView *)avatarView {
if (!_avatarView) {
_avatarView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"lufei.jpg"]];
_avatarView.contentMode = UIViewContentModeScaleAspectFill;
_avatarView.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
}
return _avatarView;
}
- (UILabel *)nameLabel {
if (!_nameLabel) {
_nameLabel = [UILabel new];
_nameLabel.text = @"Notice";
_nameLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold];
_nameLabel.textColor = [UIColor colorWithHex:0x1B1F1A];
}
return _nameLabel;
}
- (UIImageView *)cardLeft { if (!_cardLeft) { _cardLeft = [UIImageView new]; _cardLeft.contentMode = UIViewContentModeScaleAspectFit; _cardLeft.image = [UIImage imageNamed:@"my_member_icon"];} return _cardLeft; }
- (UIImageView *)cardRight { if (!_cardRight) { _cardRight = [UIImageView new];_cardRight.contentMode = UIViewContentModeScaleAspectFit; _cardRight.image = [UIImage imageNamed:@"my_recharge_icon"];} return _cardRight; }
@end

View File

@@ -0,0 +1,27 @@
//
// KBMyListCell.h
// keyBoard
//
// Created by Mac on 2025/11/10.
//
#import <UIKit/UIKit.h>
#import "BaseCell.h"
NS_ASSUME_NONNULL_BEGIN
@interface KBMyListCell : BaseCell
@property (nonatomic, strong) UIView *container; // 卡片容器(做圆角)
@property (nonatomic, strong) UIView *iconBg; // 图标圆角底
@property (nonatomic, strong) UIImageView *iconView; // 图标
@property (nonatomic, strong) UILabel *titleLabel; // 标题
@property (nonatomic, strong) UIView *bottomLine; // 分割线(仅上面一组使用)
@property (nonatomic, strong) UIImageView *arrowView; // 自定义右箭头
- (void)applyCornersWithFirst:(BOOL)isFirst last:(BOOL)isLast; // 组内圆角
- (void)setLineHidden:(BOOL)hidden;
@property (nonatomic, strong) NSDictionary *itemInfoDic; // 自定义右箭头
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,147 @@
//
// KBMyListCell.m
// keyBoard
//
// Created by Mac on 2025/11/10.
//
#import "KBMyListCell.h"
@implementation KBMyListCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
}
return self;
}
- (void)setItemInfoDic:(NSDictionary *)itemInfoDic{
_itemInfoDic = itemInfoDic;
self.titleLabel.text = itemInfoDic[@"title"];
NSString *icon = itemInfoDic[@"icon"];
self.iconView.image = [UIImage imageNamed:icon];
}
- (void)setupUI {
[super setupUI];
self.contentView.backgroundColor = UIColor.clearColor;
self.backgroundColor = UIColor.clearColor;
[self.contentView addSubview:self.container];
[self.container addSubview:self.iconBg];
[self.iconBg addSubview:self.iconView];
[self.container addSubview:self.titleLabel];
[self.container addSubview:self.arrowView];
[self.container addSubview:self.bottomLine];
// 使 UIImageView accessoryType
[self.container mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).offset(16);
make.right.equalTo(self.contentView).offset(-16);
make.top.bottom.equalTo(self.contentView);
}];
[self.iconBg mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.container).offset(16);
make.centerY.equalTo(self.container);
make.width.height.mas_equalTo(28);
}];
[self.iconView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.iconBg);
make.width.height.mas_equalTo(24);
}];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.iconBg.mas_right).offset(12);
make.centerY.equalTo(self.container);
//
make.right.lessThanOrEqualTo(self.arrowView.mas_left).offset(-12);
}];
[self.arrowView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.container);
make.right.equalTo(self.container).offset(-12);
make.width.mas_equalTo(8);
make.height.mas_equalTo(14);
}];
[self.bottomLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.titleLabel);
make.right.equalTo(self.container).offset(-12);
make.bottom.equalTo(self.container);
make.height.mas_equalTo(KB_ONE_PIXEL);
}];
}
- (UIView *)container {
if (!_container) {
_container = [UIView new];
_container.backgroundColor = [UIColor whiteColor];
_container.layer.masksToBounds = YES; //
}
return _container;
}
- (UIView *)iconBg {
if (!_iconBg) {
_iconBg = [UIView new];
_iconBg.backgroundColor = [UIColor clearColor];
}
return _iconBg;
}
- (UIImageView *)iconView {
if (!_iconView) {
_iconView = [[UIImageView alloc] init];
}
return _iconView;
}
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [UILabel new];
_titleLabel.font = [UIFont systemFontOfSize:16];
_titleLabel.textColor = [UIColor colorWithHex:0x222222];
_titleLabel.text = @"Title";
}
return _titleLabel;
}
- (UIImageView *)arrowView {
if (!_arrowView) {
_arrowView = [[UIImageView alloc] init];
_arrowView.contentMode = UIViewContentModeScaleAspectFit;
_arrowView.tintColor = [UIColor colorWithHex:0xC0C0C0];
// iOS13+ 使
if (@available(iOS 13.0, *)) {
_arrowView.image = [UIImage systemImageNamed:@"chevron.right"];
}
}
return _arrowView;
}
- (UIView *)bottomLine {
if (!_bottomLine) {
_bottomLine = [UIView new];
_bottomLine.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
}
return _bottomLine;
}
- (void)setLineHidden:(BOOL)hidden { self.bottomLine.hidden = hidden; }
- (void)applyCornersWithFirst:(BOOL)isFirst last:(BOOL)isLast {
self.container.layer.cornerRadius = 8;
if (@available(iOS 13.0, *)) { self.container.layer.cornerCurve = kCACornerCurveContinuous; }
CACornerMask mask = 0;
if (isFirst && isLast) {
mask = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner | kCALayerMinXMaxYCorner | kCALayerMaxXMaxYCorner;
} else if (isFirst) {
mask = kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner;
} else if (isLast) {
mask = kCALayerMinXMaxYCorner | kCALayerMaxXMaxYCorner;
} else {
mask = 0;
}
self.container.layer.maskedCorners = mask;
}
@end

View File

@@ -19,7 +19,7 @@
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor colorWithHex:0x02BEAC];
self.backgroundColor = [UIColor colorWithHex:KBColor];
self.layer.masksToBounds = YES; //
//

View File

@@ -65,7 +65,7 @@
- (UILabel *)rightLabel {
if (!_rightLabel) {
_rightLabel = [UILabel new];
_rightLabel.textColor = [UIColor colorWithHex:0x02BEAC];
_rightLabel.textColor = [UIColor colorWithHex:KBColor];
_rightLabel.font = [UIFont systemFontOfSize:15 weight:UIFontWeightMedium];
_rightLabel.textAlignment = NSTextAlignmentRight;
_rightLabel.text = @"Download: 1 Million";

View File

@@ -61,7 +61,7 @@
- (void)applySelected:(BOOL)selected {
self.selectedState = selected;
UIColor *fill = selected ? [UIColor colorWithHex:0x02BEAC] : [UIColor colorWithWhite:0 alpha:0.51];
UIColor *fill = selected ? [UIColor colorWithHex:KBColor] : [UIColor colorWithWhite:0 alpha:0.51];
_circleLayer.fillColor = fill.CGColor; // #02BEAC
_checkLayer.hidden = !selected; //
}

View File

@@ -155,9 +155,9 @@ static NSString * const kMySkinCellId = @"kMySkinCellId";
BOOL enable = count > 0;
self.deleteButton.enabled = enable;
if (enable) {
self.deleteButton.backgroundColor = [UIColor colorWithHex:0x02BEAC];
self.deleteButton.backgroundColor = [UIColor colorWithHex:KBColor];
[self.deleteButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
self.deleteButton.layer.borderColor = [UIColor colorWithHex:0x02BEAC].CGColor;
self.deleteButton.layer.borderColor = [UIColor colorWithHex:KBColor].CGColor;
} else {
self.deleteButton.backgroundColor = [UIColor colorWithHex:0xF2F2F2];
[self.deleteButton setTitleColor:[UIColor colorWithHex:0xC8C8C8] forState:UIControlStateNormal];

View File

@@ -9,7 +9,7 @@
NS_ASSUME_NONNULL_BEGIN
@interface MyVC : UIViewController
@interface MyVC : BaseViewController
@end

View File

@@ -8,41 +8,101 @@
#import "MyVC.h"
#import "MySkinVC.h"
#import "KBSkinDetailVC.h"
#import "KBMyHeaderView.h" //
#import "KBMyListCell.h"
@interface MyVC ()
@interface MyVC () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) BaseTableView *tableView; //
@property (nonatomic, strong) KBMyHeaderView *header; //
@property (nonatomic, strong) NSArray<NSArray<NSDictionary *> *> *data; //
@end
@implementation MyVC
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.text = @"My";
label.textColor = [UIColor darkTextColor];
label.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold];
[label sizeToFit];
label.center = self.view.center;
label.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
[self.view addSubview:label];
self.view.backgroundColor = [UIColor colorWithHex:0xF5F7FB];
// title + SF Symbols +
self.data = @[
@[@{ @"title": @"Notice", @"icon": @"my_notice_icon", @"color": @(0x60A3FF) }],
@[@{ @"title": @"Share App", @"icon": @"my_share_icon", @"color": @(0xF5A623) }],
@[@{ @"title": @"Feedback", @"icon": @"my_feedback_icon", @"color": @(0xB06AFD) },
@{ @"title": @"E-mail", @"icon": @"my_email_icon", @"color": @(0xFF8A65) },
@{ @"title": @"Agreement", @"icon": @"my_agreement_icon", @"color": @(0x4CD964) },
@{ @"title": @"Privacy Policy", @"icon": @"my_privacy_icon", @"color": @(0x5AC8FA) }]
];
[self.view addSubview:self.tableView];
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
// tableHeaderView frame
self.header = [[KBMyHeaderView alloc] initWithFrame:CGRectMake(0, 0, KB_SCREEN_WIDTH, 357)];
self.tableView.tableHeaderView = self.header;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// MySkinVC *vc = [[MySkinVC alloc] init];
KBSkinDetailVC *vc = [[KBSkinDetailVC alloc] init];
// [self.navigationController pushViewController:vc animated:true];
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
/*
#pragma mark - Navigation
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:animated];
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#pragma mark - UITableView
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.data.count; }
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.data[section].count; }
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return CGFLOAT_MIN; }
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *v = [UIView new]; v.backgroundColor = [UIColor clearColor]; return v;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { return 20; }
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { UIView *v = [UIView new]; v.backgroundColor = UIColor.clearColor; return v; }
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 64; }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
KBMyListCell *cell = [tableView dequeueReusableCellWithIdentifier:[KBMyListCell reuseId]];
if (!cell) { cell = [[KBMyListCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[KBMyListCell reuseId]]; }
NSDictionary *info = self.data[indexPath.section][indexPath.row];
cell.itemInfoDic = info;
// section 8
NSInteger rows = [tableView numberOfRowsInSection:indexPath.section];
BOOL isFirst = indexPath.row == 0;
BOOL isLast = indexPath.row == rows - 1;
[cell applyCornersWithFirst:isFirst last:isLast];
// 线线
BOOL showLine = (indexPath.section == 0) && !isLast;
[cell setLineHidden:!showLine];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - Lazy
- (BaseTableView *)tableView {
if (!_tableView) {
_tableView = [[BaseTableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
_tableView.backgroundColor = [UIColor colorWithHex:0xF5F7FB];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone; // 线
}
return _tableView;
}
@end

View File

@@ -90,7 +90,7 @@ static const CGFloat JXheightForHeaderInSection = 50;
backgroundView.indicatorHeight = 30;
backgroundView.indicatorCornerRadius = JXCategoryViewAutomaticDimension;
backgroundView.indicatorColor = [UIColor whiteColor]; // keep selected fill white
backgroundView.layer.borderColor = [UIColor colorWithHex:0x02BEAC].CGColor;
backgroundView.layer.borderColor = [UIColor colorWithHex:KBColor].CGColor;
backgroundView.layer.borderWidth = 1;
backgroundView.indicatorWidthIncrement = 0; //
//