私はカスタムCellをIBで設計し、それをサブクラス化し、そして私のアウトレットを私のカスタムクラスに接続しました。 UIView(cdView)と2つのラベル(titleLabelおよびemailLabel)というセルコンテンツに3つのサブビューがあります。各行で利用できるデータによっては、UIViewと2つのラベルを自分のセルに表示したい場合と、2つのラベルだけを表示したい場合があります。 UIViewプロパティを非表示に設定したり、スーパービューから削除したりすると、2つのラベルが左に移動します。次のビュー(UIView)には、UIViewの先頭の制約を10pxのスーパービュー(セルの内容)に設定し、UILabelsの先頭に10pxの制約を設定しようとしました。私のコードの後半
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(IndexPath *)indexPath {
...
Record *record = [self.records objectAtIndex:indexPath.row];
if ([record.imageURL is equalToString:@""]) {
cell.cdView.hidden = YES;
}
私は自分のcell.cdViewを隠していて、ラベルを左に移動したいのですが、それらはCellの同じ位置に留まっています。私はsuperviewからcell.cdViewを削除しようとしましたが、それはどちらもうまくいきませんでした。私は自分が何をしているのかを明確にするために画像を添付しました。
私はプログラム的にこれを行う方法を知っています、そして私はその解決策を探していません。私が欲しいのはIBで制約を設定することです、そして私は私のサブビューが他のビューが削除されるか隠されるなら動的に動くと期待します。自動レイアウトを使用してIBでこれを行うことは可能ですか?
.....
それは可能ですが、あなたはもう少し余分な仕事をしなければならないでしょう。最初に邪魔にならないようにするための概念的なことが2つあります。
あなたの場合、これはおそらく以下のことを意味します。
あなたがする必要があるのはあなたのラベルを慎重に過度に制約するです。既存の制約(他のビューへの10ポイントのスペース)をそのままにして、別の制約を追加します。ラベルの左端をスーパービューの左エッジから10ポイント離して不必要な優先度で設定します。
次に、それらを左に移動させたいときは、左側のビューを完全に削除します。左側のビューに対する必須の10pt制約は、それが関連するビューと一緒に表示されなくなり、ラベルがスーパービューから10pt離れているという優先順位の高い制約だけが残ります。次のレイアウトパスでは、スーパービューの幅いっぱいになるまで左に拡大しますが、端の周囲にはスペースが必要です。
1つの重要な注意点:もしあなたがあなたの左のビューを図の中に戻したいのなら、それをビューの階層に追加し直さなければならないだけでなく、同時に{そのすべての制約を再確立するこれは、そのビューが再び表示されるたびに、ビューとそのラベルの間の10ポイントの間隔の制約を元に戻す方法が必要であることを意味します。
実行時に制約を追加または削除することは、パフォーマンスに影響を与える可能性がある重い操作です。しかし、もっと簡単な方法があります。
非表示にしたいビューに対して、幅の制限を設定します。他のビューを、そのビューに対して水平方向の間隔を空けて拘束します。
非表示にするには、width制約の.constant
を0.fに更新します。他のビューは自動的に左に移動して位置を決めます。
詳細については私の他の答えをここに見なさい:
iOS 8 +のみをサポートする人のために、新しいブール型プロパティ active があります。必要な制約だけを動的に有効にするのに役立ちます
P.S拘束アウトレットは強い、弱いではない
例:
@IBOutlet weak var optionalView: UIView!
@IBOutlet var viewIsVisibleConstraint: NSLayoutConstraint!
@IBOutlet var viewIsHiddenConstraint: NSLayoutConstraint!
func showView() {
optionalView.isHidden = false
viewIsVisibleConstraint.isActive = true
viewIsHiddenConstraint.isActive = false
}
func hideView() {
optionalView.isHidden = true
viewIsVisibleConstraint.isActive = false
viewIsHiddenConstraint.isActive = true
}
ストーリーボードのエラーを修正するには、これらの制約の1つについてInstalled
チェックボックスをオフにする必要があります。
UIStackView(iOS 9以降)
もう1つの選択肢は、あなたの見解をUIStackView
でラップすることです。ビューが隠されるとUIStackView
は自動的にレイアウトを更新します
いずれかのサブビューでUIStackView
プロパティが変更されると、hidden
は自動的にビューの位置を変更します(iOS 9以降)。
UIView.animateWithDuration(1.0) { () -> Void in
self.mySubview.hidden = !self.mySubview.hidden
}
デモを見るには、このWWDCビデオの 11:48 に移動します。
私のプロジェクトはUILabel
のカスタム@IBDesignable
サブクラスを使い(色、フォント、インセットなどの一貫性を保つため)、私は次のようなものを実装しました:
override func intrinsicContentSize() -> CGSize {
if hidden {
return CGSizeZero
} else {
return super.intrinsicContentSize()
}
}
これにより、ラベルサブクラスは自動レイアウトに参加できますが、非表示の場合はスペースを取りません。
Google社員向け:Maxの答えを基に、多くの人が気付いたパディングの問題を解決するために、単にラベルの高さを増やして実際のパディングではなく区切り文字。この考えは、ビューを含むことで、どんなシナリオにも拡張できます。
これは簡単な例です:
この場合、Authorラベルの高さを適切なIBOutlet
にマッピングします。
@property (retain, nonatomic) IBOutlet NSLayoutConstraint* authorLabelHeight;
制約の高さを0.0f
に設定すると、Playボタンの高さで許容されるため、 "padding"が維持されます。
私がやってしまったのは2 xibを作成することでした。 1つは左側のビュー、もう1つはそれなしです。両方ともコントローラーに登録してから、cellForRowAtIndexPathの中でどちらを使用するかを決めました。
それらは同じUITableViewCellクラスを使用します。欠点は、xib間でコンテンツの重複があることですが、これらのセルはかなり基本的なものです。利点は、ビューの削除、制約の更新などを手動で管理するためのコードがないことです。
一般的に、これは技術的に異なるレイアウトであり、したがって異なるxibを持つべきであるので、おそらくより良い解決策です。
[self.table registerNib:[UINib nibWithNibName:@"TrackCell" bundle:nil] forCellReuseIdentifier:@"TrackCell"];
[self.table registerNib:[UINib nibWithNibName:@"TrackCellNoImage" bundle:nil] forCellReuseIdentifier:@"TrackCellNoImage"];
TrackCell *cell = [tableView dequeueReusableCellWithIdentifier:(appDelegate.showImages ? @"TrackCell" : @"TrackCellNoImage") forIndexPath:indexPath];
uiviewとラベル間の制約をIBOutletとして接続し、hidden = YESに設定されている場合は優先順位メンバーをより小さい値に設定
これを試してください、私は以下のコードを実装しました、
私は他の3つのビューを追加したという点でViewControllerで1つのビューを持っています。 、
1.ViewController.hファイル
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIView *viewOne;
@property (strong, nonatomic) IBOutlet UIView *viewTwo;
@property (strong, nonatomic) IBOutlet UIView *viewThree;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewOneWidth;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewTwoWidth;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewThreeWidth;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewBottomWidth;
@end
2.ViewController.m
#import "ViewController.h"
@interface ViewController ()
{
CGFloat viewOneWidthConstant;
CGFloat viewTwoWidthConstant;
CGFloat viewThreeWidthConstant;
CGFloat viewBottomWidthConstant;
}
@end
@implementation ViewController
@synthesize viewOne, viewTwo, viewThree;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a
nib.
/*
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
*/
// [viewOne setHidden:NO];
// [viewTwo setHidden:NO];
// [viewThree setHidden:NO];
// [viewOne setHidden:NO];
// [viewTwo setHidden:NO];
// [viewThree setHidden:YES];
// [viewOne setHidden:NO];
// [viewTwo setHidden:YES];
// [viewThree setHidden:NO];
// [viewOne setHidden:NO];
// [viewTwo setHidden:YES];
// [viewThree setHidden:YES];
// [viewOne setHidden:YES];
// [viewTwo setHidden:NO];
// [viewThree setHidden:NO];
// [viewOne setHidden:YES];
// [viewTwo setHidden:NO];
// [viewThree setHidden:YES];
// [viewOne setHidden:YES];
// [viewTwo setHidden:YES];
// [viewThree setHidden:NO];
// [viewOne setHidden:YES];
// [viewTwo setHidden:YES];
// [viewThree setHidden:YES];
[self hideShowBottomBar];
}
- (void)hideShowBottomBar
{
BOOL isOne = !viewOne.isHidden;
BOOL isTwo = !viewTwo.isHidden;
BOOL isThree = !viewThree.isHidden;
viewOneWidthConstant = _viewOneWidth.constant;
viewTwoWidthConstant = _viewTwoWidth.constant;
viewThreeWidthConstant = _viewThreeWidth.constant;
viewBottomWidthConstant = _viewBottomWidth.constant;
if (isOne && isTwo && isThree) {
// 0 0 0
_viewOneWidth.constant = viewBottomWidthConstant / 3;
_viewTwoWidth.constant = viewBottomWidthConstant / 3;
_viewThreeWidth.constant = viewBottomWidthConstant / 3;
}
else if (isOne && isTwo && !isThree) {
// 0 0 1
_viewOneWidth.constant = viewBottomWidthConstant / 2;
_viewTwoWidth.constant = viewBottomWidthConstant / 2;
_viewThreeWidth.constant = 0;
}
else if (isOne && !isTwo && isThree) {
// 0 1 0
_viewOneWidth.constant = viewBottomWidthConstant / 2;
_viewTwoWidth.constant = 0;
_viewThreeWidth.constant = viewBottomWidthConstant / 2;
}
else if (isOne && !isTwo && !isThree) {
// 0 1 1
_viewOneWidth.constant = viewBottomWidthConstant;
_viewTwoWidth.constant = 0;
_viewThreeWidth.constant = 0;
}
else if (!isOne && isTwo && isThree) {
// 1 0 0
_viewOneWidth.constant = 0;
_viewTwoWidth.constant = viewBottomWidthConstant / 2;
_viewThreeWidth.constant = viewBottomWidthConstant / 2;
}
else if (!isOne && isTwo && !isThree) {
// 1 0 1
_viewOneWidth.constant = 0;
_viewTwoWidth.constant = viewBottomWidthConstant;
_viewThreeWidth.constant = 0;
}
else if (!isOne && !isTwo && isThree) {
// 1 1 0
_viewOneWidth.constant = 0;
_viewTwoWidth.constant = 0;
_viewThreeWidth.constant = viewBottomWidthConstant;
}
else if (isOne && isTwo && isThree) {
// 1 1 1
_viewOneWidth.constant = 0;
_viewTwoWidth.constant = 0;
_viewThreeWidth.constant = 0;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
それでこの論理が誰かに役立つことを願っています。
私の場合は、高さ制約の定数を0.0f
に設定し、またhidden
プロパティをYES
に設定します。
ビューを(サブビュー付きで)再度表示するには、反対の操作を行いました。高さ定数をゼロ以外の値に設定し、hidden
プロパティをNO
に設定します。
No_sceneが示唆しているように、実行時に制約の優先順位を変更することでこれを確実に行うことができます。削除しなければならないビューが複数あるため、これは私にとってはずっと簡単でした。
これがReactiveCocoaを使ったスニペットです。
RACSignal* isViewOneHiddenSignal = RACObserve(self.viewModel, isViewOneHidden);
RACSignal* isViewTwoHiddenSignal = RACObserve(self.viewModel, isViewTwoHidden);
RACSignal* isViewThreeHiddenSignal = RACObserve(self.viewModel, isViewThreeHidden);
RAC(self.viewOne, hidden) = isViewOneHiddenSignal;
RAC(self.viewTwo, hidden) = isViewTwoHiddenSignal;
RAC(self.viewThree, hidden) = isViewThreeHiddenSignal;
RAC(self.viewFourBottomConstraint, priority) = [[[[RACSignal
combineLatest:@[isViewOneHiddenSignal,
isViewTwoHiddenSignal,
isViewThreeHiddenSignal]]
and]
distinctUntilChanged]
map:^id(NSNumber* allAreHidden) {
return [allAreHidden boolValue] ? @(780) : @(UILayoutPriorityDefaultHigh);
}];
RACSignal* updateFramesSignal = [RACObserve(self.viewFourBottomConstraint, priority) distinctUntilChanged];
[updateFramesSignal
subscribeNext:^(id x) {
@strongify(self);
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:0.3 animations:^{
[self.view layoutIfNeeded];
}];
}];
私はこれが最も簡単な答えであることそれがうまくいっていることのためにそれをチェックしてください
StackFullView.layer.isHidden = true
Task_TopSpaceSections.constant = 0. //your constrain of top view
あなたの解決策を得るために私が私のuiviewsを再調整する方法は次のとおりです。
私は自分自身のサムルールを作成しました。制約が影響を受ける可能性のあるすべてのuiviewを非表示または表示する必要があるときはいつでも、uiview内にすべての影響を受ける/依存するサブビューを追加し、その先頭/末尾/上/下制約をプログラムで更新します。
これが誰かに役立つ場合には、 視覚フォーマット の制約を使うためのヘルパークラスを作りました。現在のアプリで使用しています。
それは私のニーズに少し合わせたものかもしれませんが、あなたはそれが便利だと思うかもしれませんし、あるいはあなたがそれを修正してあなた自身のヘルパーを作りたいと思うかもしれません。
私はTimに上記の 答え 、この UIScrollViewについての答え を感謝しなければなりませんまた、この チュートリアル もあります。
これを行う適切な方法は、isActive = falseで制約を無効にすることです。ただし、制約を無効にすると制約が削除されて解放されるため、強力なコンセントを用意する必要があります。
これは古い質問ですが、それでも役に立つことを願っています。 Androidから来たこのプラットフォームでは、ビューからそれを隠すための便利なメソッドisVisible
を持っていますが、自動レイアウトがビューを描くときにフレームを考慮していません。
extensionと "extend"というuiviewを使えば、iosでも似たような機能を実行することができます(なぜUIKitに含まれていないのかわからない)、ここでSwift 3の実装です。
func isVisible(_ isVisible: Bool) {
self.isHidden = !isVisible
self.translatesAutoresizingMaskIntoConstraints = isVisible
if isVisible { //if visible we remove the hight constraint
if let constraint = (self.constraints.filter{$0.firstAttribute == .height}.first){
self.removeConstraint(constraint)
}
} else { //if not visible we add a constraint to force the view to have a hight set to 0
let height = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal , toItem: nil, attribute: .notAnAttribute, multiplier: 0, constant: 0)
self.addConstraint(height)
}
self.layoutIfNeeded()
}