diff --git a/src/screens/SelectLineScreen.render.test.tsx b/src/screens/SelectLineScreen.render.test.tsx
index c8c2b2038..c749030a2 100644
--- a/src/screens/SelectLineScreen.render.test.tsx
+++ b/src/screens/SelectLineScreen.render.test.tsx
@@ -282,16 +282,18 @@ describe('SelectLineScreen', () => {
});
describe('ローディング状態', () => {
- it('nearbyStationLoading=true のときスケルトンが表示される', () => {
+ it('nearbyStationLoading=true のとき路線リストのスケルトンが表示される', () => {
setupDefaults({ nearbyStationLoading: true });
- const { getByTestId, queryByTestId } = render();
+ const { getByTestId } = render();
expect(getByTestId('skeleton-placeholder')).toBeTruthy();
- expect(queryByTestId('presets')).toBeNull();
+ // プリセットカードは上部固定表示になり最寄り駅のローディングとは独立したため、
+ // ローディング中でも常に表示される
+ expect(getByTestId('presets')).toBeTruthy();
});
- it('nearbyStationLoading=false のときプリセットが表示される', () => {
+ it('nearbyStationLoading=false のとき路線リストのスケルトンは表示されない', () => {
setupDefaults({ nearbyStationLoading: false });
const { getByTestId, queryByTestId } = render();
diff --git a/src/screens/SelectLineScreen.tsx b/src/screens/SelectLineScreen.tsx
index d6cdebe11..ca79cfa37 100644
--- a/src/screens/SelectLineScreen.tsx
+++ b/src/screens/SelectLineScreen.tsx
@@ -45,10 +45,7 @@ import { SelectLineScreenPresets } from './SelectLineScreenPresets';
const styles = StyleSheet.create({
root: { paddingHorizontal: 24, flex: 1 },
- listContainerStyle: {
- paddingBottom: 24,
- paddingHorizontal: 24,
- },
+ listScroll: { flex: 1 },
heading: {
fontSize: 24,
fontWeight: 'bold',
@@ -69,6 +66,10 @@ const styles = StyleSheet.create({
// https://github.com/facebook/react-native/issues/53987
const REFRESH_TINT_DELAY_MS = 500;
+// 路線リストのスクロール領域下端の基本パディング。実際の下端余白はこれに
+// フッタータブバーの高さ(useFooterHeight)を加算して算出する
+const LIST_CONTENT_PADDING_BOTTOM = 24;
+
const NearbyStationLoader = () => (
@@ -152,12 +153,10 @@ const SelectLineScreen = () => {
// --- 派生値 ---
const footerHeight = useFooterHeight();
- const listPaddingBottom = useMemo(() => {
- const flattened = StyleSheet.flatten(styles.listContainerStyle) as {
- paddingBottom?: number;
- };
- return (flattened?.paddingBottom ?? 24) + footerHeight;
- }, [footerHeight]);
+ const listPaddingBottom = useMemo(
+ () => LIST_CONTENT_PADDING_BOTTOM + footerHeight,
+ [footerHeight]
+ );
const orientation = useDeviceOrientation();
const isPortraitOrientation = useMemo(
@@ -303,36 +302,47 @@ const SelectLineScreen = () => {
// --- JSX ---
return (
<>
-
+ {/*
+ 上下のセーフエリアは絶対配置オーバーレイの NowHeader / FooterTabBar が
+ それぞれ処理するため上下インセットは無効化する。一方、横向き/タブレットの
+ ノッチでコンテンツが欠けないよう、左右インセットだけは SafeAreaView で確保する。
+ */}
+
+ {/*
+ プリセットカードは上部に固定表示し、Pull to Refresh の対象外にする。
+ paddingTop で固定ヘッダー(NowHeader)の直下に配置する。
+ */}
+
+
+
+
+
+
+ {/* プリセットカードより下の路線リストのみ Pull to Refresh の対象にする */}
}
- contentContainerStyle={[
- styles.listContainerStyle,
- nowHeaderHeight ? { paddingTop: nowHeaderHeight } : null,
- { paddingBottom: listPaddingBottom },
- ]}
+ contentContainerStyle={{ paddingBottom: listPaddingBottom }}
>
{nearbyStationLoading && !refreshing ? (
) : (
<>
-
-
-
{stationLines.length > 0 && (