准备工作

  1. 自己准备的全景图
  2. pannellum.js文件
  3. pannellum.css文件

正式步骤

  • 将准备的三个文件移动到assets文件夹下

  • 在assets文件夹下创建index.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Panorama</title>

    <link rel="stylesheet" href="pannellum.css"/>

    <script type="text/javascript" src="pannellum.js"></script>

    <style>
    html, body {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
    overflow: hidden; /* 隐藏滚动条 */
    }
    #panorama {
    width: 100%;
    height: 100%;
    }
    </style>
    </head>
    <body>

    <div id="panorama"></div>

    <script>
    // 5. 初始化 Pannellum
    pannellum.viewer('panorama', {
    "type": "equirectangular",
    "panorama": "my_panorama.jpg", // <-- 确保这个名字和你的图片文件名一致
    "autoLoad": true,
    "showControls": true // 显示控制按钮 (缩放、全屏)
    });
    </script>

    </body>
    </html>
  • 布局添加webview

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    <androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.scenery.SceneryFragment">

    <WebView
    android:id="@+id/webView"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

    <View
    android:id="@+id/scrim"
    android:layout_width="0dp"
    android:layout_height="160dp"
    android:background="@drawable/scrim_bottom_dark"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

    <TextView
    android:id="@+id/sceneryText"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:textColor="@android:color/white"
    android:textSize="18sp"
    android:textAlignment="center"
    android:lineSpacingExtra="4dp"

    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"

    android:layout_marginBottom="32dp"
    android:layout_marginStart="24dp"
    android:layout_marginEnd="24dp"
    />

    </androidx.constraintlayout.widget.ConstraintLayout>
  • 在drawable里面添加渐变scrim_bottom_dark.xml

    1
    2
    3
    4
    5
    6
    7
    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
    android:angle="90"
    android:startColor="#B3000000"
    android:endColor="@android:color/transparent" />
    </shape>
  • 界面布局

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    // 定义延迟和动画时长 (毫秒)
    private val START_DELAY_MS = 5000L // 5秒后开始
    private val FADE_DURATION_MS = 1000L // 1秒渐变
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    //配置WebView
    setupWebView()
    //在这里启动淡出动画逻辑
    startFadeOutAnimation()
    }
    private fun startFadeOutAnimation() {
    // 启动一个与 Fragment 视图生命周期绑定的协程
    viewLifecycleOwner.lifecycleScope.launch {
    // 等待 5 秒
    delay(START_DELAY_MS)

    // 确保视图仍然存在(例如用户没有立即退出)
    if (binding == null) return@launch

    //同时执行蒙版和文本的淡出动画
    binding.scrim.animate()
    .alpha(0f)// 透明度变为 0(完全透明)
    .setDuration(FADE_DURATION_MS)// 持续时间
    .withEndAction {
    // 动画结束后,彻底隐藏视图
    binding.scrim.visibility = View.GONE
    }
    .start()

    binding.sceneryText.animate()
    .alpha(0f)
    .setDuration(FADE_DURATION_MS)
    .withEndAction {
    // 动画结束后,彻底隐藏视图
    binding.sceneryText.visibility = View.GONE
    }
    .start()
    }
    }

    //配置WebView
    @SuppressLint("SetJavaScriptEnabled")
    private fun setupWebView() {
    // (这是您配置 WebView 的代码)
    val webSettings: WebSettings = binding.webView.settings
    webSettings.javaScriptEnabled = true
    webSettings.allowFileAccess = true
    webSettings.allowContentAccess = true
    webSettings.allowFileAccessFromFileURLs = true
    webSettings.allowUniversalAccessFromFileURLs = true
    //加载你项目中的本地网页
    binding.webView.loadUrl("file:///android_asset/index.html")
    }