カスタム UIView サブクラスを使用してこれを行う方法を示す小さなサンプルをまとめました。以下の例では、この回答の AutoLayout フレームワークを使用しました。同じことをお勧めします。これにより、制約コードがクリーンで読みやすくなります。
一般的なアプローチは、左側のボタンの後縁を右側のボタンの前縁にバインドするキー制約へのポインターを保持し、それらのポインターを使用して制約を動的に追加/削除する必要があるということです。一般に、パフォーマンスが低下するため、あまり多くのことを行うことは望ましくありませんが、ユーザーのアクションに応じて少量を行うことは問題ありません。
私の見解は次のように宣言されています。
@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
ビューを実際に機能させるには、さらに多くの作業を行う必要がありますが、一般的なアプローチを理解していただければ幸いです。