OpenAIExpo2025/11/25 16:30

How to create Apple Maps style liquid glass sheets in Expo (the real way)

要点だけを先に読めるように短く再構成したセクションです。

元記事

Quick Digest

要約

要点だけを先に読めるように短く再構成したセクションです。

openaijamodel: gpt-5-mini-2025-08-07

ExpoでApple Maps風Liquid Glassシートを作る(実践)

Key Points

  • TrueSheetが最良
  • フォームシートで簡単実装
  • expo-swift-uiはβ段階

Summary

iOS 26のApple Mapsにある「liquid glass」かつ段階的なデテン遷移をExpoで再現する手法をまとめました。記事は主に3つのアプローチを比較しています:@expo/ui/swift-ui(ネイティブだがβ)、Expo RouterのformSheet(手早く実装)、そして制御性の高いTrueSheet(推奨)。エンジニア向けに実装上のポイントと注意点を簡潔に示します。

Key Points

  • Expo Router(簡易)

    • presentation: 'formSheet'sheetAllowedDetents: [0.1, 0.5, 1] を設定するとApple Maps風の挙動に近い。
    • contentStyle: { backgroundColor: 'transparent' } を必ず指定して液体ガラスを透過させる。
    • sheetInitialDetentIndex: 0 で浮いた最小デテント(角丸・ギャップあり)から開始。制御やカスタム同期は難しい。
  • @expo/ui/swift-ui(実験向け)

    • ネイティブのBottomSheetpresentationDetentsで同等の挙動を出せるが、パッケージはβ段階のため本番導入は慎重に。
  • TrueSheet(制御重視・推奨)

    • ネイティブ実装でblurTint: 'default'により液体ガラス外観を実現。
    • sizesでデテンを指定(数値・%・'medium'/'large'等混在可)。最低高さは明示(例: 75)するのが安定。
    • ref経由でpresent()/dismiss()を呼び、シートのアニメーション値を取得してUIと同期できる。
    • Readmeが未更新のことがあるのでネイティブ挙動を確認しながら実装する。
  • 実務アドバイス

    • デテン設計は意図的に行い、最低デテンは明示して見た目と操作感を固定する。
    • ユーザが下方へドラッグして閉じる挙動を禁止したい場合はgestureEnabled: false等で制御。
    • 可能な限りOSネイティブの描画に任せ、角丸やギャップの変化はデテンで表現する。

Full Translation

翻訳

原文の流れを保ったまま読める翻訳セクションです。

openaijamodel: gpt-5-mini-2025-08-07

ExpoでApple Maps風のLiquid Glass(リキッドグラス)シートを作る方法(本当のやり方)

ExpoでApple Maps風のLiquid Glass(リキッドグラス)シートを作る方法(本当のやり方)

Expo UI、Expo Router、TrueSheet を使って、iOS 26 の新しい Liquid Glass ボトムシートを再現する方法を解説します。スムーズな detent(デタント)遷移と iOS 26 の挙動をできるだけ忠実に再現する手順と注意点をまとめています。

iOS 26 におけるシートの挙動

  • 最低の detent(最小位置)ではシートは“浮いた”状態で、画面上にギャップがあり、角は完全に丸くなっています。
  • 中間の detent にドラッグすると、まだ浮いた状態のままですが画面端に近づき、ギャップが狭まり角丸が変化します。
  • 最高の detent にドラッグするとギャップが消え、浮いたカードのような挙動から通常のフルシートの挙動へ遷移します。

Apple Maps の最新挙動と同じインタラクションが目標です。

試したアプローチ

以下の 3 つのアプローチを試しました。Expo 環境で実現できる順に紹介します。

1) expo-swift-ui の BottomSheet

ネイティブ実装なので Liquid Glass をサポートしています。presentationDetents(または同等の設定)で detents を設定すれば、期待通りの挙動が得られます。ただし現時点では beta のため、本番に出すには注意が必要です。実験用途には最適です。

import { BottomSheet, Host } from "@expo/ui/swift-ui";
<Host style={{ position: "absolute", width }}>
  <BottomSheet
    isOpened={isOpened}
    presentationDragIndicator="visible"
    presentationDetents={[0.1, 0.5, 1]}
    onIsOpenedChange={(e) => setIsOpened(e)}
  >
    <Text>Hello, world!</Text>
  </BottomSheet>
</Host>

ここでは isOpened state でシートを制御しています。detents は 0 から 1(フル高さ)で指定します。presentationDragIndicator は上部のハンドル(ドラッグインジケーター)です。

2) Expo Router の formSheet プレゼンテーション

Evan Bacon が 𝕏(Twitter)で共有していた方法を試すと期待通りに動きました。基本的なシート挙動を手早く実現できます。

<Stack.Screen
  name="liquidGlassSheet"
  options={{
    headerShown: false,
    presentation: "formSheet",
    gestureEnabled: false,
    sheetGrabberVisible: true,
    contentStyle: { backgroundColor: "transparent" },
    sheetAllowedDetents: [0.1, 0.5, 1],
    sheetInitialDetentIndex: 0,
    sheetLargestUndimmedDetentIndex: 0,
  }}
/>

ポイント:

  • sheetGrabberVisible は上部のドラッグインジケーターです。
  • Liquid Glass 表現を通すために contentStyle の backgroundColor を "transparent" にする必要があります。
  • detents の範囲は 0 〜 1(前述)です。
  • gestureEnabled: false にしておくと、ユーザーが下方向へドラッグして閉じるのを無効化できます。
  • sheetInitialDetentIndex: 0 を設定すると初期位置が 0.1(シートが浮いた状態・角丸)になります。

この方法は「普通のシート」を手早く出すには完璧ですが、カスタムフッターやシートの移動に同期した細かなアニメーション制御が必要なケースでは柔軟性に欠けます。

3) TrueSheet(Jovanni Lo / @lodev09)

細かい制御やアニメーション同期が必要なら TrueSheet が非常に良い選択です。ネイティブ実装でシート背景のブラー(iOS 26 では Liquid Glass)をサポートし、detents、フッター、アニメーション値の取得などができます。

const sheet = useRef<TrueSheet>(null);
<TrueSheet ref={sheet} sizes={[75, "medium", "large"]} blurTint="default">
  <View>
    <Button title="Close Sheet" onPress={() => sheet.current?.dismiss()} />
  </View>
</TrueSheet>
<Button title="Open Sheet" onPress={() => sheet.current?.present()} />

ポイント:

  • シートは ref 経由で制御します(Gorhom の Sheet と同様)。
  • sizes が detents を制御します。数値、パーセンテージ、または "auto", "medium", "large" のようなプリセット文字列を混在して使えます。
  • Auto sizing が完全に安定しない場合は最低高さを明示的に指定(例: 75)してください。
  • Liquid Glass 表現には blurTint="default" を使います。
  • README がまだ最新でない可能性がありますが、ネイティブ API を呼んでいるため効果は問題なく動作します。

結論と推奨

  • 迅速に試したい場合: Expo Router の formSheet は最も手軽で多くのケースに十分です。
  • 細かい制御やアニメーション同期が必要な場合: TrueSheet が最も柔軟で本物に近い表現を提供します。
  • expo-swift-ui はネイティブで直接 Liquid Glass を扱えますが、beta のため本番運用は慎重に。

detents の値は意図的に決めて、OS のレンダリングに任せる(vibe を活かす)ことをおすすめします。

React Native のアニメーションやトリックに興味がある方は、筆者が 𝕏(@iamarunabh)で投稿しているのでそちらもチェックしてください。