Flutter卡片样式调整:实现1/3白背景、1/3模糊、剩余原图效果
Flutter卡片实现1/3原图+1/3模糊+1/3白色信息栏
当前效果

当前卡片的模糊效果覆盖了整个图片区域,而非仅中间1/3部分。
预期效果

需要实现顶部1/3为原图、中间1/3为模糊效果、底部1/3为白色信息栏的卡片样式。
现有代码
import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:trailx_app/const/colors.dart'; class FypHikingCards extends StatefulWidget { const FypHikingCards({super.key}); @override State<FypHikingCards> createState() => _FypHikingCards(); } class _FypHikingCards extends State<FypHikingCards> { final List<String> images = List<String>.generate(8, (index) => "Item $index"); final List<String> imagePaths = [ 'assets/images/hiking_0.png', 'assets/images/hiking_1.png', 'assets/images/hiking_2.png', 'assets/images/hiking_3.png', 'assets/images/hiking_4.png', 'assets/images/hiking_5.png', 'assets/images/hiking_6.png', 'assets/images/hiking_7.png' ]; final List<bool> liked = List<bool>.filled(8, false); @override Widget build(BuildContext context) { return GridView.builder( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 2.0, mainAxisSpacing: 2.0, childAspectRatio: 2 / 2.2, ), itemCount: 8, itemBuilder: (context, index) { return Center( child: Stack( children: [ Card( clipBehavior: Clip.antiAliasWithSaveLayer, elevation: 2, child: Column( mainAxisSize: MainAxisSize.min, children: <Widget>[ // This part holds the image with the blur at the bottom 1/3 Expanded( flex: 2, child: Stack( children: [ // Full image in the background Positioned.fill( child: Image.asset( imagePaths[index], fit: BoxFit.fill, width: double.infinity, ), ), // Blur the bottom part of the image with a fixed height Positioned( bottom: 0, left: 0, right: 0, child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), child: Container( color: Colors.black.withOpacity( 0), // Transparent container for blur ), ), ), ], ), ), // Text information in the white box Padding( padding: const EdgeInsets.all(8.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ SizedBox( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Length", style: GoogleFonts.getFont('Inter', color: Colors.black, fontSize: 8, fontWeight: FontWeight.w500), ), Text( "1.69 Mi", style: GoogleFonts.getFont('Inter', color: loginGreenColor, fontSize: 12, fontWeight: FontWeight.w600), ), Text( "Duration", style: GoogleFonts.getFont('Inter', color: Colors.black, fontSize: 8, fontWeight: FontWeight.w500), ), Text( "1.5 Hr", style: GoogleFonts.getFont('Inter', color: loginGreenColor, fontSize: 12, fontWeight: FontWeight.w600), ), ], ), ), SizedBox( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Distance", style: GoogleFonts.getFont('Inter', color: Colors.black, fontSize: 8, fontWeight: FontWeight.w500), ), Text( "6,321 Ft", style: GoogleFonts.getFont('Inter', color: loginGreenColor, fontSize: 12, fontWeight: FontWeight.w600), ), Text( "Difficulty", style: GoogleFonts.getFont('Inter', color: Colors.black, fontSize: 8, fontWeight: FontWeight.w500), ), Text( "Medium", style: GoogleFonts.getFont('Inter', color: loginGreenColor, fontSize: 12, fontWeight: FontWeight.w600), ), ], ), ), ], ), ), ], ), ), Positioned( top: 0, right: 0, child: IconButton( color: likedColor, icon: liked[index] ? const Icon(Icons.favorite) : const Icon( Icons.favorite_border, ), onPressed: () { setState(() { liked[index] = !liked[index]; }); }, ), ), ], ), ); }, ); } }
解决方案
问题出在模糊层没有限制高度,默认铺满了整个图片区域。我们需要将模糊层的高度限制为图片区域的1/2(因为图片区域占卡片总高度的2/3,这样模糊层刚好占卡片的1/3),同时调整位置让它覆盖图片的下半部分(即卡片的中间1/3)。
修改后的核心代码片段:
Expanded( flex: 2, child: LayoutBuilder( builder: (context, constraints) { final imageHeight = constraints.maxHeight; final blurHeight = imageHeight / 2; // 模糊层高度为图片区域的1/2 return Stack( children: [ Positioned.fill( child: Image.asset( imagePaths[index], fit: BoxFit.fill, width: double.infinity, ), ), // 模糊层只覆盖图片下半部分 Positioned( top: blurHeight, // 从图片中间位置开始 left: 0, right: 0, height: blurHeight, // 限制模糊层高度 child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), child: Container( color: Colors.black.withOpacity(0.1), // 可加轻微透明度增强效果 ), ), ), ], ); }, ), ),
这样调整后,模糊层就只会覆盖图片区域的下半部分,刚好对应卡片的中间1/3区域,顶部1/3是清晰原图,底部1/3是白色信息栏,完全符合预期效果。
内容的提问来源于stack exchange,提问作者Liu Terry
相关产品推荐
相关产品推荐

