使用ReactNative和StyledComponents布置子组件

时间:2019-06-06 06:20:43

标签: react-native layout styled-components

我正在尝试将布局应用于 ReactNative和StyledComponents上下文中的一组子项。我的特殊问题是,我需要在一组子级中的最后一个上添加余量,以便控制弹性项目的间距(ReactNative中的所有容器均为display: flex)。我不想在组件本身上增加页边空白,因为我认为这可能会失控,因为需要在许多地方重复使用组件。

我尝试了许多不同的方式来针对StyledComponents中的子对象,但没有任何效果:

  • > *
  • & > *
  • .some-classclassName在ReactNative View上贬值)

我目前最好的解决方案是将孩子的集合包装在特定的Layout处理对象中,但是当我觉得这主要是由父母直观地解决时(这也符合{的基本原则, {1}}和flex布局规范。

我很想知道其他人如何解决了这个问题,因此我将尽力做到最好。

这是我要布局的标记:

grid

将其渲染为-每个元素的边距相等,而最后一个元素没有空白:

enter image description here

这就是我在香草CSS中使用<View> <Could /> <Be /> <Anything /> <Valid /> </View> 的方式:

flex

这里的最佳实践解决方案是什么?

1 个答案:

答案 0 :(得分:0)

您提出了一些好的观点和看法-尤其是关于使用父级的flex-properties来隔开带有间隙的子级,而不是将布局委派给父级的子级来在其上包装和添加边距。

我为这两种实现提供了小吃: https://snack.expo.io/HyXElYL0V

第一个选项:包装每个孩子并添加边距:(GapLayout.js)

在这里,我们仅用View对象包装每个子对象,然后向其中添加任何填充/边距,如果需要,可以排除最后一个子对象。

const GapLayout = ({ children }) => (
  <View style={Styles.layoutContainer}>
    {children.map((child, index) => {
      const isLastChild = children.length === index + 1

      return (
        <View style={[Styles.layoutItemWrapper, { marginBottom: isLastChild ? 0 : 8 }]}>
          {child}
        </View>
      )
    })}
  </View>
)

这允许您在上面概述标记:

<GapLayout>
  <WideContent />
  <WideContent />
  <WideContent />
</GapLayout>

第二个选项:设置适当的父级高度,以便justifyContent:'space-between'有效(GapLayout2.js)

仅在父级上使用 {justifyContent:'space-between'} 会是非常理想的,这很神奇。为了在元素之间创建空间,父级必须比所有子级都高。

由于我们要添加多个长度未知的子代,因此我们需要将父代的高度设置为:未知长度+(子代数-1)*边距

class GapLayout2 extends React.Component {
  constructor() {
    super();

    this.state = {
      contentHeight: null,
    };
  }

  setContentHeight = e => {
    const { contentHeight } = this.state
    const { children, itemMargin } = this.props

    // Return if we already set a contentHeight to prevent an infinite-render-loop.
    if(contentHeight) return

    this.setState({
      contentHeight: e.nativeEvent.layout.height + (children.length - 1) * itemMargin
    })
  }

  render() {
    const { children } = this.props;
    const {contentHeight} = this.state

    return (
      <View onLayout={this.setContentHeight} style={[Styles.layoutContainer, contentHeight && { height: contentHeight }]}>
        {children}
      </View>
    );
  }
}

这里发生了什么

  1. 我们渲染父级及其所有内容。
  2. 我们使用onLayout回调获取内容高度。
  3. 在setContentHeight中,然后使用新的ContentHeight +边距设置setState。
  4. 一旦有了contentHeight,我们便以新的高度渲染父级:

    style = {[Styles.layoutContainer,contentHeight && {height:contentHeight}]}

这使我们可以进行相同的标记,而无需包裹孩子。 而且我想这将允许直接的子代之间使用flex:1/2/10,因为他们都共享同一个父代(而如果将它们包装,那将是行不通的。)

希望看到其他想法和实现。

干杯