带有分隔线的Objective C UIButton并在选择时更改文本颜色

Posted

技术标签:

【中文标题】带有分隔线的Objective C UIButton并在选择时更改文本颜色【英文标题】:Objective C UIButton with divider and changes textcolor when selected 【发布时间】:2018-08-15 02:25:12 【问题描述】:

我创建了一行UIButtons,并在其上添加了一周的日期和日期作为UILabel。 I have also created a UIView selector that when the button is selected, it will highlight the whole button.

现在我不知道如何在按钮之间添加分隔符或垂直线。而不是突出显示UIButton 我希望在选择按钮时将text colour 更改为蓝色。请帮忙

我创造了什么

我想要达到的目标

代码

CGFloat HEIGHT_BTN = 55.0; //--- 10 pixels from the navigation view

CGFloat HEIGHT_LABEL = 30.0;
CGFloat HEIGHT_LABEL2 = 15.0;


   -(void)setupSegmentButtons

    CGFloat Y_POS_BTN = [[UIApplication sharedApplication] statusBarFrame].size.height+5;

//=== The view where the buttons sits
navigationView = [[UIView alloc]initWithFrame:CGRectMake(0,Y_POS_BTN,self.view.frame.size.width,HEIGHT_BTN)];
navigationView.backgroundColor = [UIColor whiteColor];

[self.view addSubview:navigationView]; //=== Create a View called navigationView

//==== Setup the shadows
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:self.navigationView.bounds];
self.navigationView.layer.masksToBounds = NO;
self.navigationView.layer.shadowColor = [UIColor lightGrayColor].CGColor;
self.navigationView.layer.shadowOffset = CGSizeMake(5.0f, 5.0f);
self.navigationView.layer.shadowOpacity = 0.8f;
self.navigationView.layer.shadowPath = shadowPath.CGPath;

//=== Get the dates and formatting of the dates
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *beginningOfThisWeek;
NSTimeInterval durationOfWeek;

[calendar rangeOfUnit:NSWeekCalendarUnit
            startDate:&beginningOfThisWeek
             interval:&durationOfWeek
              forDate:now];

NSDateComponents *comps = [calendar components:NSUIntegerMax fromDate:now];

NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"dd/MM/YYYY"];
NSDateFormatter *datelblFormat = [[NSDateFormatter alloc] init];
[datelblFormat setDateFormat:@"dd"];
NSDateFormatter *daylblFormat= [[NSDateFormatter alloc] init];
[daylblFormat setDateFormat:@"EEE"];

//=== Loop 7 times to create the Buttons and the 2 lines Labels
for (int i = 0; i<numControllers; i++) 

    UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(i*(self.navigationView.frame.size.width/numControllers), 0, (self.navigationView.frame.size.width/numControllers),HEIGHT_BTN)];

    [navigationView addSubview:button]; //=== Put the buttons into the navigation View

    NSString *dateString = [dateFormatter stringFromDate:[calendar dateFromComponents:comps]];
    [dtDate addObject:dateString];

    NSString *lblDate = [datelblFormat stringFromDate:[calendar dateFromComponents:comps]];

    firstLineButton = [[UILabel alloc] initWithFrame:CGRectMake(0,5,self.view.frame.size.width/numControllers,HEIGHT_LABEL)];

    firstLineButton.text = lblDate;
    firstLineButton.font = [UIFont systemFontOfSize:20];
    firstLineButton.textColor = [UIColor whiteColor];
    firstLineButton.textAlignment=NSTextAlignmentCenter;
    [button addSubview:firstLineButton]; //=== Put the Date in the 1st line of the the button

    NSString *lblDay = [daylblFormat stringFromDate:[calendar dateFromComponents:comps]];

    UILabel *secondLineButton = [[UILabel alloc] initWithFrame:CGRectMake(0,28,self.view.frame.size.width/numControllers,HEIGHT_LABEL2)];
    secondLineButton.text = lblDay;
    secondLineButton.textColor = [UIColor whiteColor];
    secondLineButton.font = [UIFont boldSystemFontOfSize:11];
    secondLineButton.textAlignment=NSTextAlignmentCenter;
    [button addSubview:secondLineButton]; //=== Put the Day in the 2nd line of the Button

    button.tag = i; //--- IMPORTANT: if you make your own custom buttons, you have to tag them appropriately

    button.backgroundColor = [UIColor colorWithRed:236.0f/255.0f green:0/255.0f blue:140.0f/255.0f alpha:0.6];//%%% buttoncolors

    [button addTarget:self action:@selector(tapSegmentButtonAction:) forControlEvents:UIControlEventTouchUpInside];

    ++comps.day;


[self setupSelector]; //=== The selection bar or highligthed area


