// // KBGenderPickerPopView.m // keyBoard // // Created by Codex on 2025/11/11. // @import UIKit; #import "KBGenderPickerPopView.h" #import @interface KBGenderPickerPopView () // 白底圆角卡片容器 @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 *)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