{"id":554785,"date":"2022-02-14T06:28:52","date_gmt":"2022-02-13T22:28:52","guid":{"rendered":"http:\/\/4563.org\/?p=554785"},"modified":"2022-02-14T06:28:52","modified_gmt":"2022-02-13T22:28:52","slug":"%e6%b1%82%e5%8a%a9%ef%bc%8c%e5%85%b3%e4%ba%8e-flutter-%e7%9a%84-nestedscrollview-%e4%b8%8e-scrollbar-%e5%86%b2%e7%aa%81-8","status":"publish","type":"post","link":"http:\/\/4563.org\/?p=554785","title":{"rendered":"\u6c42\u52a9\uff0c\u5173\u4e8e Flutter \u7684 NestedScrollView \u4e0e Scrollbar \u51b2\u7a81"},"content":{"rendered":"<div>\n<div>\n<div>\n<h1> \u6c42\u52a9\uff0c\u5173\u4e8e Flutter \u7684 NestedScrollView \u4e0e Scrollbar \u51b2\u7a81 <\/h1>\n<p> <\/p>\n<div>\n<div> <span>\u8cc7\u6df1\u5927\u4f6c : alvazu <\/span>  <span><i><\/i> 40<\/span> <\/div>\n<div> <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div isfirst=\"1\"> <\/p>\n<p>\u5728 Stackoverflow \u4e0a\u627e\u4e86\u4e00\u5708\u4e5f\u6ca1\u6709\u627e\u5230\u7b54\u6848\uff0c\u60f3\u5411 v2 \u7684\u670b\u53cb\u4eec\u6c42\u52a9\u4e00\u4e0b\u3002<\/p>\n<p><code>NestedScrollView<\/code> + <code>SliverAppBar<\/code> + <code>TabView<\/code> \u4e0e<code>Scrollbar<\/code>\u5408\u7528\uff0c\u5728\u5de6\u53f3\u6ed1\u52a8\u65f6\u51fa\u73b0\u4ee5\u4e0b\u9519\u8bef\uff1a<\/p>\n<blockquote>\n<p>The following assertion was thrown while notifying status listeners for AnimationController: The PrimaryScrollController is currently attached to more than one ScrollPosition.<\/p>\n<\/blockquote>\n<p>\u6211\u5c1d\u8bd5\u8fc7\u7528<code>PrimaryScrollController<\/code>\u5305\u88f9<code>Scroller \u7ec4\u4ef6<\/code>\uff0c\u9519\u8bef\u4e0d\u518d\u51fa\u73b0\uff0c\u4f46\u662f<code>NestedScrollView<\/code>\u4e0a\u4e0b\u4e24\u8fb9\u7684\u6eda\u52a8\u4e0d\u518d\u540c\u6b65\uff1b\u5c1d\u8bd5\u8fc7\u5199<code>NotificationListener<\/code>\uff0c\u95ee\u9898\u770b\u8d77\u6765\u89e3\u51b3\u4e86\uff0c\u4f46\u662f\u4f1a\u6709\u5947\u602a\u7684\u5361\u987f\u73b0\u8c61\uff1a<\/p>\n<pre><code>NotificationListener&lt;ScrollNotification&gt;(             onNotification: (ScrollNotification notification) {               \/\/print(notification.metrics.axisDirection);               if (notification.metrics.extentAfter &gt; 0 &amp;&amp;                   notification.metrics.extentBefore &gt; 0 &amp;&amp;                   notification.metrics.axisDirection == AxisDirection.down) {                 double pixelnow = notification.metrics.pixels;                 double _jmpTo =                     _scrollController.offset + (pixelnow - _scrollLocation);                 \/\/print(\"pixel now : $pixelnow\");                 \/\/print(\"jumpto: $_jmpTo\");                 if (_scrollController.position.maxScrollExtent &gt;= _scrollController.offset                    &amp;&amp; _scrollController.offset &gt;= _scrollController.position.minScrollExtent ){                   _scrollController.jumpTo(_jmpTo);                   \/\/_scrollController.jumpTo(value)                 }                 _scrollLocation = pixelnow;               }               return false;             }, <\/code><\/pre>\n<p>\u6211\u7684\u539f\u59cb\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n<pre><code> import 'package:flutter\/material.dart';  void main() =&gt; runApp(MaterialApp(home: Scaffold(body: CommunityPage())));  class CommunityPage extends StatefulWidget {   CommunityPage({Key? key}) : super(key: key);    @override   _CommunityPageState createState() =&gt; _CommunityPageState(); }  class _CommunityPageState extends State&lt;CommunityPage&gt; {   \/\/ScrollController _scrollController = ScrollController();   \/\/final TabController _tabController = TabController();   final _tabs = &lt;String&gt;[\"Tab 1\", \"Tab 2\", \"Tab 3\"];    @override   Widget build(BuildContext context) {     return Scaffold(       body: DefaultTabController(         length: _tabs.length, \/\/ This is the number of tabs.         child: NestedScrollView(           headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {             \/\/ These are the slivers that show up in the \"outer\" scroll view.             return &lt;Widget&gt;[               SliverOverlapAbsorber(                 handle:                     NestedScrollView.sliverOverlapAbsorberHandleFor(context),                 sliver: SliverAppBar(                   automaticallyImplyLeading: false,                   title: const Text(\"Community\",style: TextStyle(color: Colors.black)),                   \/\/centerTitle: false,                   pinned: true,                   floating: true,                   snap: true,                   backgroundColor: Colors.grey[50],                   expandedHeight: 85.0,                    bottom: TabBar(                     tabs: _tabs.map((String name) =&gt; Tab(text: name)).toList(),                   ),                 ),               ),             ];           },           body: TabBarView(             children: _tabs.map((String name) {               \/\/SafeArea \u9002\u914d\u5218\u6d77\u5c4f\u7684\u4e00\u4e2a widget               return Builder(                 builder: (BuildContext context) {                   return Scrollbar(                     child: CustomScrollView(                       key: PageStorageKey&lt;String&gt;(name),                       slivers: &lt;Widget&gt;[                         SliverOverlapInjector(                           handle:                               NestedScrollView.sliverOverlapAbsorberHandleFor(                                   context),                         ),                         SliverFixedExtentList(                           itemExtent: 50.0, \/\/item \u9ad8\u5ea6\u6216\u5bbd\u5ea6\uff0c\u53d6\u51b3\u4e8e\u6ed1\u52a8\u65b9\u5411                           delegate: SliverChildBuilderDelegate(                             (BuildContext context, int index) {                               return ListTile(                                 title: Text('Item $index'),                               );                             },                             childCount: 30,                           ),                         ),                       ],                     ),                   );                 },               );             }).toList(),           ),         ),       ),     );   } } <\/code><\/pre>\n<\/p><\/div>\n<div> <b>\u5927\u4f6c\u6709\u8a71\u8aaa<\/b> (<span>0<\/span>) <\/div>\n<div> <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<ul>\n<li>\n","protected":false},"excerpt":{"rendered":"<p>\u6c42\u52a9\uff0c\u5173\u4e8e Flutter \u7684 N&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[],"tags":[],"_links":{"self":[{"href":"http:\/\/4563.org\/index.php?rest_route=\/wp\/v2\/posts\/554785"}],"collection":[{"href":"http:\/\/4563.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/4563.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/4563.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/4563.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=554785"}],"version-history":[{"count":0,"href":"http:\/\/4563.org\/index.php?rest_route=\/wp\/v2\/posts\/554785\/revisions"}],"wp:attachment":[{"href":"http:\/\/4563.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=554785"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/4563.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=554785"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/4563.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=554785"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}