This commit is contained in:
2025-11-11 15:55:52 +08:00
parent d10114572e
commit 83987db5ac
4 changed files with 307 additions and 5 deletions

View File

@@ -85,6 +85,7 @@
049FB2232EC311F900FAB05D /* KBPersonInfoVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB2222EC311F900FAB05D /* KBPersonInfoVC.m */; };
049FB2262EC3136D00FAB05D /* KBPersonInfoItemCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB2252EC3136D00FAB05D /* KBPersonInfoItemCell.m */; };
049FB2292EC31BB000FAB05D /* KBChangeNicknamePopView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB2282EC31BB000FAB05D /* KBChangeNicknamePopView.m */; };
049FB22C2EC31F8800FAB05D /* KBGenderPickerPopView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB22B2EC31F8800FAB05D /* KBGenderPickerPopView.m */; };
049FB31D2EC21BCD00FAB05D /* KBMyKeyboardCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB31C2EC21BCD00FAB05D /* KBMyKeyboardCell.m */; };
04A9FE0F2EB481100020DB6D /* KBHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 04FC97082EB31B14007BD342 /* KBHUD.m */; };
04A9FE132EB4D0D20020DB6D /* KBFullAccessManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 04A9FE112EB4D0D20020DB6D /* KBFullAccessManager.m */; };
@@ -296,6 +297,8 @@
049FB2252EC3136D00FAB05D /* KBPersonInfoItemCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBPersonInfoItemCell.m; sourceTree = "<group>"; };
049FB2272EC31BB000FAB05D /* KBChangeNicknamePopView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBChangeNicknamePopView.h; sourceTree = "<group>"; };
049FB2282EC31BB000FAB05D /* KBChangeNicknamePopView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBChangeNicknamePopView.m; sourceTree = "<group>"; };
049FB22A2EC31F8800FAB05D /* KBGenderPickerPopView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBGenderPickerPopView.h; sourceTree = "<group>"; };
049FB22B2EC31F8800FAB05D /* KBGenderPickerPopView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBGenderPickerPopView.m; sourceTree = "<group>"; };
049FB31B2EC21BCD00FAB05D /* KBMyKeyboardCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBMyKeyboardCell.h; sourceTree = "<group>"; };
049FB31C2EC21BCD00FAB05D /* KBMyKeyboardCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBMyKeyboardCell.m; sourceTree = "<group>"; };
04A9A67D2EB9E1690023B8F4 /* KBResponderUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBResponderUtils.h; sourceTree = "<group>"; };
@@ -890,6 +893,8 @@
049FB2252EC3136D00FAB05D /* KBPersonInfoItemCell.m */,
049FB2272EC31BB000FAB05D /* KBChangeNicknamePopView.h */,
049FB2282EC31BB000FAB05D /* KBChangeNicknamePopView.m */,
049FB22A2EC31F8800FAB05D /* KBGenderPickerPopView.h */,
049FB22B2EC31F8800FAB05D /* KBGenderPickerPopView.m */,
);
path = V;
sourceTree = "<group>";
@@ -1426,6 +1431,7 @@
048908E32EBF821700FABA60 /* KBSkinDetailVC.m in Sources */,
0477BDF32EBB7B850055D639 /* KBDirectionIndicatorView.m in Sources */,
049FB21A2EC20A9E00FAB05D /* KBMyKeyBoardVC.m in Sources */,
049FB22C2EC31F8800FAB05D /* KBGenderPickerPopView.m in Sources */,
048908D22EBF611D00FABA60 /* KBHistoryMoreCell.m in Sources */,
04FC95D82EB1EA16007BD342 /* BaseCell.m in Sources */,
0477BDF72EBC63A80055D639 /* KBTestVC.m in Sources */,

View File

