簡體   English   中英

iOS / Objective-C:以編程方式在按鈕下居中

[英]IOS/Objective-C: Center Line under Button Programmatically

我試圖在三個按鈕下創建一條簡單的線以創建Tabs效果。 雖然我可以在Storyboard中做到這一點,但我想在代碼中做到這一點,並且理想情況下,使該行成為該視圖中已經存在的元素的子視圖,以避免不得不對其進行特殊約束。

我的方法是創建一個沒有文本和背景色的UILabel。 我可以使UILabel成為View的子視圖,但是,它不會將其附加到按鈕的底部。

另一方面,如果將UILabel設為按鈕之一的子視圖,則看不到它。

誰能建議一個簡單的方法來做到這一點?

[centerButton setTitle:@"Favorites" forState:UIControlStateNormal];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 120, 280, 2)];
            label.backgroundColor = [UIColor redColor];
            label.textAlignment = NSTextAlignmentCenter;
             label.numberOfLines = 1;
             label.text = @"";
            [self.view addSubview: label];

在此先感謝您的任何建議。

編輯:

我嘗試以編程方式添加一些NSLayoutConstraints:

    NSLayoutConstraint *con3 = [NSLayoutConstraint
                                constraintWithItem:label attribute:NSLayoutAttributeTop
                                relatedBy:NSLayoutRelationEqual toItem:centerButton
                                attribute:NSLayoutAttributeBottom multiplier:1 constant:0];

    [label addConstraints:@[con3]];
//tried with and without
    [self.view layoutIfNeeded];

這返回了異常:

     [LayoutConstraints] The view hierarchy is not prepared
 for the constraint: <NSLayoutConstraint:0x174e85500 V:
[UIButton:0x100b0baf0'Now']-(0)-[UILabel:0x108555160] 
  (inactive)>
        When added to a view, the constraint's items
 must be descendants of that view (or the view itself). 
This will crash if the constraint needs to be resolved 
before the view hierarchy is assembled. 
Break on -[UIView(UIConstraintBasedLayout) 
_viewHierarchyUnpreparedForConstraint:] to debug.

在情節提要中創建的按鈕是self.view的子視圖,我將標簽添加為self.view作為代碼中的子視圖,因此不確定為什么會發生異常。

我從錯誤消息中懷疑,您是否可能在將redLabel視圖添加到其parentView之前(或者生命周期的早期)嘗試添加NSLayoutConstraint。 無論如何,我認為這與您要完成的工作非常接近:

#import "ViewController.h"

@interface ViewController ()
@property (strong, nullable) UILabel *previousRedLabel;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (IBAction)buttonClicked:(id)sender {
    if ([sender isKindOfClass:[UIButton class]]) {
        UIButton *clickedButton = (UIButton *)sender;
        UIView *buttonSuperview = [clickedButton superview];
        if (buttonSuperview != nil) {
            [self _putRedLineWithHeight:3.0f atTheBottomOfView:buttonSuperview animate:YES];
        }
    }
}

- (void)_putRedLineWithHeight:(CGFloat)height atTheBottomOfView:(UIView *)viewToPutUnder animate:(BOOL)animate {
    // remove our previous red line
    if (self.previousRedLabel) {
        // if you want it to be a no-op here if they click the same button
        // you'll need to add some logic to check if the superView == viewToPutUnder
        [self.previousRedLabel removeFromSuperview];
        self.previousRedLabel = nil;
    }
    UILabel *redLabel = [[UILabel alloc] init];
    // we're using autolayout so we don't want any resizing from it
    redLabel.translatesAutoresizingMaskIntoConstraints = NO;
    redLabel.backgroundColor = [UIColor redColor];
    // start out with alpha = 0
    redLabel.alpha = 0.0f;
    // add it to our parentView
    [viewToPutUnder addSubview:redLabel];
    // height (determined by passed in value)
    NSAssert(height >= 0, @"Height must be a positive number");
    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:redLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:height];
    // width equal to parentView's width
    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:viewToPutUnder attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:redLabel attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f];
    // center x == parentView's center x
    NSLayoutConstraint *centerConstraint = [NSLayoutConstraint constraintWithItem:viewToPutUnder attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:redLabel attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f];
    // now the bottom constraint (place it at the bottom of the parent view)
    NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:viewToPutUnder attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:redLabel attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];
    // add the height constraint to our label
    [redLabel addConstraint:heightConstraint];
    // and all the other constraints to our parent view
    [viewToPutUnder addConstraints:@[widthConstraint, centerConstraint, bottomConstraint]];
    redLabel.alpha = 1.0f;
    if (animate) {
        [UIView animateWithDuration:0.6f animations:^{
            [redLabel layoutIfNeeded];
        }];
    }
    self.previousRedLabel = redLabel;
}

動畫示例:

在此處輸入圖片說明

以及非動畫之一:

在此處輸入圖片說明

如果每個按鈕都不在SUPERVIEW中,則可以通過編輯后的答案進行處理

針對所有按鈕都在一個視圖中進行了調整(基於按鈕寬度的寬度,從中心到按鈕中心以及將標簽頂部固定到按鈕底部的寬度)

#import "ViewController.h"

@interface ViewController ()
@property (strong, nullable) UILabel *previousRedLabel;
- (void)_putRedLineWithHeight:(CGFloat)height atTheBottomOfButton:(UIButton *)button animate:(BOOL)animate;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (IBAction)buttonClicked:(id)sender {
    if ([sender isKindOfClass:[UIButton class]]) {
        UIButton *clickedButton = (UIButton *)sender;
        // if you want it to be a no-op here if they click the same button
        // you'll need to add some logic to store the previous clicked button and check whether it's the same button
        [self _putRedLineWithHeight:3.0f atTheBottomOfButton:clickedButton animate:YES];
    }
}

- (void)_putRedLineWithHeight:(CGFloat)height atTheBottomOfButton:(UIButton *)button animate:(BOOL)animate {
    UIView *buttonSuperview = button.superview;
    NSAssert(buttonSuperview != nil, @"Button has to have a superview");
    // remove our previous red line
    if (self.previousRedLabel) {
        [self.previousRedLabel removeFromSuperview];
        self.previousRedLabel = nil;
    }
    UILabel *redLabel = [[UILabel alloc] init];
    // we're using autolayout so we don't want any resizing from it
    redLabel.translatesAutoresizingMaskIntoConstraints = NO;
    redLabel.backgroundColor = [UIColor redColor];
    // start out with alpha = 0
    redLabel.alpha = 0.0f;
    // add it to our parentView
    [buttonSuperview addSubview:redLabel];
    // height (determined by passed in value)
    NSAssert(height >= 0, @"Height must be a positive number");
    NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:redLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:height];
    // width equal to button's width
    NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:redLabel attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f];
    // center x == button's center x
    NSLayoutConstraint *centerConstraint = [NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:redLabel attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f];
    // now pin the top of the label to the bottom of the button
    NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:redLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:button attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];
    // add the height constraint to our label
    [redLabel addConstraint:heightConstraint];
    // and all the other constraints to our parent view
    [buttonSuperview addConstraints:@[widthConstraint, centerConstraint, bottomConstraint]];
    redLabel.alpha = 1.0f;
    if (animate) {
        [UIView animateWithDuration:0.6f animations:^{
            [redLabel layoutIfNeeded];
        }];
    }
    self.previousRedLabel = redLabel;
}


@end

動畫:

在此處輸入圖片說明

不動畫:

在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM