This commit is contained in:
2025-11-06 14:02:22 +08:00
parent d7874829d9
commit 15fc9621cd
15 changed files with 337 additions and 16 deletions

View File

@@ -8,6 +8,11 @@
#ifndef KBConfig_h #ifndef KBConfig_h
#define KBConfig_h #define KBConfig_h
// UIKit is needed for CGFloat and UIScreen used by size-adaptation helpers
#if __OBJC__
#import <UIKit/UIKit.h>
#endif
// 基础baseUrl // 基础baseUrl
#ifndef KB_BASE_URL #ifndef KB_BASE_URL
#define KB_BASE_URL @"https://m1.apifoxmock.com/m1/5438099-5113192-default/" #define KB_BASE_URL @"https://m1.apifoxmock.com/m1/5438099-5113192-default/"
@@ -45,6 +50,27 @@
#define KB_APP_SCHEME @"kbkeyboardAppExtension" #define KB_APP_SCHEME @"kbkeyboardAppExtension"
#endif #endif
// --- 尺寸适配(以 375 设计稿为基准) ---
// 用法:传入设计稿上的数值,返回按当前屏幕宽度缩放后的值。
// 例如CGFloat padding = KBFit(16);
#ifndef KB_DESIGN_WIDTH
#define KB_DESIGN_WIDTH 375.0
#endif
#if __OBJC__
static inline CGFloat KBScreenWidth(void) {
return [UIScreen mainScreen].bounds.size.width;
}
static inline CGFloat KBScaleFactor(void) {
return KBScreenWidth() / (CGFloat)KB_DESIGN_WIDTH;
}
static inline CGFloat KBFit(CGFloat designValue) {
return designValue * KBScaleFactor();
}
#endif
// --- 常用宏 --- // --- 常用宏 ---
// 弱引用 self在 block 中避免循环引用):使用处直接写 KBWeakSelf; // 弱引用 self在 block 中避免循环引用):使用处直接写 KBWeakSelf;
#ifndef KBWeakSelf #ifndef KBWeakSelf

View File