//=== sets up the selection bar under the buttons or the highligted buttons on the navigation bar
-(void)setupSelector 

    //CGFloat Y_POS_BTN = [[UIApplication sharedApplication] statusBarFrame].size.height+5;
    selectionBar = [[UIView alloc]initWithFrame:CGRectMake(0, Y_BUFFER, (self.view.frame.size.width/numControllers),HEIGHT_BTN)];
    selectionBar.backgroundColor = [UIColor colorWithRed:236.0f/255.0f green:0/255.0f blue:140.0f/255.0f alpha:0.6]; //%%% sbcolor
    //selectionBar.alpha = 0.8; //%%% sbalpha
    [navigationView addSubview:selectionBar];


//=== When the top button is tapped
#pragma mark Setup
 -(void)tapSegmentButtonAction:(UIButton *)button 

    sDtDate = dtDate[button.tag];

    [self LoadClasses];

    __weak typeof(self) weakSelf = self;
    [weakSelf updateCurrentPageIndex:button.tag];

    NSInteger xCoor = selectionBar.frame.size.width*self.currentPageIndex;

    selectionBar.frame = CGRectMake(xCoor, selectionBar.frame.origin.y, selectionBar.frame.size.width, selectionBar.frame.size.height);

【问题讨论】:

为什么不使用 UISegmentedControl? 【参考方案1】:

好吧,我更喜欢一种更优雅的方式来实现这一点。

首先,创建一个UIButton 子类(比如说WeekdayButton),它将从NSDate 生成一个属性标题并进行配置,使其能够显示具有不同字体的多行标题。

WeekdayButton.h

#import <UIKit/UIKit.h>

@interface WeekdayButton : UIButton

@property (strong, nonatomic) NSDate *date;

@end

WeekdayButton.m

#import "WeekdayButton.h"

@implementation WeekdayButton

static NSDateFormatter *dayFormatter;
static NSDateFormatter *weekFormatter;

- (instancetype)initWithFrame:(CGRect)frame 
    self = [super initWithFrame:frame];
    [self setup];
    return self;


- (void)awakeFromNib 
    [super awakeFromNib];
    [self setup];


- (void)setup 
    self.titleLabel.numberOfLines = 2;
    self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
    self.titleLabel.textAlignment = NSTextAlignmentCenter;
    self.backgroundColor = [UIColor colorWithRed:236.0f/255.0f green:0/255.0f blue:140.0f/255.0f alpha:0.6];



- (void)setDate:(NSDate *)date 
    _date = date;

    NSAttributedString *normalTitle = [self generateNormalTitle];;
    NSAttributedString *selectedTitle = [self generateSelectedTitle];

    [self setAttributedTitle:normalTitle forState:UIControlStateNormal];
    [self setAttributedTitle:selectedTitle forState:UIControlStateSelected];


- (NSAttributedString *)generateNormalTitle 
    NSMutableAttributedString *result = [NSMutableAttributedString new];

    if (!dayFormatter) 
        dayFormatter = [NSDateFormatter new];
        dayFormatter.dateFormat = @"dd";
    

    if (!weekFormatter) 
        weekFormatter = [NSDateFormatter new];
        weekFormatter.dateFormat = @"EEE";
    

    NSString *day = [[dayFormatter stringFromDate:self.date] stringByAppendingString:@"\n"];
    NSString *week = [weekFormatter stringFromDate:self.date];

    [result appendAttributedString:[[NSAttributedString alloc] initWithString:day
                                                                   attributes:@NSFontAttributeName:[UIFont systemFontOfSize:20]]];

    [result appendAttributedString:[[NSAttributedString alloc] initWithString:week
                                                                   attributes:@NSFontAttributeName:[UIFont boldSystemFontOfSize:11]]];

    [result addAttribute:NSForegroundColorAttributeName value:[UIColor whiteColor] range:NSMakeRange(0, result.length)];

    return result;


- (NSAttributedString *)generateSelectedTitle 
    NSMutableAttributedString *result = [[self generateNormalTitle] mutableCopy];
    [result addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(0, result.length)];
    return result;


@end

然后在你的 ViewController 中创建一个水平的UIStackView,从今天开始生成 7 个WeekdayButton 按钮并传递NSDate 对象。

ViewController.m

#import "ViewController.h"
#import "WeekdayButton.h"

@interface ViewController ()

@property (strong, nonatomic) UIStackView *stackView;

@end

@implementation ViewController

- (void)viewDidLoad 
    [super viewDidLoad];
    [self setupWeekDayButtons];


