flutter NestedScrollView 与其body中CustomScrollView滑动冲突解决

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

const String _kGalleryAssetsPackage = 'flutter_gallery_assets';

class _Page {
  _Page({this.label});

  final String label;

  String get id => label[0];

  @override
  String toString() => '$runtimeType("$label")';
}

class _CardData {
  const _CardData({this.title, this.imageAsset, this.imageAssetPackage});

  final String title;
  final String imageAsset;
  final String imageAssetPackage;
}

final Map<_Page, List<_CardData>> _allPages = <_Page, List<_CardData>>{
  new _Page(label: 'LEFT'): <_CardData>[
    const _CardData(
      title: 'Vintage Bluetooth Radio',
      imageAsset: 'shrine/products/radio.png',
      imageAssetPackage: _kGalleryAssetsPackage,
    ),
    const _CardData(
      title: 'Sunglasses',
      imageAsset: 'shrine/products/sunnies.png',
      imageAssetPackage: _kGalleryAssetsPackage,
    ),
    const _CardData(
      title: 'Clock',
      imageAsset: 'shrine/products/clock.png',
      imageAssetPackage: _kGalleryAssetsPackage,
    ),
    const _CardData(
      title: 'Red popsicle',
      imageAsset: 'shrine/products/popsicle.png',
      imageAssetPackage: _kGalleryAssetsPackage,
    ),
    const _CardData(
      title: 'Folding Chair',
      imageAsset: 'shrine/products/lawn_chair.png',
      imageAssetPackage: _kGalleryAssetsPackage,
    ),
    const _CardData(
      title: 'Green comfort chair',
      imageAsset: 'shrine/products/chair.png',
      imageAssetPackage: _kGalleryAssetsPackage,
    ),
    const _CardData(
      title: 'Old Binoculars',
      imageAsset: 'shrine/products/binoculars.png',
      imageAssetPackage: _kGalleryAssetsPackage,
    ),
    const _CardData(
      title: 'Teapot',
      imageAsset: 'shrine/products/teapot.png',
      imageAssetPackage: _kGalleryAssetsPackage,
    ),
    const _CardData(
      title: 'Blue suede shoes',
      imageAsset: 'shrine/products/chucks.png',
      imageAssetPackage: _kGalleryAssetsPackage,
    ),
  ],
//  new _Page(label: 'RIGHT'): <_CardData>[
//    const _CardData(
//      title: 'Beachball',
//      imageAsset: 'shrine/products/beachball.png',
//      imageAssetPackage: _kGalleryAssetsPackage,
//    ),
//    const _CardData(
//      title: 'Dipped Brush',
//      imageAsset: 'shrine/products/brush.png',
//      imageAssetPackage: _kGalleryAssetsPackage,
//    ),
//    const _CardData(
//      title: 'Perfect Goldfish Bowl',
//      imageAsset: 'shrine/products/fish_bowl.png',
//      imageAssetPackage: _kGalleryAssetsPackage,
//    ),
//  ],
};

class _CardDataItem extends StatelessWidget {
  const _CardDataItem({this.page, this.data});

  static const double height = 272.0;
  final _Page page;
  final _CardData data;

