Flutter 颤振:使剪切区域对滚动列表视图透明

Flutter 颤振:使剪切区域对滚动列表视图透明,flutter,listview,clipping,Flutter,Listview,Clipping,我有一个列表视图,当它点击另一个小部件的剪辑时,我想“消失” 这是我的密码 import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: MyHomePage

我有一个
列表视图
,当它点击另一个小部件的剪辑时,我想“消失”

这是我的密码

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          TopWidget(),
          Expanded(
            child: ListView(
              itemExtent: 100,
              children: <Widget>[
                Card(color: Colors.green,),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class TopWidget extends StatelessWidget {
  TopWidget();

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: ShadowPainter(),
      child: ClipPath(
        clipper: TopWidgetClipper(),
        child: Container(
          height: 370,
          color: Colors.blue,
        ),
      ),
    );
  }
}

class TopWidgetClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    Offset controllPoint1 = Offset(0, size.height - 100);
    Offset endPoint1 = Offset(100, size.height - 100);
    Offset controllPoint2 = Offset(size.width, size.height - 100);
    Offset endPoint2 = Offset(size.width, size.height - 200);
    Path path = Path()
      ..lineTo(0, size.height)
      ..quadraticBezierTo(
          controllPoint1.dx, controllPoint1.dy, endPoint1.dx, endPoint1.dy)
      ..lineTo(size.width - 100, size.height - 100)
      ..quadraticBezierTo(
          controllPoint2.dx, controllPoint2.dy, endPoint2.dx, endPoint2.dy)
      ..lineTo(size.width, 0);
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return true;
  }
}

class ShadowPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    Offset controllPoint1 = Offset(0, size.height - 100);
    Offset endPoint1 = Offset(100, size.height - 100);
    Offset controllPoint2 = Offset(size.width, size.height - 100);
    Offset endPoint2 = Offset(size.width, size.height - 200);
    Path path = Path()
      ..lineTo(0, size.height)
      ..quadraticBezierTo(
          controllPoint1.dx, controllPoint1.dy, endPoint1.dx, endPoint1.dy)
      ..lineTo(size.width - 100, size.height - 100)
      ..quadraticBezierTo(
          controllPoint2.dx, controllPoint2.dy, endPoint2.dx, endPoint2.dy)
      ..lineTo(size.width, 0);

    canvas.drawShadow(path, Colors.grey[50], 3.0, false);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}
导入“包装:颤振/材料.省道”;
void main(){
runApp(MyApp());
}
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回材料PP(
主页:MyHomePage(),
);
}
}
类MyHomePage扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回脚手架(
正文:专栏(
儿童:[
TopWidget(),
扩大(
子:ListView(
项目范围:100,
儿童:[
卡片(颜色:Colors.green,),
],
),
),
],
),
);
}
}
类TopWidget扩展了无状态Widget{
TopWidget();
@凌驾
小部件构建(构建上下文){
返回自定义油漆(
画家:阴影画家(),
孩子:克利帕斯(
clipper:TopWidgetClipper(),
子:容器(
身高:370,
颜色:颜色,蓝色,
),
),
);
}
}
类TopWidgetClipper扩展了CustomClipper{
@凌驾
路径getClip(大小){
偏移量控制点1=偏移量(0,size.height-100);
偏移端点1=偏移(100,size.height-100);
偏移量控制点2=偏移量(大小.宽度,大小.高度-100);
偏移端点2=偏移(大小.宽度,大小.高度-200);
路径路径=路径()
..lineTo(0,尺寸。高度)
…方贝塞尔托(
ControlPoint1.dx,ControlPoint1.dy,endPoint1.dx,endPoint1.dy)
…lineTo(尺寸.宽度-100,尺寸.高度-100)
…方贝塞尔托(
ControlPoint2.dx,ControlPoint2.dy,endPoint2.dx,endPoint2.dy)
..lineTo(尺寸.宽度,0);
返回路径;
}
@凌驾
bool shouldReclip(CustomClipper oldClipper){
返回true;
}
}
类ShadowPainter扩展了CustomPainter{
@凌驾
空心油漆(帆布,尺寸){
偏移量控制点1=偏移量(0,size.height-100);
偏移端点1=偏移(100,size.height-100);
偏移量控制点2=偏移量(大小.宽度,大小.高度-100);
偏移端点2=偏移(大小.宽度,大小.高度-200);
路径路径=路径()
..lineTo(0,尺寸。高度)
…方贝塞尔托(
ControlPoint1.dx,ControlPoint1.dy,endPoint1.dx,endPoint1.dy)
…lineTo(尺寸.宽度-100,尺寸.高度-100)
…方贝塞尔托(
ControlPoint2.dx,ControlPoint2.dy,endPoint2.dx,endPoint2.dy)
..lineTo(尺寸.宽度,0);
画布.drawShadow(路径,颜色.灰色[50],3.0,假);
}
@凌驾
bool应重新绘制(自定义代理){
返回true;
}
}
到目前为止,当我向下滚动时,当列表(绿色框)到达我裁剪的
TopWidget
的容器底部(黄色边框)时,它就看不见了。但我希望列表只有在到达剪辑边缘时才能平滑地消失(如第二个屏幕截图中的蓝色区域)


