You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter年龄选择页添加随滑块变化的人物剪影过渡效果

最佳实现方案

核心思路是基于滑块值的渐变透明度叠加,将不同年龄段的人物剪影重叠放置,通过滑块值实时计算每个剪影的显示透明度,配合CSS过渡实现平滑的年龄视觉变化。具体步骤:

  • 准备5个阶段的剪影资源:覆盖10岁(男孩)、30岁(少年)、50岁(青年)、70岁(中年)、90岁(老人)关键节点,确保所有剪影尺寸统一。
  • 用绝对定位将所有剪影叠加在同一容器内,初始状态仅10岁男孩剪影完全显示。
  • 监听滑块的input事件,根据当前滑块值(10-90)计算每个剪影的透明度:滑块值越接近某年龄段阈值,对应剪影透明度越高,其他剪影透明度线性降低。
  • 额外添加轻微缩放、旋转效果,模拟年龄增长带来的体态变化,强化视觉层次感。
可运行代码片段

以下代码用CSS绘制简化的人物剪影(可直接替换为实际剪影图片),实现完整的平滑过渡效果:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>健身App年龄选择</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: Arial, sans-serif;
        }
        .age-select-container {
            max-width: 400px;
            margin: 50px auto;
            padding: 20px;
            text-align: center;
        }
        .slider-container {
            margin: 30px 0;
        }
        #age-slider {
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: #ddd;
            outline: none;
            -webkit-appearance: none;
        }
        #age-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: #2196F3;
            cursor: pointer;
        }
        #age-slider::-moz-range-thumb {
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: #2196F3;
            cursor: pointer;
            border: none;
        }
        .age-display {
            font-size: 24px;
            margin-bottom: 20px;
            font-weight: bold;
        }
        /* 剪影容器:所有剪影叠加 */
        .silhouette-container {
            position: relative;
            width: 120px;
            height: 200px;
            margin: 30px auto;
        }
        .silhouette {
            position: absolute;
            width: 100%;
            height: 100%;
            transition: opacity 0.3s ease, transform 0.3s ease;
            opacity: 0;
        }
        /* 男孩剪影(10岁) */
        .silhouette.boy {
            opacity: 1;
            transform: scale(0.7);
        }
        .silhouette.boy::after {
            content: '';
            position: absolute;
            width: 40px;
            height: 70px;
            background: #333;
            border-radius: 20px 20px 0 0;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
        }
        .silhouette.boy::before {
            content: '';
            position: absolute;
            width: 20px;
            height: 40px;
            background: #333;
            top: 90px;
            left: 35%;
            border-radius: 0 0 10px 10px;
        }
        .silhouette.boy .leg-right {
            position: absolute;
            width: 20px;
            height: 40px;
            background: #333;
            top: 90px;
            right: 35%;
            border-radius: 0 0 10px 10px;
        }
        /* 少年剪影(30岁) */
        .silhouette.teen {
            transform: scale(0.85);
        }
        .silhouette.teen::after {
            content: '';
            position: absolute;
            width: 45px;
            height: 90px;
            background: #333;
            border-radius: 22px 22px 0 0;
            top: 15px;
            left: 50%;
            transform: translateX(-50%);
        }
        .silhouette.teen::before {
            content: '';
            position: absolute;
            width: 22px;
            height: 50px;
            background: #333;
            top: 105px;
            left: 32%;
            border-radius: 0 0 11px 11px;
        }
        .silhouette.teen .leg-right {
            position: absolute;
            width: 22px;
            height: 50px;
            background: #333;
            top: 105px;
            right: 32%;
            border-radius: 0 0 11px 11px;
        }
        /* 青年剪影(50岁) */
        .silhouette.youth {
            transform: scale(1);
        }
        .silhouette.youth::after {
            content: '';
            position: absolute;
            width: 50px;
            height: 95px;
            background: #333;
            border-radius: 25px 25px 0 0;
            top: 10px;
            left: 50%;
            transform: translateX(-50%);
        }
        .silhouette.youth::before {
            content: '';
            position: absolute;
            width: 25px;
            height: 55px;
            background: #333;
            top: 105px;
            left: 30%;
            border-radius: 0 0 12px 12px;
        }
        .silhouette.youth .leg-right {
            position: absolute;
            width: 25px;
            height: 55px;
            background: #333;
            top: 105px;
            right: 30%;
            border-radius: 0 0 12px 12px;
        }
        /* 中年剪影(70岁) */
        .silhouette.middle {
            transform: scale(0.95);
        }
        .silhouette.middle::after {
            content: '';
            position: absolute;
            width: 50px;
            height: 85px;
            background: #333;
            border-radius: 25px 25px 0 0;
            top: 20px;
            left: 50%;
            transform: translateX(-50%) translateY(5px) rotate(-5deg);
        }
        .silhouette.middle::before {
            content: '';
            position: absolute;
            width: 25px;
            height: 50px;
            background: #333;
            top: 105px;
            left: 32%;
            border-radius: 0 0 12px 12px;
            transform: rotate(5deg);
        }
        .silhouette.middle .leg-right {
            position: absolute;
            width: 25px;
            height: 50px;
            background: #333;
            top: 105px;
            right: 32%;
            border-radius: 0 0 12px 12px;
            transform: rotate(-5deg);
        }
        /* 老人剪影(90岁) */
        .silhouette.elder {
            transform: scale(0.8);
        }
        .silhouette.elder::after {
            content: '';
            position: absolute;
            width: 45px;
            height: 75px;
            background: #333;
            border-radius: 22px 22px 0 0;
            top: 30px;
            left: 50%;
            transform: translateX(-50%) translateY(10px) rotate(-10deg);
        }
        .silhouette.elder::before {
            content: '';
            position: absolute;
            width: 22px;
            height: 45px;
            background: #333;
            top: 105px;
            left: 35%;
            border-radius: 0 0 11px 11px;
            transform: rotate(10deg);
        }
        .silhouette.elder .leg-right {
            position: absolute;
            width: 22px;
            height: 45px;
            background: #333;
            top: 105px;
            right: 35%;
            border-radius: 0 0 11px 11px;
            transform: rotate(-10deg);
        }
        .continue-btn {
            padding: 12px 40px;
            background: #4CAF50;
            color: white;
            border: none;
            border-radius: 25px;
            font-size: 16px;
            cursor: pointer;
            margin-top: 20px;
        }
        .continue-btn:hover {
            background: #45a049;
        }
    </style>
