FlatListで2カラムリストを作るときのstyle
現状Yogaにgridがサポートされてないからきつい 単純にやると以下のように書ける
numColumnsでカラム数を指定し、
flexは0.5にすることで半分より伸びないようにする
code: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が壊れる
https://gyazo.com/e4906d6ad44921c08ccb3c777be7c38e
微妙に、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のイメージ
code: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;
}
};