【问题标题】:Gracefully hiding and showing views when using autolayout使用自动布局时优雅地隐藏和显示视图
【发布时间】:2013-03-06 17:30:44
【问题描述】:

我认为可能有一种方法可以使用自动布局轻松隐藏和显示连续的按钮,以便可以根据可见的视图自动整齐地排列视图。

例如,假设我有两个按钮,我总是希望在框架中居中:

// pseudo visual format code:
|-----[star][download]-----|

当我按下下载按钮时,我现在希望看到三个按钮:(pause 是重新标记的 download 按钮;cancel 是以前隐藏的按钮)

|--[star][cancel][pause ]--|

我想我也许可以让所有三个按钮始终存在,但可能会覆盖宽度以使视图在状态之间优雅地动画?我认为可能有一种更语义化的方式来实现从自动布局结构中添加和删除视图。有什么想法吗?

【问题讨论】:

标签: ios autolayout


【解决方案1】:

我整理了一个小示例,展示了如何使用自定义 UIView 子类完成此操作。在下面的示例中,我使用了来自this answerAutoLayout framework,我建议您也这样做;它使约束代码保持清晰易读。

一般的方法是,您必须保留指向键约束的指针,这些键约束将左侧按钮的后缘绑定到右侧按钮的前缘,然后使用这些指针动态添加/删除约束。通常,您不希望这样做太多,因为性能会受到影响,但响应用户操作的少量操作是可以的。

我的观点是这样声明的:

@protocol TSDownloadViewDelegate;
@interface TSDownloadView : UIView
  @property (strong, nonatomic)          id<TSDownloadViewDelegate> delegate;
@end

@protocol TSDownloadViewDelegate <NSObject>
  - (void) downloadStartedInDownloadView:(TSDownloadView*)downloadView;
  - (void) downloadPausedInDownloadView:(TSDownloadView *)downloadView;
  - (void) downloadCancelledInDownloadView:(TSDownloadView*)downloadView;
@end

并像这样实现:

#import "UIView+AutoLayout.h"
#import "TSDownloadView.h"

static const CGFloat        kMargin                = 20.0;

@interface TSDownloadView ()

    // Our buttons
    @property (strong, nonatomic)          UIButton *   starButton;
    @property (strong, nonatomic)          UIButton *   cancelButton;
    @property (strong, nonatomic)          UIButton *   downloadButton;

    // State tracking
    @property (nonatomic)                  BOOL         downloading;
    @property (nonatomic)                  BOOL         constraintsUpdated;

    // The constraint governing what's tied to the right hand side of the starButton
    @property (weak, nonatomic)            NSLayoutConstraint *starRightConstraint;

    // The constraint governing what's tied to the left hand side of the downloadButton
    @property (weak, nonatomic)            NSLayoutConstraint *downloadLeftConstraint;

@end

@implementation TSDownloadView

- (void) initializator
{
    _starButton = [UIButton buttonWithType:UIButtonTypeSystem];
    _cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
    _downloadButton = [UIButton buttonWithType:UIButtonTypeSystem];

    _starButton.translatesAutoresizingMaskIntoConstraints = NO;
    _cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
    _downloadButton.translatesAutoresizingMaskIntoConstraints = NO;

    _starButton.titleLabel.textAlignment = NSTextAlignmentCenter;
    _cancelButton.titleLabel.textAlignment = NSTextAlignmentCenter;
    _downloadButton.titleLabel.textAlignment = NSTextAlignmentCenter;

    [_starButton setTitle:@"Star" forState:UIControlStateNormal];
    [_cancelButton setTitle:@"Cancel" forState:UIControlStateNormal];
    [_downloadButton setTitle:@"Download" forState:UIControlStateNormal];

    [_downloadButton addTarget:self action:@selector(downloadClicked:) forControlEvents:UIControlEventTouchUpInside];

    [self addSubview:_starButton];
    [self addSubview:_cancelButton];
    [self addSubview:_downloadButton];

    _cancelButton.hidden = YES;

}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        [self initializator];
    }
    return self;
}

