React Native - 具有动态高度子项的FlatList

时间:2018-03-27 04:40:32

标签: react-native redux

我一直在努力将类似砖石的风格融入到我的应用中。 我尝试应用react-native-masonry包。但是,您必须传递图像网址。 我试图完成相同的样式,但渲染文本而不必渲染图像。

到目前为止,我已经绕着FlatList工作了,但这是我能得到的。

 <FlatList
data={[
    { id: 1, username: "user1", title: "Title test", heigth: 150 },
    {
        id: 2,
        username: "RH",
        title: "Testing the length of a title with an image",
        image: "http://localhost:5005/dummy.png",
        heigth: 300
    },
    { id: 3, username: "john", title: "Another not so long title" },
    {
        username: "CAF",
        title:
            "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
        heigth: 600
    }
]}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
numColumns={2}
/>;

enter image description here

我正在硬编码不同长度的卡片,但似乎它们坚持在行的最大高度。

这是我的卡组件(renderItem)。

 _renderItem = ({ item }) => (
<Card style={{ height: item.heigth }}>
    <CardItem>
        <Left>
            <Text style={{ fontWeight: "bold", fontSize: 20 }}>
                {item.title}
            </Text>
        </Left>
    </CardItem>
    <CardItem cardBody style={{ marginBottom: 5 }}>
        {!isEmpty(item.image) && (
            <Image
                source={{ uri: item.image }}
                style={{ width: 170, flex: 1, height: 100 }}
            />
        )}
    </CardItem>
    <CardItem>
        <Left />
        <Body />
        <Right>
            <Text note>{item.username}</Text>
        </Right>
    </CardItem>
</Card>
);

由于

3 个答案:

答案 0 :(得分:1)

使用这个库,我有同样的要求。它几乎解决了这个问题。 https://github.com/AppAndFlow/react-native-masonry-list

答案 1 :(得分:0)

我找到了一种在本地本机中实现此目标的方法-无需外部库。诀窍是使用负边距。实施有些棘手,但并不是太困难。

我们需要在VirtualizedList属性CellRendererComponent中应用负边距,以使其在Android上正常工作。

JSX:

<View style={styles.container}>
      <FlatList
        style={styles.flatlist}
        data={data}
        keyExtractor={(item, index) => index.toString()}
        CellRendererComponent={({ children, item, ...props }) => {
            return (
                <View {...props} style={{ marginTop: item.marginTop }}>
                    {children}
                </View>
            )
        }}
        renderItem={({ item }) => {
            const { source: source1, height: height1, marginTop: marginTop1 } = item.image1;
            const { source: source2, height: height2, marginTop: marginTop2 } = item.image2;
            return (
                <View style={Style.viewRow}>
                    <Image source={source1} style={[styles.image, { height: height1, marginTop: marginTop1 }]} />
                    <Image source={source2} style={[styles.image, { height: height2, marginTop: marginTop2 }]} />
                </View>
            )
        }}
    />
</View>

数据:

const source = { uri: 'https://placekitten.com/160/300' };

const data = [
    {
        marginTop: 0,
        image1: { source, height: 300, marginTop: 0 },
        image2: { source, height: 250, marginTop: 0 }
    },
    {
        marginTop: -50,
        image1: { source, height: 290, marginTop: 50 },
        image2: { source, height: 300, marginTop: 0 }
    },
    {
        marginTop: -40,
        image1: { source, height: 250, marginTop: 40 },
        image2: { source, height: 350, marginTop: 0 }
    }
];

样式:

const styles = StyleSheet.create({
   container: {
      flex: 1
   },
   flatList: {
      width: '100%',
      height: '100%'
   },
   viewRow: {
      flexDirection: 'row'
   },
   image: {
      width: '50%',
      resizeMode: 'cover'
   }
});

剩下的唯一工作就是将图像的数据排列在数组中。确保具有图像的高度,始终将较高的图像放在较短的一侧,然后计算差值...。欣赏。

答案 2 :(得分:0)

  

使用@Dror Bar提出的技术,我编写了代码   根据物品的高度将它们放置在两列中。这就是你   可以做到这一点:

   let colLeft=0; let colRight=0; let colDiff=0;
        const rows = [];

        data.forEach(item  => {
            let cellData = {
                marginTop: 0,
                image1: { source: '', height: 0, marginTop: 0 },
                image2: { source: '', height: 0, marginTop: 0 }
            }
            if(colLeft <= colRight) {
                colDiff = colLeft - colRight;
                cellData.marginTop = colDiff > 0 ? -colDiff : 0;
                cellData.image1.source = item.source;
                cellData.image1.height = item.height;
                cellData.image1.marginTop = colDiff;
                colLeft =  colLeft + item.height;
                console.log('Col Left: ', colLeft);

            } else {
                colDiff = colRight - colLeft;
                cellData.marginTop = colDiff > 0 ? -colDiff : 0;
                cellData.image2.source = item.source;
                cellData.image2.height = item.height;
                cellData.image2.marginTop = colDiff;
                colRight =  colRight + item.height;
                console.log('Col Right: ', colRight);
            }
            rows.push(cellData);
        });
        return rows;
  

这是数据样本:

    const imageData = [
        {
            source: 'grey',
            height: 180
        },
        {
            source: 'blue',
            height: 150
        },
        {
            source: 'purple',
            height: 70
        },
        {
            source: 'blue',
            height: 50
        },
        {
            source: 'pink',
            height: 140
        },
        {
            source: 'blue',
            height: 180
        },
        {
            source: 'red',
            height: 60
        },
        {
            source: 'yellow',
            height: 180
        },
        {
            source: 'green',
            height: 140
        },
        {
            source: 'blue',
            height: 100
        },
];
  

您可以使用flatList来呈现此数据,就像Dror Bar所做的一样。