用列反应本机平面列表,最后一项宽度

我使用一个平面列表来显示两列中的项目列表

<FlatList style={{margin:5}}
data={this.state.items}
numColumns={2}
keyExtractor={(item, index) => item.id }
renderItem={(item) => <Card image={item.item.gallery_image_url} text={item.item.name}/> }
/>

卡片组件只是一个视图,有一些样式:

<View style={{ flex: 1, margin: 5, backgroundColor: '#ddd', height: 130}} ></View>

它工作得很好,但是如果项目的数量是奇数,那么最后一行只包含一个项目,并且该项目延伸到屏幕的整个宽度。

如何将项目设置为与其他项目相同的宽度?

enter image description here

116823 次浏览

Theres a few things you can try here.

A) Setting a pre-defined width for the card ( Maybe equal to the height you've set? ). Then you can use alignItems in order to have the card positioned in the middle or on the left - Unsure as to which you wanted here.

B) If there are an even number of cards, you could add an empty View at the end in order to fill this space. I find this method pretty clunky but useful when trying to leave space for future elements.

C) Simply use alignItems: 'space-between, i like to use this to center items, but you would have to define the width, or use something like flex:0.5

I suggest researching more into flexbox to help you with this, as it is hard to tell the context of this situation. I'm assuming the above methods will help, but if not, here are some links for you to look at -

First link

Second link

Third link Link Broken

Hope this helps. If you need any further clarification - just ask

You can try to get the current width of the device via Dimensions, do some math based on the number of columns you want to render, minus off the margins and set that as the minWidth and maxWidth.

For example:

const {height, width} = Dimensions.get('window');
const itemWidth = (width - 15) / 2;


<View style=\{\{ flex: 1, margin: 5, backgroundColor: '#ddd', minWidth: {this.itemWidth}, maxWidth: {this.itemWidth}, height: 130}} ></View>

for your case use flex: 1/2

therefore: Your item should have flex of 1/(number of columns) if you have 3 columns your item should have flex:1/3

The reason for it is your Card have style flex: 1, so it will try to expand all the space remain. You can fix it by add maxWidth: '50%' to your Card style

<View style=\{\{ flex: 1, margin: 5, backgroundColor: '#ddd', height: 130, maxWidth: '50%'}} ></View>

This is the cleanest way to style a FlatList with columns and spaced evenly:

    <FlatList style=\{\{margin:5}}
numColumns={2}                  // set number of columns
columnWrapperStyle={style.row}  // space them out evenly
        

data={this.state.items}
keyExtractor={(item, index) => item.id }
renderItem={(item) => <Card image={item.item.gallery_image_url} text={item.item.name}/> }
/>


const style = StyleSheet.create({
row: {
flex: 1,
justifyContent: "space-around"
}
});

@Emilius Mfuruki suggestion is good, but if you have text with varying length it doesn't work perfectly. Then use this width inside your item view:

const {height, width} = Dimensions.get('window');
const itemWidth = (width - (MarginFromTheSide * 2 + MarginInBetween * (n-1))) / n;

In FlatList use:

columnWrapperStyle=\{\{
flex: 1,
justifyContent: 'space-evenly',
}}

Works perfectly.

You can use ListFooterComponent={this.renderFooter}

just use flex:0.5 and width:'50%'

Create an array with odd number of images in it, like:

const images = [
require('./../...jpg'),
require('./../...jpg'),
require('./../...jpg'),
require('./../...jpg'),
require('./../...jpg'),
];

And then, use the code given below,

const App = () => {
const _renderItem = ({ item, index }) => (
<Image
source={item}
style=\{\{
width: '50%',
height: 200,
}}
resizeMode="cover"
/>
);


return (
<View style=\{\{flex: 1, marginHorizontal: 10,}}>
<FlatList
columnWrapperStyle=\{\{ justifyContent: 'space-between' }}
keyExtractor={(_, index)=> index.toString()}
data={images}
numColumns={2}
renderItem={_renderItem}
/>
</View>
)
};
export default App;

Working Example

I tried some of the solutions above but I still had some problems with the margins on the last item (2 columns list).

enter image description here

My solution was simply wrapping the item into a parent container, leaving the original container with flex: 1 and the parent container of the item with flex: 0.5 so it would take the margin correctly.

itemContainer: {
flex: 0.5,
},
itemSubContainer: {
flex: 1,
marginHorizontal: margin,
},

The simplest solution is do the math. Imagine we have 2 View for each Row and we want to give 10 margin to every side it will look something like that:

enter image description here

As you see in the image above each View have 2 margins in horizontal. (inside of red rectangle) So we have to subtract the product of margin, number of column and 2 from the width.

import { Dimensions } from 'react-native';
const {width} = Dimensions.get("window")
const column = 2
const margin = 10
const SIZE = (width - (margin * column * 2)) / column
<View style=\{\{ margin: 10, width: SIZE }} ></View>

A simple way with flex

 <FlatList style=\{\{margin:5}}
data={this.state.items}
numColumns={2}
keyExtractor={(item, index) => item.id }
renderItem={({item, index}) => {
const lastItem = index === this.state.items.length - 1;
return (
<View style=\{\{flex: lastItem ? 1 / 2 : 1 }}>
<Card image={item.gallery_image_url} text={item.name}/>
</View>
)}}
/>

None of the above answers have worked perfectly for me so I post my own answer:

  • works with padding and margins
  • the last element will always have the correct size
<FlatList
data={data}
numColumns={2}
renderItem={({item, index}) => {
const lastItem = index === data.length - 1;
return (
<View style=\{\{flex: 1, padding: 8, maxWidth: lastItem ? '50%' : '100%' }}>
...
</View>
)}}
/>

Note: change maxWidth according to number of columns

Result:

reactFlatlist