  @override
  Widget build(BuildContext context) {
    return new Card(
      child: new Padding(
        padding: const EdgeInsets.all(16.0),
        child: new Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            new Align(
              alignment:
                  page.id == 'L' ? Alignment.centerLeft : Alignment.centerRight,
              child: new CircleAvatar(child: new Text('${page.id}')),
            ),
            new SizedBox(
              width: 144.0,
              height: 144.0,
              child: new Image.asset(
                data.imageAsset,
                package: data.imageAssetPackage,
                fit: BoxFit.contain,
              ),
            ),
            new Center(
              child: new Text(
                data.title,
                style: Theme.of(context).textTheme.title,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class ScrollViewDemo extends StatefulWidget {
  @override
  State createState() {
    // TODO: implement createState
    return ScrollViewDemoState();
  }
}

class ScrollViewDemoState extends State {
  static const String routeName = '/material/tabs';
  ScrollController _controller = new ScrollController();
  ScrollController _controller2 = new ScrollController();

  double h = 0;
  double d15;
  double d20;
  double d25;
  double d30;
  double d35;
  double d40;
  double d45;
  double d50;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _controller.addListener(() {
      d15 = ScreenUtil().setWidth(15);

      d20 = ScreenUtil().setWidth(20);
      d25 = ScreenUtil().setWidth(25);

      d30 = ScreenUtil().setWidth(30);
      d35 = ScreenUtil().setWidth(35);

      d50 = ScreenUtil().setWidth(50);

      d40 = ScreenUtil().setWidth(40);
      d45 = ScreenUtil().setWidth(45);

      double d60 = ScreenUtil().setWidth(60);
      double d70 = ScreenUtil().setWidth(70);

      double d80 = ScreenUtil().setWidth(80);
      double d85 = ScreenUtil().setWidth(85);

      double d90 = ScreenUtil().setWidth(90);

      double d100 = ScreenUtil().setWidth(100);

      setState(() {
        if ((_controller.offset > d100)) {
          h = d50;
        } else if ((_controller.offset > d90)) {
          h = d45;
        } else if ((_controller.offset > d80)) {
          h = d40;
        } else if ((_controller.offset > d70)) {
          h = d35;
        } else if ((_controller.offset > d60)) {
          h = d30;
        } else if ((_controller.offset > d50)) {
          h = d25;
        } else if ((_controller.offset > d40)) {
          h = d20;
        } else if ((_controller.offset > d30)) {
          h = d15;
        } else {
          h = ScreenUtil().setWidth(0);
        }
      });
    });
    double start = 0;
    _controller2.addListener(() {
//      print("---->_controller2:${_controller2.offset}");
      if ((_controller2.offset - start).abs() > 3) {
        _controller.jumpTo(_controller2.offset);
        start = _controller2.offset;
      }
    });
  }

  @override
  Widget build(BuildContext context) {

    return new DefaultTabController(
      length: _allPages.length,
      child: new Scaffold(
        backgroundColor: Colors.white,
        body: new NestedScrollView(
          controller: _controller,
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return [
              new SliverOverlapAbsorber(
                handle:
                    NestedScrollView.sliverOverlapAbsorberHandleFor(context),
                child: new SliverAppBar(
                  actions: [
                    IconButton(
                      icon: const Icon(Icons.share),
                      tooltip: 'Add new entry',
                      onPressed: () {
                        /* ... */
                      },
                    ),
                  ],
                  leading: Container(
                    child: Icon(Icons.backspace),
                    width: 0,
                    alignment: Alignment.center,
                  ),
                  title: Text("这是一个标题"),
                  pinned: true,
                  //固定在顶部
                  expandedHeight: ScreenUtil().setWidth(260),
                  // 这个高度必须比flexibleSpace高度大
                  forceElevated: innerBoxIsScrolled,
                  bottom: PreferredSize(
                      child: new Container(
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.only(
                              topLeft: Radius.circular(20),
                              topRight: Radius.circular(20)),
                          color: Colors.white,
                        ),
                        height: h,
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: [
                            Container(
                              child: InkWell(
                              child: Text(
                                "导航一",
                                style: TextStyle(
                                    color:
                                    h > 10 ? Colors.black : Colors.white),
                              ),
                              onTap: () {
                                _controller2.animateTo(
                                    ScreenUtil().setWidth(260),
                                    duration: new Duration(seconds: 1),
                                    curve: Curves.ease);
                              },
                            ),
                            alignment: Alignment.center,
                            )
                            ,
                            InkWell(
                                child: Text("导航二",
                                    style: TextStyle(
                                        color: h > 10
                                            ? Colors.black
                                            : Colors.white)),
                                onTap: () {
                                  _controller2.animateTo(
                                      ScreenUtil().setWidth(600),
                                      duration: new Duration(seconds: 1),
                                      curve: Curves.ease);
                                  ;
                                })
                          ],
                        ),

                      ),
                      preferredSize: new Size(double.infinity, h)),
                  // 46.0为TabBar的高度,也就是tabs.dart中的_kTabHeight值,因为flutter不支持反射所以暂时没法通过代码获取
                  flexibleSpace: new Container(
                    child: new Column(
                      children: [
                        new Expanded(
                          child: new Container(
                            height: ScreenUtil().setWidth(170),
                            decoration: BoxDecoration(color: Colors.white),
                            child: Stack(
                              fit: StackFit.expand,
                              children: [
                                Image.asset(
                                  "images/test_1.png",
                                  fit: BoxFit.cover,
                                  height: ScreenUtil().setWidth(150),
                                ),
                                Stack(
                                  children: [
                                    Container(
                                      height: ScreenUtil().setWidth(30),
                                      width: ScreenUtil().setWidth(375),
                                      decoration: BoxDecoration(
                                        borderRadius: BorderRadius.only(
                                            topLeft: Radius.circular(20),
                                            topRight: Radius.circular(20)),
                                        color: Colors.white,
                                      ),
                                      child: Container(
                                        margin: EdgeInsets.only(
                                            left: ScreenUtil().setWidth(125)),
                                        child: Row(
                                          children: [
                                            Text(
                                              "这是测试的标题2",
                                              style: TextStyle(
                                                  color: Colors.black,
                                                  fontSize:
                                                      ScreenUtil().setSp(15)),
                                            ),
                                            Text(
                                              "描述",
                                              style: TextStyle(
                                                  color: Colors.red,
                                                  fontSize:
                                                      ScreenUtil().setSp(12)),
                                            )
                                          ],
                                        ),
                                      ),
                                    ),
                                    Container(
                                      child: Container(
                                          margin: EdgeInsets.only(
                                              left: ScreenUtil().setWidth(10),
                                              right: ScreenUtil().setWidth(10)),
                                          child: Row(
                                            children: [
                                              Image.asset(
                                                "images/test_2.png",
                                                fit: BoxFit.fill,
                                                width:
                                                    ScreenUtil().setWidth(116),
                                                height:
                                                    ScreenUtil().setWidth(164),
                                              ),
                                              Column(
                                                children: [
                                                  Text(
                                                    "这是测试的标题1",
                                                    style: TextStyle(
                                                        color: Colors.white),
                                                  ),
                                                  Text(
                                                    "副标题1",
                                                    style: TextStyle(
                                                        color: Colors.red),
                                                  ),
                                                  Text(
                                                    "副标题2",
                                                    style: TextStyle(
                                                        color: Colors.red),
                                                  ),
                                                  Text(
                                                    "副标题3",
                                                    style: TextStyle(
                                                        color: Colors.red),
                                                  ),
                                                  Text(
                                                    "副标题4",
                                                    style: TextStyle(
                                                        color: Colors.red),
                                                  )
                                                ],
                                              )
                                            ],
                                          )),
                                      height: h >= ScreenUtil().setWidth(20)
                                          ? (h >= ScreenUtil().setWidth(30)
                                              ? (h >= ScreenUtil().setWidth(35)
                                                  ? (h >= ScreenUtil().setWidth(40)
                                                      ? 0
                                                      : ScreenUtil().setWidth(80))
                                                  : ScreenUtil().setWidth(100))
                                              : ScreenUtil().setWidth(140))
                                          : ScreenUtil().setWidth(170),
                                    ),
                                  ],
                                  alignment: AlignmentDirectional.bottomEnd,
                                ),
                              ],
                            ),
                            width: double.infinity,
                          ),
                        )
                      ],
                    ),
                  ),
                ),
              ),
            ];
          },
          body: new TabBarView(
            children: _allPages.keys.map((_Page page) {
              return new SafeArea(
                top: false,
                bottom: false,
                child: new Builder(
                  builder: (BuildContext context) {
                    return new CustomScrollView(
                      controller: _controller2,
                      key: new PageStorageKey<_Page>(page),
                      slivers: [
                        new SliverOverlapInjector(
                          handle:
                              NestedScrollView.sliverOverlapAbsorberHandleFor(
                                  context),
                        ),
                        new SliverPadding(
                          padding: const EdgeInsets.symmetric(
                            vertical: 8.0,
                            horizontal: 16.0,
                          ),
                          sliver: new SliverFixedExtentList(
                            itemExtent: _CardDataItem.height,
                            delegate: new SliverChildBuilderDelegate(
                              (BuildContext context, int index) {
                                final _CardData data = _allPages[page][index];
                                return new Padding(
                                  padding: const EdgeInsets.symmetric(
                                    vertical: 8.0,
                                  ),
                                  child: new _CardDataItem(
                                    page: page,
                                    data: data,
                                  ),
                                );
                              },
                              childCount: _allPages[page].length,
                            ),
                          ),
                        ),
                      ],
                    );
                  },
                ),
              );
            }).toList(),
          ),
//        body: Column(children: [],),
        ),
      ),
    );
  }
}

说明:
NestedScrollView 与body 中的CustomScrollView滑动冲突解决,通过CustomScrollView的_controller2
控制NestedScrollView的_controller,以达到控制NestedScrollView的滚动的结果,当内部的CustomScrollView滚动时候_controller2监听器里 _controller.jumpTo(_controller2.offset),实现外层的NestedScrollView滚动

 

 

 

你可能感兴趣的:(Flutter)