uniapp

使用 blur 毛玻璃; blur 详细教程

<template>
  <view class="container" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd">
    <scroll-view
      scroll-y
      style="height: 100vh;"
      @scroll="onScroll"
    >
      <view v-for="i in 40" :key="i" class="item">内容 {{ i }}</view>
    </scroll-view>

    <!-- 底部菜单 -->
    <view
      class="bottom-nav"
      :style="{
        transform: `translateY(${translateY}px) scale(${scale})`,
        transition: isTouching ? 'none' : 'all 0.3s ease'
      }"
    >
      <view class="nav-item" v-for="(item, i) in navList" :key="i">
        <image :src="item.icon" class="nav-icon" />
        <text class="nav-text">{{ item.text }}</text>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref } from 'vue'

const translateY = ref(0)
const scale = ref(1)
const startY = ref(0)
const isTouching = ref(false)
const navList = [
  { icon: '/static/home.png', text: '首页' },
  { icon: '/static/shop.png', text: '商城' },
  { icon: '/static/user.png', text: '我的' }
]

const touchStart = (e) => {
  startY.value = e.touches[0].clientY
  isTouching.value = true
}
const touchMove = (e) => {
  const diff = e.touches[0].clientY - startY.value
  // 向上滑动时上移并放大
  translateY.value = Math.min(0, diff)
  scale.value = 1 + Math.min(0.15, Math.abs(diff) / 200)
}
const touchEnd = () => {
  isTouching.value = false
  translateY.value = 0
  scale.value = 1
}
const onScroll = (e) => {
  // 可扩展:滚动时渐隐或移动菜单
}
</script>

<style scoped>
.container {
  position: relative;
  overflow: hidden;
}
.item {
  height: 100rpx;
  line-height: 100rpx;
  text-align: center;
  background: #f8f8f8;
  margin-bottom: 10rpx;
}
.bottom-nav {
  position: fixed;
  bottom: 20rpx;
  left: 50%;
  transform: translateX(-50%);
  width: 90%;
  height: 120rpx;
  border-radius: 40rpx;
  background: rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(20rpx);
  display: flex;
  justify-content: space-around;
  align-items: center;
  transition: all 0.3s ease;
}
.nav-item {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.nav-icon {
  width: 60rpx;
  height: 60rpx;
}
.nav-text {
  font-size: 24rpx;
  color: #fff;
}
</style>

  • 毛玻璃使用 backdrop-filter;

拖动时放大,松开恢复;

兼容 App、H5、小程序(部分小程序 blur 支持有限)。

flutter实现

  • 用到的组件
  • BackdropFilter:毛玻璃;

  • GestureDetector:监听手势;

  • AnimatedContainer 或 Transform.scale:平滑放大;

  • SingleChildScrollView:滑动内容。

import 'dart:ui';
import 'package:flutter/material.dart';

class FrostedBottomBar extends StatefulWidget {
  @override
  _FrostedBottomBarState createState() => _FrostedBottomBarState();
}

class _FrostedBottomBarState extends State<FrostedBottomBar> {
  double _translateY = 0;
  double _scale = 1.0;
  bool _isDragging = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onVerticalDragUpdate: (details) {
          setState(() {
            _isDragging = true;
            _translateY = details.primaryDelta!.clamp(-60.0, 0.0);
            _scale = 1 + (_translateY.abs() / 300);
          });
        },
        onVerticalDragEnd: (_) {
          setState(() {
            _isDragging = false;
            _translateY = 0;
            _scale = 1.0;
          });
        },
        child: Stack(
          children: [
            ListView.builder(
              itemCount: 40,
              itemBuilder: (context, i) => ListTile(title: Text("Item $i")),
            ),
            Positioned(
              bottom: 20,
              left: 0,
              right: 0,
              child: AnimatedContainer(
                duration: Duration(milliseconds: _isDragging ? 0 : 300),
                transform: Matrix4.identity()
                  ..translate(0.0, _translateY)
                  ..scale(_scale),
                alignment: Alignment.bottomCenter,
                child: ClipRRect(
                  borderRadius: BorderRadius.circular(40),
                  child: BackdropFilter(
                    filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
                    child: Container(
                      height: 80,
                      margin: EdgeInsets.symmetric(horizontal: 20),
                      decoration: BoxDecoration(
                        color: Colors.white.withOpacity(0.2),
                        borderRadius: BorderRadius.circular(40),
                      ),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: const [
                          Icon(Icons.home, color: Colors.white),
                          Icon(Icons.shopping_cart, color: Colors.white),
                          Icon(Icons.person, color: Colors.white),
                        ],
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

  • 毛玻璃完全原生(BackdropFilter);
  • 拖动平滑放大,松手回弹;
  • iOS 样式极佳,流畅度接近原生 Dock。
框架 优点 缺点 适用场景
UniApp 轻量,适配多端 毛玻璃在部分小程序不支持 商业小程序、兼容App
Flutter 动画丝滑、质感最接近iOS原生 打包体积大 高端App、iOS视觉追求
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