</head>
<body>
    <div class="age-select-container">
        <h2>选择你的年龄</h2>
        <div class="slider-container">
            <input type="range" id="age-slider" min="10" max="90" value="10">
            <div class="age-display">当前年龄: <span id="age-value">10</span></div>
        </div>
        <!-- 人物剪影容器 -->
        <div class="silhouette-container">
            <div class="silhouette boy">
                <div class="leg-right"></div>
            </div>
            <div class="silhouette teen">
                <div class="leg-right"></div>
            </div>
            <div class="silhouette youth">
                <div class="leg-right"></div>
            </div>
            <div class="silhouette middle">
                <div class="leg-right"></div>
            </div>
            <div class="silhouette elder">
                <div class="leg-right"></div>
            </div>
        </div>
        <button class="continue-btn">Continue</button>
    </div>

    <script>
        const ageSlider = document.getElementById('age-slider');
        const ageValue = document.getElementById('age-value');
        const silhouettes = {
            boy: document.querySelector('.silhouette.boy'),
            teen: document.querySelector('.silhouette.teen'),
            youth: document.querySelector('.silhouette.youth'),
            middle: document.querySelector('.silhouette.middle'),
            elder: document.querySelector('.silhouette.elder')
        };

        // 计算每个剪影的透明度
        function updateSilhouettes(age) {
            // 各年龄段阈值
            const thresholds = {
                boy: 10,
                teen: 30,
                youth: 50,
                middle: 70,
                elder: 90
            };

            // 计算每个剪影的显示权重
            Object.keys(silhouettes).forEach(key => {
                const threshold = thresholds[key];
                let opacity = 0;

                // 当年龄在当前阈值和下一个阈值之间时,计算透明度
                if (age <= threshold) {
                    // 年龄小于等于当前阈值,和前一个阈值比较
                    const prevKey = Object.keys(thresholds)[Object.keys(thresholds).indexOf(key) - 1];
                    if (prevKey) {
                        const prevThreshold = thresholds[prevKey];
                        if (age >= prevThreshold) {
                            opacity = (threshold - age) / (threshold - prevThreshold);
                        } else {
                            opacity = 1;
                        }
                    } else {
                        opacity = 1;
                    }
                } else {
                    // 年龄大于当前阈值,和后一个阈值比较
                    const nextKey = Object.keys(thresholds)[Object.keys(thresholds).indexOf(key) + 1];
                    if (nextKey) {
                        const nextThreshold = thresholds[nextKey];
                        if (age <= nextThreshold) {
                            opacity = (age - threshold) / (nextThreshold - threshold);
                        }
                    }
                }

                silhouettes[key].style.opacity = opacity;
            });
        }

        // 监听滑块变化
        ageSlider.addEventListener('input', function() {
            const age = parseInt(this.value);
            ageValue.textContent = age;
            updateSilhouettes(age);
        });

        // 初始化
        updateSilhouettes(10);
    </script>
</body>
</html>

代码说明

  • 用CSS绘制了5个不同年龄段的简化剪影,你可以直接替换为实际剪影图片(将.silhouette::after等伪元素的background属性替换为url('你的图片路径')即可)。
  • 通过JavaScript监听滑块输入,实时计算每个剪影的透明度,实现平滑过渡。
  • 添加了缩放和旋转效果,模拟年龄增长带来的体态变化,增强视觉体验。

内容的提问来源于stack exchange,提问作者Promaster

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:24:56