generated at
FlatListで2カラムリストを作るときのstyle

現状Yogaにgridがサポートされてないからきつい


単純にやると以下のように書ける
numColumns でカラム数を指定し、
flex は0.5にすることで半分より伸びないようにする
ts
<FlatList data={[{ key: 'a' }, { key: 'b' }, { key: 'c' }]} numColumns={2} renderItem={({ item }) => ( <View style={{ flex: 0.5, backgroundColor: 'red' }}> <Text>{item.key}</Text> </View> )} columnWrapperStyle={{ gap: 8, // 1行の中に並ぶアイテム同士のgap }} contentContainerStyle={{ gap: 8, // 行間 }} />
しかし、これだと奇数の場合に微妙にstyleが壊れる
微妙に、cの横幅が長いのが分かるだろう
flex: 0.5 はa,b,cのいずれにも効いているが、a,bは良い感じに縮み、 gap: 8 を保っている
しかし、cはgapの相手がいないため、 flex: 0.5 のみが優先され、他よりもちょっと伸びる


無理やり実現する方法はいくつか考えられるがどれも微妙
widthで指定する
Flexを棄てるということ
変える場所
widthを使って、画面幅を見ながら数px単位で合わせる
データはそのままでいい
Emptyで端数を埋める
変える場所
data に端数の分だけ undefined 等を埋める
renderItem 内でEmptyと出し分ける
styleはそのままで良い
FlatListをwrapするようなComponentを作っておけば良い
カラム数が多い場合は無駄にEmptyがたくさん表示されうる


wrapperのイメージ
ts
export function GridFlatList<T>({ ...props }: Props<T>) { const numColumns = props.numColumns || 1; const data = props.data || []; const paddedData = padEmpty(data, numColumns); return ( <FlatList {...props} data={paddedData} keyExtractor={(item, index) => { if (isEmpty(item)) { return `empty-${index}`; } return props.keyExtractor ? props.keyExtractor(item, index) : index.toString(); }} renderItem={({ item, ...rest }) => { if (isEmpty(item)) { return <View />; } if (props.renderItem == null) { return null; } return props.renderItem({ item, ...rest }); }} /> ); } const empty = Symbol('empty'); const isEmpty = (item: any): item is symbol => item === empty; const padEmpty = <T,>( data: ArrayLike<T>, numColumns: number, ): (T | symbol)[] => { const dataArray = Array.from(data); const rest = data.length % numColumns; if (rest === 0) { return dataArray; } return [...dataArray, ...range(numColumns - rest).map(() => empty)]; };