@@ -16,6 +16,8 @@
0477BDF32EBB7B850055D639 /* KBDirectionIndicatorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BDF22EBB7B850055D639 /* KBDirectionIndicatorView.m */; }; 0477BDF32EBB7B850055D639 /* KBDirectionIndicatorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BDF22EBB7B850055D639 /* KBDirectionIndicatorView.m */; };
0477BDF72EBC63A80055D639 /* KBTestVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BDF62EBC63A80055D639 /* KBTestVC.m */; }; 0477BDF72EBC63A80055D639 /* KBTestVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BDF62EBC63A80055D639 /* KBTestVC.m */; };
0477BDFA2EBC66340055D639 /* HomeHeadView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BDF92EBC66340055D639 /* HomeHeadView.m */; }; 0477BDFA2EBC66340055D639 /* HomeHeadView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BDF92EBC66340055D639 /* HomeHeadView.m */; };
0477BDFD2EBC6A170055D639 /* HomeHotVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BDFC2EBC6A170055D639 /* HomeHotVC.m */; };
0477BE002EBC6A330055D639 /* HomeRankVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0477BDFF2EBC6A330055D639 /* HomeRankVC.m */; };
04A9FE0F2EB481100020DB6D /* KBHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC97082EB31B14007BD342 /* KBHUD.m */; }; 04A9FE0F2EB481100020DB6D /* KBHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC97082EB31B14007BD342 /* KBHUD.m */; };
04A9FE132EB4D0D20020DB6D /* KBFullAccessManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */; }; 04A9FE132EB4D0D20020DB6D /* KBFullAccessManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */; };
04A9FE162EB873C80020DB6D /* UIViewController+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE152EB873C80020DB6D /* UIViewController+Extension.m */; }; 04A9FE162EB873C80020DB6D /* UIViewController+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE152EB873C80020DB6D /* UIViewController+Extension.m */; };
@@ -109,6 +111,10 @@
0477BDF62EBC63A80055D639 /* KBTestVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBTestVC.m; sourceTree = "<group>"; }; 0477BDF62EBC63A80055D639 /* KBTestVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBTestVC.m; sourceTree = "<group>"; };
0477BDF82EBC66340055D639 /* HomeHeadView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HomeHeadView.h; sourceTree = "<group>"; }; 0477BDF82EBC66340055D639 /* HomeHeadView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HomeHeadView.h; sourceTree = "<group>"; };
0477BDF92EBC66340055D639 /* HomeHeadView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HomeHeadView.m; sourceTree = "<group>"; }; 0477BDF92EBC66340055D639 /* HomeHeadView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HomeHeadView.m; sourceTree = "<group>"; };
0477BDFB2EBC6A170055D639 /* HomeHotVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HomeHotVC.h; sourceTree = "<group>"; };
0477BDFC2EBC6A170055D639 /* HomeHotVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HomeHotVC.m; sourceTree = "<group>"; };
0477BDFE2EBC6A330055D639 /* HomeRankVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HomeRankVC.h; sourceTree = "<group>"; };
0477BDFF2EBC6A330055D639 /* HomeRankVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HomeRankVC.m; sourceTree = "<group>"; };
04A9A67D2EB9E1690023B8F4 /* KBResponderUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBResponderUtils.h; sourceTree = "<group>"; }; 04A9A67D2EB9E1690023B8F4 /* KBResponderUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBResponderUtils.h; sourceTree = "<group>"; };
04A9FE102EB4D0D20020DB6D /* KBFullAccessManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFullAccessManager.h; sourceTree = "<group>"; }; 04A9FE102EB4D0D20020DB6D /* KBFullAccessManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBFullAccessManager.h; sourceTree = "<group>"; };
04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFullAccessManager.m; sourceTree = "<group>"; }; 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBFullAccessManager.m; sourceTree = "<group>"; };
@@ -241,6 +247,19 @@
path = Utils; path = Utils;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
0477BE012EBC6D420055D639 /* FunctionTest */ = {
isa = PBXGroup;
children = (
0477BDF52EBC63A80055D639 /* KBTestVC.h */,
0477BDF62EBC63A80055D639 /* KBTestVC.m */,
A1B2D7002EB8C00100000001 /* KBLangTestVC.h */,
A1B2D7012EB8C00100000001 /* KBLangTestVC.m */,
0459D1B22EBA284C00F2D189 /* KBSkinCenterVC.h */,
0459D1B32EBA284C00F2D189 /* KBSkinCenterVC.m */,
);
path = FunctionTest;
sourceTree = "<group>";
};
04A9FE122EB4D0D20020DB6D /* Manager */ = { 04A9FE122EB4D0D20020DB6D /* Manager */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -363,14 +382,13 @@
children = ( children = (
04FC95CD2EB1E7A1007BD342 /* HomeVC.h */, 04FC95CD2EB1E7A1007BD342 /* HomeVC.h */,
04FC95CE2EB1E7A1007BD342 /* HomeVC.m */, 04FC95CE2EB1E7A1007BD342 /* HomeVC.m */,
A1B2D7002EB8C00100000001 /* KBLangTestVC.h */,
A1B2D7012EB8C00100000001 /* KBLangTestVC.m */,
0459D1B22EBA284C00F2D189 /* KBSkinCenterVC.h */,
0459D1B32EBA284C00F2D189 /* KBSkinCenterVC.m */,
0477BDEE2EBB76E30055D639 /* HomeSheetVC.h */, 0477BDEE2EBB76E30055D639 /* HomeSheetVC.h */,
0477BDEF2EBB76E30055D639 /* HomeSheetVC.m */, 0477BDEF2EBB76E30055D639 /* HomeSheetVC.m */,
0477BDF52EBC63A80055D639 /* KBTestVC.h */, 0477BDFB2EBC6A170055D639 /* HomeHotVC.h */,
0477BDF62EBC63A80055D639 /* KBTestVC.m */, 0477BDFC2EBC6A170055D639 /* HomeHotVC.m */,
0477BDFE2EBC6A330055D639 /* HomeRankVC.h */,
0477BDFF2EBC6A330055D639 /* HomeRankVC.m */,
0477BE012EBC6D420055D639 /* FunctionTest */,
); );
path = VC; path = VC;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -885,6 +903,7 @@
files = ( files = (
04FC95E92EB23B67007BD342 /* KBNetworkManager.m in Sources */, 04FC95E92EB23B67007BD342 /* KBNetworkManager.m in Sources */,
04FC95D22EB1E7AE007BD342 /* MyVC.m in Sources */, 04FC95D22EB1E7AE007BD342 /* MyVC.m in Sources */,
0477BE002EBC6A330055D639 /* HomeRankVC.m in Sources */,
043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */, 043FBCD22EAF97630036AFE1 /* KBPermissionViewController.m in Sources */,
04A9FE162EB873C80020DB6D /* UIViewController+Extension.m in Sources */, 04A9FE162EB873C80020DB6D /* UIViewController+Extension.m in Sources */,
04C6EABE2EAF86530089C901 /* AppDelegate.m in Sources */, 04C6EABE2EAF86530089C901 /* AppDelegate.m in Sources */,
@@ -910,6 +929,7 @@
A1B2D7022EB8C00100000001 /* KBLangTestVC.m in Sources */, A1B2D7022EB8C00100000001 /* KBLangTestVC.m in Sources */,
04C6EABF2EAF86530089C901 /* main.m in Sources */, 04C6EABF2EAF86530089C901 /* main.m in Sources */,
04FC95CC2EB1E780007BD342 /* BaseTabBarController.m in Sources */, 04FC95CC2EB1E780007BD342 /* BaseTabBarController.m in Sources */,
0477BDFD2EBC6A170055D639 /* HomeHotVC.m in Sources */,
0459D1B72EBA287900F2D189 /* KBSkinManager.m in Sources */, 0459D1B72EBA287900F2D189 /* KBSkinManager.m in Sources */,
04FC95F42EB339C1007BD342 /* AppleSignInManager.m in Sources */, 04FC95F42EB339C1007BD342 /* AppleSignInManager.m in Sources */,
04C6EAC12EAF86530089C901 /* ViewController.m in Sources */, 04C6EAC12EAF86530089C901 /* ViewController.m in Sources */,

View File

@@ -9,12 +9,11 @@
@implementation HomeHeadView @implementation HomeHeadView
/* - (instancetype)initWithFrame:(CGRect)frame{
// Only override drawRect: if you perform custom drawing. if (self = [super initWithFrame:frame]) {
// An empty implementation adversely affects performance during animation. self.backgroundColor = [UIColor blueColor];
- (void)drawRect:(CGRect)rect { }
// Drawing code return self;
} }
*/
@end @end

View File

@@ -0,0 +1,16 @@
//
// HomeHotVC.h
// keyBoard
//
// Created by Mac on 2025/11/6.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface HomeHotVC : UIViewController
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,31 @@
//
// HomeHotVC.m
// keyBoard
//
// Created by Mac on 2025/11/6.
//
#import "HomeHotVC.h"
@interface HomeHotVC ()
@end
@implementation HomeHotVC
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
/*
#pragma mark - Navigation
// 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.
}
*/
@end

View File

@@ -0,0 +1,16 @@
//
// HomeRankVC.h
// keyBoard
//
// Created by Mac on 2025/11/6.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface HomeRankVC : UIViewController
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,31 @@
//
// HomeRankVC.m
// keyBoard
//
// Created by Mac on 2025/11/6.
//
#import "HomeRankVC.h"
@interface HomeRankVC ()
@end
@implementation HomeRankVC
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
/*
#pragma mark - Navigation
// 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.
}
*/
@end

View File

@@ -7,9 +7,24 @@
#import "HomeSheetVC.h" #import "HomeSheetVC.h"
#import "KBDirectionIndicatorView.h" #import "KBDirectionIndicatorView.h"
//
#import "HomeHotVC.h"
#import "HomeRankVC.h"
@interface HomeSheetVC () @interface HomeSheetVC ()
@property (nonatomic, strong) KBDirectionIndicatorView *indicator; @property (nonatomic, strong) KBDirectionIndicatorView *indicator;
//
@property (nonatomic, strong) UIView *topBar;
@property (nonatomic, strong) UIButton *hotButton;
@property (nonatomic, strong) UIButton *rankButton;
@property (nonatomic, strong) UIView *underlineView; // 线
//
@property (nonatomic, strong) UIView *containerView;
@property (nonatomic, strong) UIViewController *currentChild;
@property (nonatomic, strong) HomeHotVC *hotVC;
@property (nonatomic, strong) HomeRankVC *rankVC;
@end @end
@implementation HomeSheetVC @implementation HomeSheetVC
@@ -22,6 +37,11 @@
config = [HWBackgroundConfig configWithBehavior:HWBackgroundBehaviorDefault]; config = [HWBackgroundConfig configWithBehavior:HWBackgroundBehaviorDefault];
config.backgroundAlpha = 0.01; config.backgroundAlpha = 0.01;
[self.hw_dimmedView reloadConfig:config]; [self.hw_dimmedView reloadConfig:config];
// +
[self setupTopButtonsAndContainer];
//
[self switchToIndex:0 animated:NO];
} }
- (UIView<HWPanModalIndicatorProtocol> *)customIndicatorView { - (UIView<HWPanModalIndicatorProtocol> *)customIndicatorView {
@@ -32,6 +52,13 @@
- (void)panModalTransitionDidFinish { - (void)panModalTransitionDidFinish {
// //
[self.indicator applyPresentationState:self.hw_presentationState]; [self.indicator applyPresentationState:self.hw_presentationState];
//
//
if (self.topBar && self.topBar.alpha < 1.0) {
[UIView animateWithDuration:0.18 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.topBar.alpha = 1.0;
} completion:nil];
}
} }
- (void)didChangeTransitionToState:(PresentationState)state { - (void)didChangeTransitionToState:(PresentationState)state {
@@ -77,5 +104,157 @@
return NO; return NO;
} }
//
- (NSTimeInterval)transitionDuration {
return 0;
}
//
- (BOOL)isHapticFeedbackEnabled {
return NO;
}
#pragma mark - UI
- (void)setupTopButtonsAndContainer {
//
self.topBar = [[UIView alloc] init];
self.topBar.backgroundColor = [UIColor colorWithWhite:1 alpha:0.9];
[self.view addSubview:self.topBar];
//
self.topBar.alpha = 0.0;
//
self.hotButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.hotButton setTitle:@"热门" forState:UIControlStateNormal];
[self.hotButton setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];
[self.hotButton setTitleColor:[UIColor blackColor] forState:UIControlStateSelected];
self.hotButton.titleLabel.font = [UIFont boldSystemFontOfSize:16];
self.hotButton.tag = 0;
[self.hotButton addTarget:self action:@selector(onTapTopButton:) forControlEvents:UIControlEventTouchUpInside];
[self.topBar addSubview:self.hotButton];
self.rankButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.rankButton setTitle:@"排行" forState:UIControlStateNormal];
[self.rankButton setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];
[self.rankButton setTitleColor:[UIColor blackColor] forState:UIControlStateSelected];
self.rankButton.titleLabel.font = [UIFont boldSystemFontOfSize:16];
self.rankButton.tag = 1;
[self.rankButton addTarget:self action:@selector(onTapTopButton:) forControlEvents:UIControlEventTouchUpInside];
[self.topBar addSubview:self.rankButton];
// 线
self.underlineView = [[UIView alloc] init];
self.underlineView.backgroundColor = [UIColor blackColor];
self.underlineView.layer.cornerRadius = 1.0;
[self.topBar addSubview:self.underlineView];
//
self.containerView = [[UIView alloc] init];
self.containerView.backgroundColor = [UIColor whiteColor];
self.containerView.clipsToBounds = YES;
[self.view addSubview:self.containerView];
// Masonry
CGFloat topPadding = 12; //
[self.topBar mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.view);
make.top.equalTo(self.view).offset(topPadding);
make.height.mas_equalTo(44);
}];
[self.hotButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.bottom.equalTo(self.topBar);
make.left.equalTo(self.topBar);
}];
[self.rankButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.bottom.equalTo(self.topBar);
make.right.equalTo(self.topBar);
make.left.equalTo(self.hotButton.mas_right);
make.width.equalTo(self.hotButton);
}];
//
[self.underlineView mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(2);
make.bottom.equalTo(self.topBar.mas_bottom).offset(-2);
make.centerX.equalTo(self.hotButton);
make.width.mas_equalTo(24);
}];
[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.topBar.mas_bottom).offset(8);
make.left.right.bottom.equalTo(self.view);
}];
}
#pragma mark - Action
- (void)onTapTopButton:(UIButton *)sender {
[self switchToIndex:sender.tag animated:YES];
}
#pragma mark - Switch Child
- (void)switchToIndex:(NSInteger)index animated:(BOOL)animated {
UIViewController *target = (index == 0) ? self.hotVC : self.rankVC;
if (!target) {
if (index == 0) {
self.hotVC = [HomeHotVC new];
target = self.hotVC;
} else {
self.rankVC = [HomeRankVC new];
target = self.rankVC;
}
}
if (self.currentChild == target) {
//
[self updateButtonStateForIndex:index animated:animated];
return;
}
//
if (self.currentChild) {
[self.currentChild willMoveToParentViewController:nil];
[self.currentChild.view removeFromSuperview];
[self.currentChild removeFromParentViewController];
}
//
[self addChildViewController:target];
[self.containerView addSubview:target.view];
target.view.backgroundColor = [UIColor colorWithWhite:0.98 alpha:1];
[target.view mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.containerView);
}];
[target didMoveToParentViewController:self];
self.currentChild = target;
[self updateButtonStateForIndex:index animated:animated];
}
- (void)updateButtonStateForIndex:(NSInteger)index animated:(BOOL)animated {
self.hotButton.selected = (index == 0);
self.rankButton.selected = (index == 1);
UIButton *btn = (index == 0) ? self.hotButton : self.rankButton;
// 线
[self.underlineView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(2);
make.bottom.equalTo(self.topBar.mas_bottom).offset(-2);
make.centerX.equalTo(btn);
make.width.mas_equalTo(24);
}];
if (animated) {
[UIView animateWithDuration:0.25 animations:^{
[self.topBar layoutIfNeeded];
}];
} else {
[self.topBar layoutIfNeeded];
}
}
@end @end

View File

@@ -19,19 +19,22 @@
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor]; self.view.backgroundColor = [UIColor whiteColor];
CGFloat topV = KBFit(500);
[self.view addSubview:self.headView]; [self.view addSubview:self.headView];
[self setupMas:topV];
// sheetVC // sheetVC
HomeSheetVC *vc = [HomeSheetVC new]; HomeSheetVC *vc = [[HomeSheetVC alloc] init];
vc.minHeight = 300; vc.minHeight = KB_SCREEN_HEIGHT - topV - 30;
vc.topInset = 100; vc.topInset = 100;
[self presentPanModal:vc]; [self presentPanModal:vc];
} }
- (void)setupMas{ - (void)setupMas:(CGFloat)headViewTopV{
[self.headView mas_makeConstraints:^(MASConstraintMaker *make) { [self.headView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.view); make.left.right.equalTo(self.view);
make.top.equalTo(self.view); make.top.equalTo(self.view);
make.height.mas_equalTo(headViewTopV);
}]; }];
} }