反应原生平面列表如何强制列表项具有相同的高度?

Posted

技术标签:

【中文标题】反应原生平面列表如何强制列表项具有相同的高度?【英文标题】:react native flat list how to force list items to be the same height? 【发布时间】:2020-09-19 22:02:49 【问题描述】:

我有一个 React-Native 应用程序,我在其中使用 FlatList 显示从服务器获取的项目列表。该列表有 2 列,我需要我的列表项具有相同的高度。我在呈现列表项的代码周围放置了一个边框,但列表项的高度不同。我尝试使用 flexbox 设置使视图填充容器,但我尝试的一切都没有区别。

我创建了我的应用程序的简化版本来说明问题:

请注意,红色边框区域的高度不同。我需要让这些高度相同。

灰色边框被添加到包裹负责列表项的组件的视图中,红色边框是负责列表项的组件的根视图。为了清楚起见,请参阅下面的代码。

我不能在我的应用程序中使用灰色边框,因为我的应用程序显示空框,而负责列表项的组件在呈现之前从服务器获取附加信息

此外,我不能对高度使用固定尺寸。

应用项目结构和代码

我的代码以“container.js”结尾的文件从服务器获取数据并将其传递给匹配的渲染组件的方式进行拆分。例如,“MainListContainer”将从服务器获取列表,然后将列表数据传递给“MainList”,而“ListItemContainer”将从服务器获取有关单个列表项的附加信息并将其传递给“ListItem”进行渲染实际项目。我将这个模型保留在我的简化应用程序中,使其尽可能接近我的实际应用程序。

index.js

import AppRegistry from 'react-native';
import MainListContainer from './app/components/MainListContainer';
import name as appName from './app.json';

AppRegistry.registerComponent(appName, () => MainListContainer);

MainListContainer.js

import React from 'react';
import MainList from './MainList';

const data = [
  id: '1', title: 'Item 1', subtitle: 'A', description: 'This is the first item.',
  id: '2', title: 'Item 2', subtitle: 'B', description: 'The Big Brown Fox Jumped over the lazy dogs. The Big Brown Fox Jumped over the lazy dogs.',,
];

const MainListContainer = () => 
  return ( <MainList items=data /> );
;

export default MainListContainer;

MainList.js

import React from 'react';
import StyleSheet, FlatList, View from 'react-native';
import ListItemContainer from './ListItemContainer';

export default class MainList extends React.Component 
  constructor(props) 
    super(props);
    this.state =  numColumns: 2;
    this.renderItem = this.renderItem.bind(this);
  

  renderItem(item, index) 
    return (
      <View style=styles.flatListItemContainer>  <!-- THIS IS WHERE THE GREY BORDER IS ADDED -->
        <ListItemContainer key=index item=item />
      </View>
    );
  

  render() 
    const items = this.props;
    const numColumns = this.state;

    return (
      <View>
        <FlatList
          data=items
          renderItem=this.renderItem
          numColumns=numColumns
          key=numColumns
          keyExtractor=(item) => item.id
        />
      </View>
    );
  
;


const styles = StyleSheet.create(

  flatListItemContainer: 
    flex: 1,
    margin: 10,

    borderColor: '#ccc',
    borderWidth: 1,
  ,

);

ListItemContainer.js

import React from 'react';
import ListItem from './ListItem';

const ListItemContainer = (props) => 
    const  item  = props;

    return (
        <ListItem item=item />
    );
;

export default ListItemContainer;

ListItem.js

import React from 'react';
import TouchableHighlight, View, StyleSheet, Image, Text from 'react-native';

const ListItem = (props) => 
  const  item  = props;

  return (
    <TouchableHighlight
      underlayColor="white"
    >
      <View style=styles.containerView> <!-- THIS IS WHERE THE RED BORDER IS ADDED -->

        <View style=styles.top_row>
          <Image style=styles.image source=require('../images/placeholder.png') />
          <View style=styles.title_texts>
            <Text style=fontWeight:'bold'>item.title</Text>
            <Text style=color: 'rgb(115, 115, 115)'>item.subtitle</Text>
          </View>
        </View>

        <Text>item.description</Text>

      </View>
    </TouchableHighlight>
  );
