【问题标题】:Can we set content priority of component in react-native?我们可以在 react-native 中设置组件的内容优先级吗?
【发布时间】:2016-05-02 01:53:24
【问题描述】:

在 AutoLayout 中,我们可以根据约束排列多个视图,例如,如果我有一个 UILabel 和一个 UIImageView 定位在一行中,我可以这样做:

UILable *label = [UILabel new];
UIImageView *imageView = [UIImageView new];
[self.view addSubview:label];
[self.view addSubview:imageView];

[label mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.bottom.top.equalTo(self.view);
    make.right.equalTo(imageView.mas_left);
}];

[imageView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.right.bottom.top.equalTo(self.view);
}];

现在,如果我想保持label的内容不被压缩,传统的AutoLayout方式是设置label的contentCompressionResistancePriority更高,那么布局系统将保持label的内容不被压缩,如果水平轴剩余空间不够,imageView 的宽度会被压缩。所有这一切都基于content size,或intrinsicContentSize

继续,我将在 JS 中重新实现一个原生自定义视图,它使用intrinsicContentSize 属性来计算它是否应该完全显示其内容。自定义视图的目标是水平并排显示多个标签,在我的原生实现中,我将检查layoutSubviews方法中每个子视图的边界是否超出其超级视图:

-(void)layoutSubviews {
    [super layoutSubviews];
    CGFloat width = 0;    
    bool update = NO;

    for(UIView * subview in self.subviews) {
        if(subview.frame.origin.x + subview.width > self.width) {
            subview.hidden = YES;
            update = YES;
        } else {
            subview.hidden = NO;
            width = subview.origin.x + subview.width;
        }
    }

    if(update) {
        self.fitSize = CGSizeMake(width, self.fitSize.height);
        [self invalidateIntrinsicContentSize];    //in intrinsicContentSize method, return self.fitSize
    }
}

现在 AutoLayout 知道视图的实际大小,它将基于视图的实际大小进行布局。我也想使用 react native 来实现这一点,但是我发现我无法设置两个组件之间的关系,例如我使用基于约束的 AutoLayout 也无法覆盖 intrinsicContentSize 方法来计算我想要的视图的实际大小,是这个用例有什么解决方案吗?

【问题讨论】:

    标签: ios flexbox react-native


    【解决方案1】:

    React Native 使用the CSS Flexbox 来布局它的视图。这与UIStackView 非常相似;换句话说,您在问题中要求的所有内容都与布局 React Native 视图真正相关!

    最好的描述方式是将其与 iOS 9 的UIStackView 进行比较。如果您对此不熟悉,我强烈建议您使用check out this tutorial,因为一旦您熟悉了UIStackView,将这些知识连接到Flexbox 将是小菜一碟。

    在 React Native 中,您使用 StyleSheet 来定义视图的布局。考虑以下样式:

    const styles = React.StyleSheet.create({
      container: {
        flexDirection: "vertical",
        flex: 1,
      }
    })
    

    这种container 样式本质上是定义一个UIStackView,其中项目垂直对齐。

    flex 值的存在表示容器中的元素将引用它们自己的 flex 值来确定内容拥抱优先级

    这是。就像你提到的,React Native 的布局可以通过操纵它如何解释每个视图的内在内容大小来完全操纵。

    考虑以下布局:

    让我们关注底部标签栏。假设标签栏本身具有上述container 样式的样式(带有flexDirection: "horizontal")。

    要在 React Native 中实现这种布局,您需要为所有子元素指定一个 flex 值。 flex 的值越高,与兄弟姐妹相比,它的less 内容拥抱优先级就越低。换句话说,1 个同级的 flex 值越高,对所有其他 flex 值较低的同级强制执行更高的内容拥抱优先级。

    因此,布局样式表可能如下所示:

    const styles = React.StyleSheet.create({
      //flex box containing the child elements
      container: {
        flexDirection: "horizontal",
        flex: 1
      },
    
      //the three child elements nested inside the container
      plusButton: {
        flex: 1
      },
      chooseSourcePlaylistButton: {
        flex: 2
      },
      settingsButton: {
        flex: 1
      },
    })
    

    因为您希望中间视图展开并将其他元素推到边缘,您希望它通过给它一个更大的flex 值来支配 flex 框。

    【讨论】:

    • 首先感谢您的回答!我突然意识到 flexbox 中的 flex 值等于我提到的调用内容优先级:) 但是作为另一个问题,我还没有任何想法。如果我期望continuous宽度压缩,我可以通过简单地将flex值设置得更大来解决这个问题,但我的期望是discrete压缩,这意味着如果我的自定义视图的大小足以完全显示两个标签,然后显示两个,如果它的大小只能显示1.5个标签(我们假设),它会显示一个标签并隐藏另一个标签,然后将intrinsicContentSize设置为layoutSubviews中的一个标签大小。
    • 我在本机代码中的所有计算都是基于frame,就像我的问题中显示的代码一样,但是在 flexbox 布局系统中,我无法进行这种计算,或者我只是还没有找到正确的方法...这是我对您的回答的更新,希望您清楚我在说什么,再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-04
    • 2013-03-14
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    • 2022-08-12
    相关资源
    最近更新 更多