你知道我怎样才能做到这一点吗?谢谢大家!

正如我从@pskink(谢谢)学到的,在这样的用例中,您需要小部件实际调整其边界(spoiler:shape),您应该使用不同小部件的
shape
属性,并在扩展
shapeorder
的自定义类中使用本例中使用的
路径。最简单的方法是:

容器(
身高:370,
装饰:造型装饰(
颜色:颜色,蓝色,
形状:AppBarBorder(),
///您还可以指定一些整洁的阴影投射到在这个阴影下滚动的小部件上
阴影:[
箱形阴影(
颜色:颜色。黑色。不透明度(0.7),
半径:18.0,
扩展半径:2.0,
),
],
),
),
和自定义类:

类AppBarBorder扩展了ShapeBorder{
@凌驾
路径getOuterPath(Rect Rect,{TextDirection TextDirection}){
偏移量控制点1=偏移量(0,rect.size.height-100);
偏移端点1=偏移(100,rect.size.height-100);
偏移量控制点2=偏移量(rect.size.width,rect.size.height-100);
偏移端点2=偏移(rect.size.width,rect.size.height-200);
返回路径()
…lineTo(0,矩形尺寸高度)
…方贝塞尔托(
ControlPoint1.dx,ControlPoint1.dy,endPoint1.dx,endPoint1.dy)
..lineTo(rect.size.width-100,rect.size.height-100)
…方贝塞尔托(
ControlPoint2.dx,ControlPoint2.dy,endPoint2.dx,endPoint2.dy)
..lineTo(rect.size.width,0);
}
@凌驾
EdgeInSetGeometry get dimensions=>EdgeInsets.only(底部:0);
@凌驾
路径getInnerPath(Rect Rect,{TextDirection TextDirection})=>null;
@凌驾
void paint(画布画布,Rect Rect,{TextDirection TextDirection}){
@凌驾
形状顺序比例(双t)=>此;
}
与声明
CustomClipper
CustomPainter
的方法几乎相同,因为您不需要实现这些方法中的大多数,基本上只需要关心
getOuterPath

最后,我们需要重新构造布局本身,因为当前您有一个带有此自定义
容器
形状的
,下面是
列表视图
。由于
容器
不属于
列表视图
的一部分,因此不能将其滚动到下面或其他位置。最简单的方法是使用
堆栈

堆栈(
儿童:[
扩大(
子:ListView(
填充:仅限边缘设置(顶部:370.0),
项目范围:100,
儿童:[
卡片(
颜色:颜色。绿色,
),
],
),
),
容器(
身高:370,
装饰:造型装饰(
颜色:颜色,蓝色,
形状:AppBarBorder