4.6 KiB
4.6 KiB
ActionSheet Gesture Specification
Overview
JR Shikoku mobile appのActionSheet(ニュースリリース、各列車情報など)のジェスチャー実装仕様です。
Core Behavior
Swipe-to-Dismiss (スワイプで閉じる)
| Platform | 動作 | 方法 |
|---|---|---|
| iOS (Phone) | シート下方向スワイプで閉じる | isModal={true} + gestureEnabled={true} |
| iOS (iPad) | スワイプ無効 | isModal={false} → 通常のViewとして表示 |
| Android | スワイプ無効 | isModal={false} |
isModalの役割
isModal={true}にするとActionSheet内部で<Modal>ラッパーが適用されます- iOSのModalはOSレベルのswipe-to-dismissジェスチャーを組み込みでサポートしています
gestureEnabled={true}でそのジェスチャーを有効化します- iPadでは物理的に画面が larg いため、モーダル化しません(通常Viewとして表示)
Height Control
EachTrainInfo (共用パターン)
const maxHeight = useSheetMaxHeight();
// ↓
containerStyle={{ maxHeight }}
useSheetMaxHeight()フックが以下を判定して高さを計算:
| shortSide(デバイス短辺) | maxHeight値 | 意味 |
|---|---|---|
| ≥ 600 (iPad etc.) | undefined |
全画面表示、高さ制限なし |
| < 600 (Phone) | deviceHeight * 0.75 | 画面の高さの75% |
NewsReleaseInfo (個別実装)
const sheetHeight = windowDimen.height * 0.8;
// ↓
containerStyle={{ height: sheetHeight }}
- Phoneのみ画面高さの80%固定
- shortSide判定はしない点で差異あり
Platform-Specific Layout
Android
containerStyle={{
paddingBottom: insets.bottom, // SafeArea対応
useBottomSafeAreaPadding={true},
}}
AndroidはSafeAreaパディングが必要です。 Bottom barの領域を避けます。
ScrollView inside ActionSheet
react-native-actions-sheet内部のScrollView使用(注意)
import { ScrollView } from "react-native-actions-sheet"; // ← これ使う
nestedScrollEnabled={true}はAndroid用(nested scrolling有効化)- ScrollViewコンテンツとActionSheetのジェスチャーが干渉しないように重要
Layout Structure (テンプレート)
// ActionSheet
containerStyle={{ height: ..., borderTopLeftRadius: 5, borderTopRightRadius: 5 }}
CustomHeaderComponent={<></>} // カスタムヘッダーなし
gestureEnabled={true} // iOSでswipe-to-dismiss有効
isModal={Platform.OS === "ios" && !Platform.isPad}
→ Content
→ DragHandle (ドラッグハンドル)
→ Title (タップでスクロールトップ)
→ ScrollView ← ネスト可能なコンテンツのみ
→ NewsReleaseInfoBox / EachTrainInfoCore
→ BottomButton (固定配置、ScrollView外) ← 押せるボタンは必ず外側
ボタンの配置ルール
- 重要な操作ボタン(「公式でもっと見る」etc.)はScrollViewの外に配置
- ScrollView内にあるとスクロールで隠れ、クリック不可になる
- ActionSheetの下部、SafeAreaパディングの直上に固定する
Back Handler (Androidのみ)
useEffect(() => {
if (Platform.OS === "android") {
const backAction = () => true; // default prevent(スワイプ無効化)
const backHandler = BackHandler.addEventListener(
"hardwareBackPress", backAction
);
return () => backHandler.remove();
}
}, []);
Androidでハードウェアバックキーを押下時にスワイプを無効化します。
Gesture Flow (iOS)
ユーザー操作 ActionSheet内部処理
──────── ────────────────
シートを下方向にスワイプ → Modalがgesture検知
↓ ↓
スワイプ距離閾値超過 ↓(閉じる判定)
↓ ↓
Modal-dismiss実行 sheet ref close + onCloseコールバック
Key Points Summary
- ジェスチャー有効化:
gestureEnabled={true}は必須 - iOSモーダル化:
isModal={Platform.OS === "ios" && !Platform.isPad} - Androidパディング:
useBottomSafeAreaPadding+containerStyle.pb両方必要 - ScrollView配置: ActionSheetコンテンツ内のスクロールにはライブラリ版(
react-native-actions-sheet)を使用 - ボタン配置: 重要ボタンはScrollView外、画面下部固定