【问题标题】:How to hide a UIView that doesn't fit in available space?如何隐藏不适合可用空间的 UIView?
【发布时间】:2021-03-29 06:54:12
【问题描述】:

有一个包含 4 个元素的堆栈视图。

每个元素都有一个 1000 的水平内容压缩阻力优先级,除了一个:

A(1000) - B(1000) - C(999) - D(1000)

有了很大的空间,没有问题,每个视图都需要它。但是,在空间有限的情况下,C 视图会首先横向收缩以腾出空间给其他视图。

它可以缩小直到不可见:

A(1000) - B(1000) - - D(1000)

但是,B和D之间的距离虽然是不可见的,却是A和B之间距离的两倍。因为C没有被隐藏,只是缩小了。

有没有什么方法可以检测出一个视图已经被缩小了,所以它可以真正被隐藏起来。

PD:此视图位于 UITableViewCell 内,而不是 UIViewController 内。单元格没有 didLayoutSubviews 方法,我尝试在 layoutSubviews 中这样做:

- (void)layoutSubviews
{
    [super layoutSubviews];
    // Truly hide it if is not visible anymore because there is no space.
    self.view.hidden = self.view.frame.size.width == 0;
}

但它不起作用,你知道吗?

【问题讨论】:

  • 您的 4 个“元素”是否具有固定宽度?或者它们的宽度是动态的?您的堆栈视图的宽度是否受到限制?问题是...如果C 缩小到零,并且您将其隐藏-同时删除间距-C 现在将有更多空间,并且不再为零...所以您将显示它,但是这将增加额外的空间,所以它会缩小到零......你在一个无限循环中。展示如何设置元素的宽度。我认为您可能需要进行一些计算,而不是使用堆栈视图。

标签: ios objective-c swift uiview uistackview


【解决方案1】:

这个怎么样。

代码如下。这只是一个示例,需要正确的情节提要配置。

@interface ViewController ()

@property (weak, nonatomic) IBOutlet NSLayoutConstraint * trailingConstraint;
@property (weak, nonatomic) IBOutlet UIView             * blackView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint * blackViewTrailingConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint * blackViewWidthConstraint;

@property (nonatomic) BOOL preventLoop;

@end

@implementation ViewController

- (void)viewDidLoad {

    super.viewDidLoad;

    [self.blackView addObserver:self
             forKeyPath:@"bounds"
                options:0
                context:nil];

}

- ( void ) observeValueForKeyPath: ( NSString     * ) keyPath
             ofObject: ( id             ) object
               change: ( NSDictionary * ) change
              context: ( void         * ) context
{
    if ( ! self.preventLoop ) {

        self.preventLoop = YES;

        if ( self.blackView.bounds.size.width < 10 ) {

            self.blackViewWidthConstraint.constant = 0;
            self.blackViewTrailingConstraint.constant = 0;

        } else {

            self.blackViewTrailingConstraint.constant = 40;

        }

        self.preventLoop = NO;

    }

}

- (IBAction)squashButtonAction:(id)sender {

    self.trailingConstraint.constant += 10;
    self.blackViewWidthConstraint.constant = MAX ( 0, self.blackViewWidthConstraint.constant - 10 );

}

- (IBAction)resetButtonAction:(id)sender {

    self.trailingConstraint.constant = 20;
    self.blackViewWidthConstraint.constant = 150;

}

@end

这个想法是使用键值观察来检测边界大小何时低于阈值;在这种情况下为 10。发生这种情况时,相关视图(此处为黑色)的宽度和尾随约束都将设置为 0。宽度在这里很明显,尾随约束是黑色视图和最后一个黄色视图之间的空间。这样你就不会得到双倍的空间。

由于您更改了观察者内部的值,因此您需要一些逻辑来防止它循环,正如您在代码中看到的那样。

黑色视图的宽度约束和紫色视图的尾随约束用于模拟视图的挤压,直到没有足够的空间容纳黑色视图。在您的特定情况下,您可能需要以不同的方式将其连接起来,但这可以完成工作,并且您有一个很好的工作示例来说明这个想法。

编辑

给猫剥皮的方法有很多种……这是另一个更简单的想法。这混合了您最初的尝试和我最初的答案的想法。您可以在其中一个布局消息中执行相同的操作,而不是使用观察者,如下所示。

我认为您的尝试与我建议的最大区别在于添加一个尾随约束(我的代码中为blackViewTrailingConstraint),然后在适当的时候使用它来将尾随空间压缩为 0。

无论如何,这里是在没有观察者的情况下完成相同操作的代码

- ( void ) viewWillLayoutSubviews {

    // you could also use ...

    // if ( self.blackView.bounds.size.width < 5 ) {

    // ... here but it is more correct to use the width
    // constaint and not the actual width here as you
    // and set the constaint and the width only updates
    // once layout completes
    if ( self.blackViewWidthConstraint.constant < 5 ) {

        self.blackViewWidthConstraint.constant = 0;
        self.blackViewTrailingConstraint.constant = 0;
        
    } else {

        self.blackViewTrailingConstraint.constant = 40;

    }

}

【讨论】:

  • 嗨,skaak,我现在无法尝试您的代码。我下周试试(我在度假)。非常感谢您的回答:-)
  • @Sergio 享受假期!很好,我已经考虑过并更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 2016-01-18
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 2012-06-07
  • 2021-02-27
  • 1970-01-01
相关资源
最近更新 更多