;

export default ListItem;

const styles = StyleSheet.create(
  containerView: 
    padding: 14,

    borderColor: 'red',
    borderWidth: 1,
  ,

  top_row: 
    flex: 1,
    flexDirection: 'row',
    marginBottom: 10,
  ,

  title_texts: 
    flex: 1,
    flexDirection: 'column',
  ,

  image: 
    alignSelf: 'flex-end',
    resizeMode: 'cover',
    height: 40,
    width: 40,
    marginRight: 20
  ,

);

我的尝试

ListItem.js : 将样式移到“TouchableHighlight”视图中 ListItem.js:添加一个包含“TouchableHighlight”视图的视图并在那里添加样式 ListItem.js : 在“TouchableHighlight”上添加“alignItems:'stretch',将其添加到“containerView”样式中,也在描述字段中尝试过 与“alignItems”相同,但改用“alignedSelf” 与“alignItems”相同,但改用“alignedContent” 尝试在不同视图(容器、描述)上使用“flexGrow”

【问题讨论】:

您可以使用this 库来测量字符串的文本高度。然后,将最高的设置为您的 ListItem 高度。 我在项目容器中添加了flex: 1,这对我有用,现在它们的高度都一样。 【参考方案1】:

您可以测量列表中每个元素的高度,当您确定最大高度时,您可以为列表中的每个元素使用该高度。

const Parent = ( ...props ) => 
    const [maxHeight, setMaxHeight] = useState<number>(0);
    
    const computeMaxHeight = (h: number) => 
        if (h > maxHeight) setMaxHeight(h);
    
    return (
        <FlatList
            data=props.data
            renderItem=( item ) => (
                <RenderItem 
                    item=item
                    computeHeight=(h) => computeMaxHeight(h)
                    height=maxHeight
                />
            )
            ....
        />
    )

物品:

const RenderItem = (...props ) => 
    return (
        <View
            style= height: props.height 
            onLayout=(event) => props.computeHeight(event.nativeEvent.layout.height)
        >
          <Stuffs />
        </View>
    )

这是实现这一目标的一种非常低效的方式。如果我有一个很长的列表或任何多个项目的列表,我会避免这种情况。但是,您可以进行某些检查以限制重新渲染等。或者,如果只有文本会影响高度,那么您只能测量具有最多文本的元素的高度,其余部分使用该元素的高度。

【讨论】:

【参考方案2】:

您可以使用弹性框来代替设置固定宽度高度。我刚刚通过在 FlatList 中删除 alignSelf 并在其上添加 alignItems center 解决了这个问题。

将flatList包裹在flex box中,对齐项目中心,你可以在你的MainList.js文件中添加代码,第一个&lt;View&gt;,即:

render() 
const items = this.props;
const numColumns = this.state;

return (
  <View style=flex: 1, alignItems: 'center'>
    <FlatList
      data=items
      renderItem=this.renderItem
      numColumns=numColumns
      key=numColumns
      keyExtractor=(item) => item.id
    />
  </View>
);

如果还是没有反映,可以尝试在 FlatList 样式的 props 中添加 flex:1, alignItems center。

【讨论】:

【参考方案3】:

您缺少一个非常基本的概念,即在您的ListItem.js 中为平面列表项目提供固定高度,尝试在containerView 中设置height:200。让我知道这是否适合你

【讨论】:

我认为你不能在这里设置 200px。如果任何单元格的文本高度超过 200 像素,您的解决方案将不起作用。 我不想给出一个固定的高度。我永远不会知道一个合适的高度。我不知道从服务器返回的描述文本的文本长度。用户也可以增加他们的字体大小。如果它适用于灰色边框,我怎么能不拉伸红色边框以适应灰色

以上是关于反应原生平面列表如何强制列表项具有相同的高度?的主要内容,如果未能解决你的问题,请参考以下文章

HTML5/CSS 根据其他列相互高度对齐列表项

如何实现 Activity 指示器进行渲染,直到显示平面列表数据?反应原生

如何将对象迭代到平面列表中 - 反应原生?

反应平面列表渲染项

我无法在反应原生平面列表中写入输入

反应原生平面列表不滚动