如何使我的滚动条在图像上不会切断其圆形容器顶部?

问题描述 投票:0回答:1

我设计了一个控制器,允许在顶部有一个图像,在下面有一个滚动容器。 当用户向上滚动时,图像会缩小其尺寸,同时滚动其余部分。

我遇到的问题是,当我们向上滚动时,容器被剪掉(参见照片)。

我该如何度过这个难关?

向下滚动就可以了

Scrolling down is OK

向上滚动会切断我的圆形容器:如何解决这个问题?

Scrolling up cuts off my rounded container: how to address this?

我的小部件代码:


/// A Scrolling widget that have an image at the top and a csolling container
/// below
class ScrollingImageWidget extends StatefulWidget {
  final String imagePath;
  final List<Widget> children;
  final double imageCoverRate;
  const ScrollingImageWidget({
    super.key,
    required this.imagePath,
    required this.children,
    this.imageCoverRate = 0.9,
  });

  @override
  State<ScrollingImageWidget> createState() => _ScrollingImageWidgetState();
}

class _ScrollingImageWidgetState extends State<ScrollingImageWidget> {
  late final size = MediaQuery.of(context).size;

  late final normalImageHeight = size.height / 4 * widget.imageCoverRate;
  late double imageHeight = size.height / 4;
  final _scrollController = ScrollController();
  double? scrollDelta;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: const BoxDecoration(
          // color: Colors.pink,
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(60),
            topRight: Radius.circular(60),
          ),
        ),
        width: size.width,
        height: size.height,
        child: Stack(
          children: [
            // The image

            // AnimatedContainer(
            //   duration: const Duration(milliseconds: 20),
            //   curve: Curves.easeInOut,
            SizedBox(
              height: imageHeight,
              width: double.infinity,
              child: Image.asset(
                widget.imagePath,
                height: imageHeight,
                width: double.infinity,
                fit: BoxFit.cover,
              ),
            ),

            // Text("image height: $imageHeight vs ${size.height / 4}\nscrol delta: ${scrollDelta}"),

            // The scrolling content
            NotificationListener<ScrollNotification>(
              // Listen for scroll events
              onNotification: (notification) {
                if (notification is ScrollUpdateNotification) {
                  final rate =
                      _scrollController.position.pixels < 0 ? 4.0 : 1.0;
                  setState(() {
                    scrollDelta = notification.scrollDelta;
                    imageHeight = normalImageHeight -
                        _scrollController.position.pixels * rate;
                    // Clamp imageHeight to prevent negative values
                    imageHeight = imageHeight.clamp(0.0, size.height * .9);
                  });
                }
                return true; // Allow further notification propagation
              },
              child: Positioned(
                top: imageHeight * widget.imageCoverRate,
                child: SizedBox(
                  width: size.width,
                  height: size.height * 0.9 - imageHeight,
                  // child: Scrollbar(
                  // controller: _scrollController,
                  // thumbVisibility: true,
                  // trackVisibility: true,
                  child: ListView.builder(
                    controller: _scrollController,
                    physics: const BouncingScrollPhysics(),
                    itemCount: widget.children.length,
                    itemBuilder: (context, index) => widget.children[index],
                  ),
                  // ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }
}

我如何实例化滚动条:


class SettingsScreen extends StatelessWidget {
  const SettingsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return ScrollingImageWidget(
      imagePath: "./lib/assets/images/speakbetter.main.jpg",
      children: [
        Container(
          decoration: const BoxDecoration(
            color: Colors.amber,
            borderRadius: BorderRadius.only(
              topLeft: Radius.circular(64),
              topRight: Radius.circular(64),
            ),
            boxShadow: [
              BoxShadow(
                color: Colors.grey, //.withOpacity(0.5),
                spreadRadius: 5,
                blurRadius: 7,
                offset: Offset(
                    0, 3), // Adjust the offset to control the shadow direction
              ),
            ],
          ),
          child: Padding(
            padding: const EdgeInsets.all(32),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  "Read the following",
                  style: Theme.of(context)
                      .textTheme
                      .headlineLarge
                      ?.copyWith(fontWeight: ui.FontWeight.w900),
                ),

                Container(
                   color: Colors.green,
                   width: double.infinity,
                   height: 350,
                   child: const Text("Container 2/3")),
                Container(
                   color: Colors.blue,
                   width: double.infinity,
                   height: 550,
                   child: const Text("Container 3/3")),
              ],
            ),
          ),
        ),
      ],
    );
  }
}

flutter scroll
1个回答
0
投票

要解决剪切问题,请将外部

Container
(琥珀色的)移到
ScrollingImageWidget
内,并将其包裹在
ListView.builder
周围。另外,请确保将
clipBehavior
属性设置为
Clip.hardEdge
,这样当子项超出容器的顶部边框时,它们就会被剪掉。

Container(
  width: size.width,
  height: size.height * 0.9 - imageHeight,
  clipBehavior: Clip.hardEdge, // Ensures content is clipped at the container's border
  decoration: const BoxDecoration(
    color: Colors.amber,
    borderRadius: BorderRadius.only(
      topLeft: Radius.circular(64),
      topRight: Radius.circular(64),
    ),
    boxShadow: [
      BoxShadow(
        color: Colors.grey,
        spreadRadius: 5,
        blurRadius: 7,
        offset: Offset(0, 3),
      ),
    ],
  ),
  child: ListView.builder(
    controller: _scrollController,
    physics: const BouncingScrollPhysics(),
    itemCount: widget.children.length,
    itemBuilder: (context, index) => widget.children[index],
  ),
)

额外提示:

最好使用

MediaQuery.sizeOf(context)
而不是
MediaQuery.of(context).size
以防止不必要的重建。这个微小的变化可以提高性能,特别是在滚动过程中严重依赖布局调整的小部件中。

© www.soinside.com 2019 - 2024. All rights reserved.