uniapp/flutter中实现苹果IOS 26 毛玻璃效果、跟随滑动放大动画
uniapp
使用 blur 毛玻璃; blur 详细教程
<template><view class="container" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd"><scroll-viewscroll-ystyle="height: 100vh;"@scroll="onScroll"><view v-for="i in 40" :key="i" class="item">内容 {{ i }}</view></scroll-view><!-- 底部菜单 --><viewclass="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].clientYisTouching.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 = falsetranslateY.value = 0scale.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;@overrideWidget 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视觉追求 |
