You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flutter自定义透明背景AppBar:解决ListView上移遮挡问题

嘿,这个问题我之前也遇到过!当AppBar设为透明时,ListView确实会默认延伸到它的下方,不过咱们可以通过几个简单的调整来解决:

问题根源

你的代码里有两个小问题导致了这个现象:

  1. NestedScrollViewbody里用了Expanded,这完全是多余的——NestedScrollView的body本身就支持滚动视图,不需要额外的Expanded来约束空间。
  2. ListView没有设置顶部内边距,所以内容会从屏幕最顶端开始,自然就被透明的AppBar挡住了。

解决方案

我帮你修改了代码,主要做了这几个调整:

  1. 移除NestedScrollView body里的Expanded,直接放ListView。
  2. 计算AppBar的总高度(包括底部的搜索栏AppBar),给ListView设置对应的顶部padding,确保内容从AppBar下方开始。
  3. 顺便优化了一下布局的稳定性,适配不同屏幕场景。

修改后的完整代码:

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

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, this.title = "Hallo"}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    // 计算AppBar总高度:状态栏高度 + 主AppBar高度 + 底部搜索栏AppBar高度
    final double totalAppBarHeight = 
        MediaQuery.of(context).padding.top + 
        kToolbarHeight + 
        AppBar().preferredSize.height;

    return Scaffold(
      body: Container(
        decoration: BoxDecoration(
          image: DecorationImage(
            alignment: Alignment.topRight,
            image: AssetImage("lib/assets/images/Bg.png"),
          ),
        ),
        child: Container(
          decoration: BoxDecoration(
            image: DecorationImage(
              alignment: Alignment.topRight,
              image: AssetImage(
                "lib/assets/images/Bg2.png",
              ),
              scale: 1.05,
            ),
          ),
          child: NestedScrollView(
            headerSliverBuilder: (context, innerBoxIsScrolled) => [
              SliverAppBar(
                elevation: 0,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.vertical(
                    bottom: Radius.circular(30),
                  ),
                ),
                backgroundColor: Colors.transparent,
                automaticallyImplyLeading: false,
                floating: true,
                snap: false,
                pinned: true,
                title: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text(
                      "Startseite",
                      style: TextStyle(color: Colors.black),
                    ),
                    Row(
                      children: [
                        Container(
                            decoration: BoxDecoration(
                                gradient: LinearGradient(
                                  colors: [
                                    Color.fromARGB(255, 197, 193, 193),
                                    Color.fromARGB(255, 167, 156, 156)
                                        .withOpacity(0.8),
                                  ],
                                  begin: Alignment.topLeft,
                                  end: Alignment.bottomRight,
                                ),
                                borderRadius: BorderRadius.circular(12)),
                            padding: EdgeInsets.all(2),
                            child: Icon(Icons.notifications)),
                        SizedBox(width: 10),
                        ClipOval(
                          child: Container(
                            decoration: BoxDecoration(
                              gradient: LinearGradient(
                                colors: [
                                  Color(0xFFFFFFFF),
                                  Color(0xFF000000).withOpacity(0),
                                ],
                                begin: Alignment.topLeft,
                                end: Alignment.bottomRight,
                              ),
                              borderRadius: BorderRadius.circular(16),
                            ),
                            padding: EdgeInsets.all(10),
                            child: Container(
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(10),
                                image: DecorationImage(
                                  image: ExactAssetImage(
                                      'lib/assets/images/baki.jpg'),
                                  fit: BoxFit.fill,
                                ),
                              ),
                            ),
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
                bottom: AppBar(
                  elevation: 0,
                  automaticallyImplyLeading: false,
                  backgroundColor: Colors.transparent,
                  title: Container(
                    decoration: BoxDecoration(borderRadius: BorderRadius.circular(12)),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Padding(
                          padding: const EdgeInsets.only(bottom: 10.0),
                          child: Stack(
                            children: [
                              Padding(
                                padding: const EdgeInsets.only(top: 3.0),
                                child: Container(
                                  width: MediaQuery.of(context).size.width * 0.5,
                                  height: MediaQuery.of(context).size.height * 0.025,
                                  decoration: BoxDecoration(
                                    gradient: LinearGradient(
                                      colors: [
                                        Color(0xFF4B4646).withOpacity(0.6),
                                        Color(0xFFFFFFFF).withOpacity(0.2),
                                      ],
                                      begin: Alignment.centerLeft,
                                      end: Alignment.centerRight,
                                    ),
                                    borderRadius: BorderRadius.circular(12),
                                  ),
                                  child: Padding(
                                    padding: const EdgeInsets.symmetric(
                                        vertical: 5.0),
                                    child: Padding(
                                      padding: const EdgeInsets.only(left: 4.0),
                                      child: Text(
                                        "Suchen",
                                        textAlign: TextAlign.start,
                                        style: TextStyle(
                                            fontFamily: "Acme-Regular",
                                            color: Colors.grey.shade200,
                                            fontSize: 10),
                                      ),
                                    ),
                                  ),
                                ),
                              ),
                              Padding(
                                padding: const EdgeInsets.only(
                                  left: 170.0,
                                ),
                                child: Container(
                                    decoration: BoxDecoration(
                                        color: Colors.grey.shade300.withOpacity(0.4),
                                        borderRadius: BorderRadius.circular(12)),
                                    padding: EdgeInsets.all(5),
                                    child: Icon(Icons.search, size: 20, color: Colors.green)),
                              ),
                            ],
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.only(bottom: 12),
                          child: Container(
                              decoration: BoxDecoration(
                                  color: Colors.grey.shade300.withOpacity(0.4),
                                  borderRadius: BorderRadius.circular(12)),
                              child: Icon(Icons.filter_alt, size: 22, color: Colors.green)),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            ],
            // 移除多余的Expanded,直接使用ListView
            body: ListView(
              // 设置顶部padding为计算好的总高度,左右下保持原有的8
              padding: EdgeInsets.only(
                top: totalAppBarHeight,
                left: 8,
                right: 8,
                bottom: 8,
              ),
              children: <Widget>[
                Container(
                  height: 50,
                  color: Colors.amber[600],
                  child: const Center(child: Text('Entry A')),
                ),
                Container(
                  height: 50,
                  color: Colors.amber[500],
                  child: const Center(child: Text('Entry B')),
                ),
                Container(
                  height: 50,
                  color: Colors.amber[100],
                  child: const Center(child: Text('Entry C')),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

额外说明

这段代码里我把状态栏高度也加入了计算,这样即使在不同的设备上(比如带刘海屏的手机),内容也不会被状态栏或者AppBar遮挡,适配性更强。如果你的场景不需要考虑状态栏,直接去掉MediaQuery.of(context).padding.top这部分即可。

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

火山引擎 最新活动