@@ -0,0 +1,33 @@
//
// KBGenderPickerPopView.h
// keyBoard
//
// Created by Codex on 2025/11/11.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
/// 性别选择弹窗自定义视图(给 LSTPopView 使用)
/// - 使用 UIPickerView 实现上下滑动
/// - Masonry 约束、懒加载、中文注释
@interface KBGenderPickerPopView : UIView
/// 数据源(元素为 NSDictionary包含 key: id, name
@property (nonatomic, copy) NSArray<NSDictionary *> *items;
/// 预选中的 id可为空
@property (nonatomic, copy, nullable) NSString *selectedId;
/// 保存回调,返回选中的字典
@property (nonatomic, copy, nullable) void (^saveHandler)(NSDictionary *selected);
/// 关闭回调
@property (nonatomic, copy, nullable) void (^closeHandler)(void);
/// 将选择器滚动到 selectedId 对应的行
- (void)syncSelection;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,233 @@
//
// KBGenderPickerPopView.m
// keyBoard
//
// Created by Codex on 2025/11/11.
//
@import UIKit;
#import "KBGenderPickerPopView.h"
#import <Masonry/Masonry.h>
@interface KBGenderPickerPopView () <UIPickerViewDelegate, UIPickerViewDataSource>
//
@property (nonatomic, strong) UIView *cardView;
//
@property (nonatomic, strong) UILabel *titleLabel;
//
@property (nonatomic, strong) UIButton *closeButton;
//
@property (nonatomic, strong) UIPickerView *picker;
// /线线
@property (nonatomic, strong) UIView *lineTop;
@property (nonatomic, strong) UIView *lineBottom;
//
@property (nonatomic, strong) UIButton *saveButton;
@end
@implementation KBGenderPickerPopView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = UIColor.clearColor;
//
_items = @[
@{ @"id": @"1", @"name": @"Male" },
@{ @"id": @"2", @"name": @"Female" },
@{ @"id": @"3", @"name": @"The Third Gender" },
];
[self buildUI];
[self makeConstraints];
}
return self;
}
#pragma mark - Public
- (void)setItems:(NSArray<NSDictionary *> *)items {
_items = [items copy];
[self.picker reloadAllComponents];
[self syncSelection];
}
- (void)setSelectedId:(NSString *)selectedId {
_selectedId = [selectedId copy];
[self syncSelection];
}
- (void)syncSelection {
// id __block indexOfObjectPassingTest
NSInteger row = 0;
if (self.selectedId.length > 0) {
NSUInteger idx = [self.items indexOfObjectPassingTest:^BOOL(NSDictionary *obj, NSUInteger idx, BOOL *stop) {
return [[obj objectForKey:@"id"] ?: @"" isEqualToString:self.selectedId];
}];
if (idx != NSNotFound) row = (NSInteger)idx;
}
if (row < (NSInteger)self.items.count) {
[self.picker selectRow:row inComponent:0 animated:NO];
}
[self.picker reloadAllComponents];
}
#pragma mark - Actions
- (void)onTapClose { if (self.closeHandler) self.closeHandler(); }
- (void)onTapSave {
NSInteger row = [self.picker selectedRowInComponent:0];
if (row >= 0 && row < (NSInteger)self.items.count) {
NSDictionary *sel = self.items[row];
if (self.saveHandler) self.saveHandler(sel);
}
}
#pragma mark - UI
- (void)buildUI {
[self addSubview:self.cardView];
[self.cardView addSubview:self.titleLabel];
[self.cardView addSubview:self.closeButton];
[self.cardView addSubview:self.picker];
[self.cardView addSubview:self.lineTop];
[self.cardView addSubview:self.lineBottom];
[self.cardView addSubview:self.saveButton];
}
- (void)makeConstraints {
[self.cardView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self); }];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.cardView).offset(20);
make.top.equalTo(self.cardView).offset(18);
}];
[self.titleLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.titleLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.titleLabel);
make.right.equalTo(self.cardView).offset(-16);
make.width.height.mas_equalTo(36);
}];
[self.picker mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.cardView).offset(10);
make.right.equalTo(self.cardView).offset(-10);
make.top.equalTo(self.titleLabel.mas_bottom).offset(6);
make.bottom.equalTo(self.saveButton.mas_top).offset(0);
}];
// 线 picker
CGFloat rowH = 48;
[self.lineTop mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.picker);
make.centerY.equalTo(self.picker).offset(-rowH/2.0);
make.height.mas_equalTo(1);
}];
[self.lineBottom mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.picker);
make.centerY.equalTo(self.picker).offset(rowH/2.0);
make.height.mas_equalTo(1);
}];
[self.saveButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.cardView).offset(16);
make.right.equalTo(self.cardView).offset(-16);
make.bottom.equalTo(self.cardView).offset(-18);
make.height.mas_equalTo(46);
}];
}
#pragma mark - Picker
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { return 1; }
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { return self.items.count; }
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component { return 48.0; }
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
UILabel *label = (UILabel *)view;
if (![label isKindOfClass:UILabel.class]) {
label = [[UILabel alloc] init];
label.textAlignment = NSTextAlignmentCenter;
label.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold];
}
NSString *name = self.items[row][@"name"] ?: @"";
label.text = name;
BOOL selected = (row == [pickerView selectedRowInComponent:0]);
label.textColor = selected ? [UIColor colorWithRed:0.02 green:0.75 blue:0.67 alpha:1.0]
: [UIColor colorWithWhite:0.65 alpha:1.0];
return label;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
//
[pickerView reloadAllComponents];
}
#pragma mark - Lazy UI
- (UIView *)cardView {
if (!_cardView) {
_cardView = [UIView new];
_cardView.backgroundColor = UIColor.whiteColor;
_cardView.layer.cornerRadius = 18.0; _cardView.layer.masksToBounds = YES;
}
return _cardView;
}
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [UILabel new];
_titleLabel.text = @"Modify Gender";
_titleLabel.textColor = [UIColor blackColor];
_titleLabel.font = [UIFont systemFontOfSize:22 weight:UIFontWeightBold];
}
return _titleLabel;
}
- (UIButton *)closeButton {
if (!_closeButton) {
_closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
_closeButton.backgroundColor = [UIColor colorWithWhite:1 alpha:0.95];
_closeButton.layer.cornerRadius = 18.0; _closeButton.layer.masksToBounds = YES;
UIImage *img = nil; if (@available(iOS 13.0, *)) img = [UIImage systemImageNamed:@"chevron.down"];
[_closeButton setImage:img forState:UIControlStateNormal];
if (!img) { [_closeButton setTitle:@"" forState:UIControlStateNormal]; }
[_closeButton setTitleColor:[UIColor colorWithWhite:0.3 alpha:1] forState:UIControlStateNormal];
_closeButton.tintColor = [UIColor colorWithWhite:0.3 alpha:1];
[_closeButton addTarget:self action:@selector(onTapClose) forControlEvents:UIControlEventTouchUpInside];
}
return _closeButton;
}
- (UIPickerView *)picker {
if (!_picker) {
_picker = [[UIPickerView alloc] init];
_picker.dataSource = self; _picker.delegate = self;
_picker.backgroundColor = UIColor.clearColor;
}
return _picker;
}
- (UIView *)lineTop {
if (!_lineTop) { _lineTop = [self makeLine]; }
return _lineTop;
}
- (UIView *)lineBottom {
if (!_lineBottom) { _lineBottom = [self makeLine]; }
return _lineBottom;
}
- (UIView *)makeLine { UIView *v = [UIView new]; v.backgroundColor = [UIColor colorWithWhite:0.88 alpha:1.0]; return v; }
- (UIButton *)saveButton {
if (!_saveButton) {
_saveButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_saveButton setTitle:@"Save" forState:UIControlStateNormal];
[_saveButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
_saveButton.titleLabel.font = [UIFont systemFontOfSize:20 weight:UIFontWeightSemibold];
_saveButton.backgroundColor = [UIColor colorWithRed:0.02 green:0.75 blue:0.67 alpha:1.0];
_saveButton.layer.cornerRadius = 23.0; _saveButton.layer.masksToBounds = YES;
[_saveButton addTarget:self action:@selector(onTapSave) forControlEvents:UIControlEventTouchUpInside];
}
return _saveButton;
}
@end