- (id) initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if( self )
    {
        [self initializator];
    }
    return self;
}


- (void)downloadClicked:(id)sender
{
    self.downloading = !self.downloading;
    if( self.downloading )
    {
        [self.downloadButton setTitle:@"Pause" forState:UIControlStateNormal];
        self.cancelButton.hidden = NO;

        // Remove previous constraints
        [self removeConstraint:self.starRightConstraint];
        [self removeConstraint:self.downloadLeftConstraint];

        // |--[star][cancel][pause ]--|
        self.starRightConstraint = [self.starButton autoPinEdge:ALEdgeRight toEdge:ALEdgeLeft ofView:self.cancelButton withOffset:-kMargin];
        self.downloadLeftConstraint = [self.downloadButton autoPinEdge:ALEdgeLeft toEdge:ALEdgeRight ofView:self.cancelButton withOffset:kMargin];

        // Tell delegate what's happened
        if( self.delegate )
            [self.delegate downloadStartedInDownloadView:self];
    }
    else
    {
        [self.downloadButton setTitle:@"Download" forState:UIControlStateNormal];
        self.cancelButton.hidden = YES;

        // Remove previous constraints
        [self removeConstraint:self.starRightConstraint];
        [self removeConstraint:self.downloadLeftConstraint];

        // |-----[star][download]-----|
        self.starRightConstraint = [self.starButton autoPinEdge:ALEdgeRight toEdge:ALEdgeLeft ofView:self.downloadButton withOffset:-kMargin];
        self.downloadLeftConstraint = nil;

        // Tell delegate what's happened
        if( self.delegate )
            [self.delegate downloadPausedInDownloadView:self];
    }

}

- (void) updateConstraints
{
    [super updateConstraints];
    if( self.constraintsUpdated ) return;
        self.constraintsUpdated = YES;

    // Now put our constraints in place

    // Make sure the button hugs the label and doesn't get stretched
    // just because there's space available
    [self.starButton setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];

    // Pin the starButton to the top, left and bottom edges of its superview
    [self.starButton autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:kMargin];
    [self.starButton autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:kMargin];
    [self.starButton autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:kMargin];

    // Repeat for the other buttons

    [self.cancelButton setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
    [self.cancelButton autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:kMargin];
    [self.cancelButton autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:kMargin];

    [self.downloadButton setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
    [self.downloadButton autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:kMargin];
    [self.downloadButton autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:kMargin];
    [self.downloadButton autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:kMargin];


    // These two are special. We keep a reference to them so we can replace
    // them later. Note that since the cancelButton is hidden at the start,
    // the initial value for downloadLeftConstraint is simply nil.

    self.starRightConstraint = [self.starButton autoPinEdge:ALEdgeRight toEdge:ALEdgeLeft ofView:self.downloadButton withOffset:-kMargin];
    self.downloadLeftConstraint = nil;
}
@end

要使视图真正发挥作用,还有很多工作要做,但希望您能看到要采取的一般方法。

【讨论】:

    【解决方案2】:

    使用自动布局设计(5)个按钮。

    //在 ViewDidLoad 上:设置取消和暂停按钮隐藏

    -(void) viewDidLoad
    {
       [_pauseBtn setHidden:YES];
       [_cancelBtn setHidden:YES];
    }
    

    //关于下载动作

    -(IBAction) downloadClick (UIButton *) sender
    {
        [_pauseBtn setHidden:NO];
        [_cancelBtn setHidden:NO];
        [sender setHidden:YES];
    }
    

    【讨论】:

      【解决方案3】:

      【讨论】:

      • 你有没有找到任何方法来实现这一点?我也被困在同一个问题上。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-18
      • 1970-01-01
      • 2013-08-06
      • 2014-04-04
      • 1970-01-01
      相关资源
      最近更新 更多