- (void)setupWeekDayButtons 

    UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 40, self.view.frame.size.width, 55)];
    containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    [self.view addSubview:containerView];

    containerView.layer.shadowRadius = 5;
    containerView.layer.shadowColor = [UIColor blackColor].CGColor;
    containerView.layer.shadowOpacity = 0.5;
    containerView.layer.shadowOffset = CGSizeMake(0, 5);

    self.stackView = [[UIStackView alloc] initWithFrame:containerView.bounds];
    self.stackView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    self.stackView.axis = UILayoutConstraintAxisHorizontal;
    self.stackView.distribution = UIStackViewDistributionFill;
    self.stackView.spacing = 0;
    [containerView addSubview:self.stackView]; //Embeding stackview in a UIView cause UIStackView can't draw shadow.

    int numberOfDays = 7;
    for (int i = 0; i < numberOfDays; i++) 
        NSDate *date = [[NSDate date] dateByAddingTimeInterval:i * 24 * 3600];
        WeekdayButton *button = [WeekdayButton buttonWithType:UIButtonTypeCustom];
        [button addTarget:self action:@selector(weekDayTapped:) forControlEvents:UIControlEventTouchUpInside];
        button.date = date;
        button.translatesAutoresizingMaskIntoConstraints = NO;
        [self.stackView addArrangedSubview:button];
        [button.widthAnchor constraintEqualToAnchor:self.stackView.widthAnchor
                                         multiplier:1/(CGFloat)numberOfDays].active = YES;

        if (i != numberOfDays - 1) 
            UIView *separator = [UIView new];
            separator.translatesAutoresizingMaskIntoConstraints = NO;
            separator.backgroundColor = [UIColor whiteColor];
            [button addSubview:separator];

            [separator.widthAnchor constraintEqualToConstant:1].active = true;
            [separator.trailingAnchor constraintEqualToAnchor:button.trailingAnchor constant:0].active = YES;
            [separator.centerYAnchor constraintEqualToAnchor:button.centerYAnchor constant:0].active = YES;
            [separator.heightAnchor constraintEqualToAnchor:button.heightAnchor multiplier:1 constant:-20].active = YES;
        
    


- (void)weekDayTapped:(WeekdayButton *)sender 
    [self.stackView.arrangedSubviews makeObjectsPerformSelector:@selector(setSelected:) withObject:nil]; //Deselecting all buttons
    sender.selected = YES; 

    NSLog(@"Selected: %@", sender.date);
    //TODO: Do your logic after selection here


@end

结果如下:

【讨论】:

【参考方案2】:

我在这里通过堆栈视图和自动布局的力量提供答案

代码将受到限制,您几乎可以自定义 IB 中的所有内容。 设置选中状态时可能需要注意按钮的色调。

-(IBAction)selector:(id)sender
    UIButton * button = (UIButton *)sender;
    [button setSelected:  !button.isSelected ];
 

setting in IB

selected State

topstackview second stack view

使用这个想法,您可以更快、更安全地构建您的示例。

【讨论】:

嗨 E.Coms,欢迎来到 SO!请注意,SO 社区不赞成大多数是图像的答案,因为它严重降低了您的答案的可发现性。 Xcode 设置对话框的图像尤其成问题,因为它没有突出显示 important 设置。请考虑用答案的关键部分替换或增加这些图像。感谢您的贡献!【参考方案3】:

对于:“如何在按钮之间添加分隔符或垂直线”: 在[button addSubview:secondLineButton]; //=== Put the Day in the 2nd line of the Button之后添加一个视图作为分隔符

if (i < (numControllers - 1))  
    UIView *separator = [[UIView alloc] initWithFrame:CGRectMake(button.frame.size.width - 1, 5, 1, button.frame.size.height - 10))];  
        separator.backgroundColor = UIColor.whiteColor
        [button addSubview:separator];  

对于文本颜色,创建:btnCurrentSelected 和:

@interface YouClass : UIViewController

    UIButton *btnCurrentSelected;





 -(void)tapSegmentButtonAction:(UIButton *)button 

    sDtDate = dtDate[button.tag];

    [self LoadClasses];
    [btnCurrentSelected setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal] // set color for old button selected
    btnCurrentSelected = button
    [btnCurrentSelected setTitleColor:[UIColor blueColor] forState:UIControlStateNormal] // set color for button selected

    __weak typeof(self) weakSelf = self;
    [weakSelf updateCurrentPageIndex:button.tag];

    NSInteger xCoor = selectionBar.frame.size.width*self.currentPageIndex;

    selectionBar.frame = CGRectMake(xCoor, selectionBar.frame.origin.y, selectionBar.frame.size.width, selectionBar.frame.size.height);

【讨论】:

感谢您的及时回复 如何创建btnCurrentSelected ?以及如何不绘制最后一个分隔符?我只需要六个分隔符? 不工作。标题cooler无论被选中还是未选中都是一样的。 标题颜色保持不变。我正在使用 UI 标签来创建标题。有没有办法在选择时更改标签文本颜色?【参考方案4】:

这里不需要使用UIButton,只需要自定义一个UIControl子类,里面需要自定义布局,需要在选中的Set方法里面处理高亮或者一般状态

【讨论】:

以上是关于带有分隔线的Objective C UIButton并在选择时更改文本颜色的主要内容,如果未能解决你的问题,请参考以下文章

预蜂窝上带有分隔线的 LinearLayout

带有选项卡式窗口和分隔线的 Source Insight 类型编辑器?

跨度字母不会将字母从 xml 分隔到 Objective C 中的字符串

tableview 图像未正确显示 - iOS 8 iPhone App Objective C

如何设置 ListView 分隔线的宽度?

如何更改 Android ListView 分隔线的颜色?