View File

@@ -16,6 +16,7 @@
#import <PhotosUI/PhotosUI.h>
#import "LSTPopView.h"
#import "KBChangeNicknamePopView.h"
#import "KBGenderPickerPopView.h"
@interface KBPersonInfoVC () <UITableViewDelegate, UITableViewDataSource, PHPickerViewControllerDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate>
@@ -107,10 +108,9 @@
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// / ID
if (indexPath.row == 0) {
// ->
CGFloat width = MIN(KB_SCREEN_WIDTH - 48, 360);
CGFloat width = KB_SCREEN_WIDTH;
KBChangeNicknamePopView *content = [[KBChangeNicknamePopView alloc] initWithFrame:CGRectMake(0, 0, width, 230)];
content.prefillNickname = self.items.firstObject[@"value"] ?: @"";
@@ -119,7 +119,7 @@
popStyle:LSTPopStyleSmoothFromBottom
dismissStyle:LSTDismissStyleScale];
pop.bgColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
pop.hemStyle = LSTHemStyleCenter; //
pop.hemStyle = LSTHemStyleBottom; //
pop.isClickBgDismiss = YES; //
pop.isAvoidKeyboard = YES; //
pop.avoidKeyboardSpace = 10;
@@ -139,9 +139,39 @@
};
[pop pop];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.15 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [content focusInput]; });
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.15 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [content focusInput]; });
} else if (indexPath.row == 1) {
// TODO:
// ->
NSArray *genders = @[ @{@"id":@"1",@"name":@"Male"}, @{@"id":@"2",@"name":@"Female"}, @{@"id":@"3",@"name":@"The Third Gender"} ];
CGFloat width = KB_SCREEN_WIDTH;
KBGenderPickerPopView *content = [[KBGenderPickerPopView alloc] initWithFrame:CGRectMake(0, 0, width, 300)];
content.items = genders;
// id
NSString *curName = self.items[1][@"value"];
NSString *selId = nil;
for (NSDictionary *d in genders) { if ([d[@"name"] isEqualToString:curName]) { selId = d[@"id"]; break; } }
content.selectedId = selId;
LSTPopView *pop = [LSTPopView initWithCustomView:content
parentView:nil
popStyle:LSTPopStyleSmoothFromBottom
dismissStyle:LSTDismissStyleSmoothToBottom];
pop.bgColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
pop.hemStyle = LSTHemStyleBottom;
pop.isClickBgDismiss = YES;
__weak typeof(self) weakSelf = self; __weak typeof(pop) weakPop = pop;
content.closeHandler = ^{ [weakPop dismiss]; };
content.saveHandler = ^(NSDictionary *selected) {
NSString *name = selected[@"name"] ?: @"";
NSMutableArray *m = [weakSelf.items mutableCopy];
NSMutableDictionary *d1 = [m[1] mutableCopy];
d1[@"value"] = name; m[1] = d1; weakSelf.items = m;
[weakSelf.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
[weakPop dismiss];
};
[pop pop];
}
}