<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Sliver on 首页 | Widegram</title>
    <link>https://widegram.com/tags/sliver/</link>
    <description>Recent content in Sliver on 首页 | Widegram</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Wed, 03 Nov 2021 01:47:00 +0000</lastBuildDate><atom:link href="https://widegram.com/tags/sliver/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Flutter Sliver组件全解</title>
      <link>https://widegram.com/2021/11/flutter-sliver/</link>
      <pubDate>Wed, 03 Nov 2021 01:47:00 +0000</pubDate>
      
      <guid>https://widegram.com/2021/11/flutter-sliver/</guid>
      <description>一、初试Sliver 1.1 使用Sliver制作一个ListView ​	ListView的底层原理就是Sliver，我们可以用CustomScrollView先做出一个视窗（所谓视窗就是里面的内容比边框大），在其中使用SliverChildBuilderDelegate，而事实上，这也正是ListViewBuilder的底层做法。
CustomScrollView(	//定义一个视窗 slivers: [ SliverList(delegate: SliverChildBuilderDelegate((context, index) { return Container( height: 200, color: Colors.primaries[index%Colors.primaries.length], ); })) ], ) 1.2 更加灵活的ListView——加入任意Widget ​	而使用Sliver，我们就可以实现更加灵活的功能，例如在顶部加入一个FlutterLogo：
CustomScrollView( slivers: [ SliverToBoxAdapter(child: FlutterLogo(size:100),),	//加入一个FlutterLogo SliverList( delegate: SliverChildBuilderDelegate((context, index) { //使用SliverChildBuilderDelegate实现动态加载（Builder） //delegate: SliverChildListDelegate对应不用Builder的ListView return Container( height: 200, color: Colors.primaries[index%Colors.primaries.length], ); })) ], ) 1.3 更加灵活的ListView——组合GridView ​	我们也可以尝试组合GridView：
CustomScrollView( slivers: [ /* 1. 用SliverToBoxAdapter包裹的普通Widget */ const SliverToBoxAdapter(child: FlutterLogo(size:100),), /* 2. 用SliverGrid表示的GridView */ SliverGrid( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), delegate: SliverChildBuilderDelegate((context, index) =&amp;gt; Container( color: Colors.</description>
      <content:encoded><![CDATA[<h3 id="一初试sliver">一、初试Sliver</h3>
<h4 id="11-使用sliver制作一个listview">1.1 使用Sliver制作一个ListView</h4>
<p>​		ListView的底层原理就是Sliver，我们可以用<code>CustomScrollView</code>先做出一个视窗（所谓视窗就是里面的内容比边框大），在其中使用<code>SliverChildBuilderDelegate</code>，而事实上，这也正是ListViewBuilder的底层做法。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dart" data-lang="dart"><span style="display:flex;"><span>CustomScrollView(		<span style="color:#75715e">//定义一个视窗
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  slivers: [
</span></span><span style="display:flex;"><span>    SliverList(delegate: SliverChildBuilderDelegate((context, index) {
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">return</span> Container(
</span></span><span style="display:flex;"><span>        height: <span style="color:#ae81ff">200</span>, 
</span></span><span style="display:flex;"><span>        color: Colors.primaries[index<span style="color:#f92672">%</span>Colors.primaries.length],
</span></span><span style="display:flex;"><span>      );
</span></span><span style="display:flex;"><span>    }))
</span></span><span style="display:flex;"><span>  ],
</span></span><span style="display:flex;"><span>)
</span></span></code></pre></div><img src="https://i.loli.net/2021/11/03/32aMcJSl1Bu9zYE.png" alt="截屏2021-11-02 下午10.19.31" style="zoom: 25%;" />
<h4 id="12-更加灵活的listview加入任意widget">1.2 更加灵活的ListView——加入任意Widget</h4>
<p>​		而使用Sliver，我们就可以实现更加灵活的功能，例如在顶部加入一个FlutterLogo：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dart" data-lang="dart"><span style="display:flex;"><span>CustomScrollView(
</span></span><span style="display:flex;"><span>  slivers: [
</span></span><span style="display:flex;"><span>    SliverToBoxAdapter(child: FlutterLogo(size:<span style="color:#ae81ff">100</span>),),	<span style="color:#75715e">//加入一个FlutterLogo
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    SliverList(
</span></span><span style="display:flex;"><span>      delegate: SliverChildBuilderDelegate((context, index) {
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//使用SliverChildBuilderDelegate实现动态加载（Builder）
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#75715e">//delegate: SliverChildListDelegate对应不用Builder的ListView
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#66d9ef">return</span> Container(
</span></span><span style="display:flex;"><span>          height: <span style="color:#ae81ff">200</span>, 
</span></span><span style="display:flex;"><span>          color: Colors.primaries[index<span style="color:#f92672">%</span>Colors.primaries.length],
</span></span><span style="display:flex;"><span>        );
</span></span><span style="display:flex;"><span>    	}))
</span></span><span style="display:flex;"><span>  ],
</span></span><span style="display:flex;"><span>)
</span></span></code></pre></div><img src="https://i.loli.net/2021/11/03/g7hMdl8nPDjAi3W.png" alt="截屏2021-11-02 下午10.22.03" style="zoom:25%;" />
<h4 id="13-更加灵活的listview组合gridview">1.3 更加灵活的ListView——组合GridView</h4>
<p>​		我们也可以尝试组合GridView：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dart" data-lang="dart"><span style="display:flex;"><span>CustomScrollView(
</span></span><span style="display:flex;"><span>  slivers: [
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/* 1. 用SliverToBoxAdapter包裹的普通Widget */</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">const</span> SliverToBoxAdapter(child: FlutterLogo(size:<span style="color:#ae81ff">100</span>),),
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/* 2. 用SliverGrid表示的GridView */</span>
</span></span><span style="display:flex;"><span>    SliverGrid(
</span></span><span style="display:flex;"><span>      gridDelegate: <span style="color:#66d9ef">const</span> SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: <span style="color:#ae81ff">3</span>),
</span></span><span style="display:flex;"><span>      delegate: SliverChildBuilderDelegate((context, index) <span style="color:#f92672">=&gt;</span> Container(
</span></span><span style="display:flex;"><span>        color: Colors.primaries[index <span style="color:#f92672">%</span> Colors.primaries.length]
</span></span><span style="display:flex;"><span>      ), childCount: <span style="color:#ae81ff">6</span>,  <span style="color:#75715e">//也就是GridView中的itemCount
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>                                          )
</span></span><span style="display:flex;"><span>    ),
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/* 3. 用SliverList表示的ListViewer.builder */</span>
</span></span><span style="display:flex;"><span>    SliverList(
</span></span><span style="display:flex;"><span>      delegate: SliverChildBuilderDelegate((context, index) {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> Container(
</span></span><span style="display:flex;"><span>          height: <span style="color:#ae81ff">200</span>, 
</span></span><span style="display:flex;"><span>          color: Colors.primaries[index<span style="color:#f92672">%</span>Colors.primaries.length],
</span></span><span style="display:flex;"><span>        );
</span></span><span style="display:flex;"><span>      })),
</span></span><span style="display:flex;"><span>  ],
</span></span><span style="display:flex;"><span>)
</span></span></code></pre></div><img src="https://i.loli.net/2021/11/03/seKE9IT8mzvip4w.png" alt="截屏2021-11-02 下午11.00.19" style="zoom:25%;" />
<h3 id="二其他的几个常用sliver">二、其他的几个常用Sliver</h3>
<h4 id="21-使用itemextentsliverfixedextentlist">2.1 使用itemExtent——SliverFixedExtentList</h4>
<p>​		您肯定还记得ListView中，为了方面滚动条的定位和跳转，我们会通过ListView中的<code>itemExtent</code>属性来固定每一项在主轴上的长度，例如我们需要定位到第100个元素，只需要将其乘上对应的数即可。</p>
<p>​		这里的<code>itemExtent</code>属性不可以用列表内容Widget的<code>widget</code>或<code>height</code>属性替代，因为那样不会获得滚动条的性能优化。</p>
<p>​		在Sliver中我们需要使用<code>SliverFixedExtentList</code>来定义itemExtent属性，这样我们就可以让某些元素有固定的长度，另一些则不必。</p>
<h4 id="22-自适应的itemextentsliverprototypeextentlist">2.2 自适应的itemExtent——SliverPrototypeExtentList</h4>
<p>​		通常我们很难直接得到内容Widget的高度，例如字号可能会因为老年模式而改变，因此我们可以使用<code>SliverPrototypeExtentList</code>来动态确定其<code>itemExtent</code>.</p>
<p>​		<code>SliverPrototypeExtentList</code>需要一个<code>prototypeItem</code>属性，它只是用来测量内容在主轴上的高度，并不会真的渲染到屏幕上。当字号调整时，我们只要配置了<code>prototypeItem</code>属性，它就会自动重新计算其<code>itemExtent</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dart" data-lang="dart"><span style="display:flex;"><span><span style="color:#75715e">//自适应的itemExtent
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>SliverPrototypeExtentList(delegate: delegate, prototypeItem: prototypeItem),
</span></span></code></pre></div><h4 id="23-使用pageviewsliverfillviewport">2.3 使用PageView——SliverFillViewport</h4>
<p>​		回想一下<code>PageView</code>组件——其中的每一个项目都会沾满整个屏幕，通过滑动来切换，通常我们可以用它来做软件的开屏教程。</p>
<p>​		在Sliver中，提供了一个叫做<code>SliverFillViewport</code>的组件，它也是PageView的底层原理。</p>
<h4 id="24-自动回缩的华丽导航条sliverappbar">2.4 自动回缩的华丽导航条——SliverAppBar</h4>
<p>​		我们可以使用SliverAppBar制作一个华丽的动态导航条，首先我们要去掉Scaffold中的AppBar属性，并用下面的代码添加到<code>CustomScrollView</code>中：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dart" data-lang="dart"><span style="display:flex;"><span>SliverAppBar(
</span></span><span style="display:flex;"><span>  floating: <span style="color:#66d9ef">true</span>, <span style="color:#75715e">//稍微一向下拉导航条就出现
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  snap: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">//title: Text(&#34;111&#34;),
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  pinned: <span style="color:#66d9ef">false</span>,<span style="color:#75715e">//不固定
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  expandedHeight: <span style="color:#ae81ff">100</span>,<span style="color:#75715e">//导航条高度
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  stretch: <span style="color:#66d9ef">true</span>,<span style="color:#75715e">//使用更长的拉伸（flexibleSpace）
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  flexibleSpace: FlexibleSpaceBar( 
</span></span><span style="display:flex;"><span>    background: FlutterLogo(size:<span style="color:#ae81ff">100</span>),<span style="color:#75715e">//导航条中的背景
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    title: Text(<span style="color:#e6db74">&#34;111&#34;</span>),
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//上缩效果
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    collapseMode: CollapseMode.parallax,
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//下拉效果
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    stretchModes: [
</span></span><span style="display:flex;"><span>      StretchMode.blurBackground,
</span></span><span style="display:flex;"><span>      StretchMode.zoomBackground,
</span></span><span style="display:flex;"><span>      StretchMode.fadeTitle
</span></span><span style="display:flex;"><span>    ],
</span></span><span style="display:flex;"><span>  ),
</span></span><span style="display:flex;"><span>),
</span></span></code></pre></div><img src="https://i.loli.net/2021/11/03/mQeOrRHkWsVidCl.png" alt="截屏2021-11-02 下午11.52.39" style="zoom:25%;" />
<h3 id="三sliver转换器">三、Sliver转换器</h3>
<h4 id="31-普通widget的sliver对应版本">3.1 普通Widget的Sliver对应版本</h4>
<p>例如：</p>
<ul>
<li>
<p><code>Opacity</code> =&gt; <code>SliverOpacity</code></p>
</li>
<li>
<p><code>AnimatedOpacity</code> =&gt;<code>SilverAnimatedOpacity</code></p>
</li>
<li>
<p>值得注意的是，<code>SizedBox</code>直接对应空的<code>SliverToBoxAdapter()</code>，也就是不传任何东西</p>
</li>
</ul>
<p>普通Widget基本都能找到其Sliver形式，可以直接用sliver属性嵌套（相当于普通Widget的child）属性。</p>
<h4 id="32-特殊sliver">3.2 特殊Sliver</h4>
<ol>
<li><code>SliverFillRemaining</code>——占据当前视窗的剩余全部空间，但最多占满一整页。</li>
<li>注意：使用<code>SliverLayoutBuilder</code>可以自己作出一个SliverFillRemaining组件哦～</li>
</ol>
<p>完整实例：</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dart" data-lang="dart"><span style="display:flex;"><span><span style="color:#66d9ef">import</span> <span style="color:#e6db74">&#39;package:flutter/material.dart&#39;</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">void</span> main() {
</span></span><span style="display:flex;"><span>  runApp(<span style="color:#66d9ef">const</span> MyApp());
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">MyApp</span> <span style="color:#66d9ef">extends</span> StatelessWidget {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">const</span> MyApp({Key<span style="color:#f92672">?</span> key}) <span style="color:#f92672">:</span> <span style="color:#66d9ef">super</span>(key: key);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#960050;background-color:#1e0010">@</span>override
</span></span><span style="display:flex;"><span>  Widget build(BuildContext context) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> MaterialApp(
</span></span><span style="display:flex;"><span>      title: <span style="color:#e6db74">&#39;Flutter Demo&#39;</span>,
</span></span><span style="display:flex;"><span>      theme: ThemeData(
</span></span><span style="display:flex;"><span>        primarySwatch: Colors.blue,
</span></span><span style="display:flex;"><span>      ),
</span></span><span style="display:flex;"><span>      home: <span style="color:#66d9ef">const</span> MyHomePage(title: <span style="color:#e6db74">&#39;Flutter Demo Home Page&#39;</span>),
</span></span><span style="display:flex;"><span>    );
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">MyHomePage</span> <span style="color:#66d9ef">extends</span> StatefulWidget {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">const</span> MyHomePage({Key<span style="color:#f92672">?</span> key, <span style="color:#66d9ef">required</span> <span style="color:#66d9ef">this</span>.title}) <span style="color:#f92672">:</span> <span style="color:#66d9ef">super</span>(key: key);
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">String</span> title;
</span></span><span style="display:flex;"><span>  <span style="color:#960050;background-color:#1e0010">@</span>override
</span></span><span style="display:flex;"><span>  State<span style="color:#f92672">&lt;</span>MyHomePage<span style="color:#f92672">&gt;</span> createState() <span style="color:#f92672">=&gt;</span> _MyHomePageState();
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">_MyHomePageState</span> <span style="color:#66d9ef">extends</span> State<span style="color:#f92672">&lt;</span>MyHomePage<span style="color:#f92672">&gt;</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#960050;background-color:#1e0010">@</span>override
</span></span><span style="display:flex;"><span>  Widget build(BuildContext context) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> Scaffold(
</span></span><span style="display:flex;"><span>      body: <span style="color:#66d9ef">const</span> CustomScrollView(
</span></span><span style="display:flex;"><span>        slivers: [
</span></span><span style="display:flex;"><span>      SliverAppBar(
</span></span><span style="display:flex;"><span>        floating: <span style="color:#66d9ef">true</span>, <span style="color:#75715e">//稍微一向下拉导航条就出现
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        snap: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//title: Text(&#34;111&#34;),
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        pinned: <span style="color:#66d9ef">false</span>,<span style="color:#75715e">//不固定
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        expandedHeight: <span style="color:#ae81ff">100</span>,<span style="color:#75715e">//导航条高度
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        stretch: <span style="color:#66d9ef">true</span>,<span style="color:#75715e">//使用更长的拉伸（flexibleSpace）
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        flexibleSpace: FlexibleSpaceBar( 
</span></span><span style="display:flex;"><span>          background: FlutterLogo(size:<span style="color:#ae81ff">100</span>),<span style="color:#75715e">//导航条中的背景
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>          title: Text(<span style="color:#e6db74">&#34;111&#34;</span>),
</span></span><span style="display:flex;"><span>          <span style="color:#75715e">//上缩效果
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>          collapseMode: CollapseMode.parallax,
</span></span><span style="display:flex;"><span>          <span style="color:#75715e">//下拉效果
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>          stretchModes: [
</span></span><span style="display:flex;"><span>            StretchMode.blurBackground,
</span></span><span style="display:flex;"><span>            StretchMode.zoomBackground,
</span></span><span style="display:flex;"><span>            StretchMode.fadeTitle
</span></span><span style="display:flex;"><span>          ],
</span></span><span style="display:flex;"><span>        ),
</span></span><span style="display:flex;"><span>      ),
</span></span><span style="display:flex;"><span>      SliverToBoxAdapter(child: FlutterLogo(size: <span style="color:#ae81ff">100</span>)),
</span></span><span style="display:flex;"><span>      SliverToBoxAdapter(child: FlutterLogo(size: <span style="color:#ae81ff">100</span>)),
</span></span><span style="display:flex;"><span>      SliverToBoxAdapter(child: FlutterLogo(size: <span style="color:#ae81ff">100</span>)),
</span></span><span style="display:flex;"><span>      SliverFillRemaining(
</span></span><span style="display:flex;"><span>        child:Center(	<span style="color:#75715e">//用加载圈填满剩余视口
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>          child: CircularProgressIndicator(),
</span></span><span style="display:flex;"><span>        )
</span></span><span style="display:flex;"><span>      )
</span></span><span style="display:flex;"><span>        ],
</span></span><span style="display:flex;"><span>      ),
</span></span><span style="display:flex;"><span>    );
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><img src="https://i.loli.net/2021/11/03/WuPeF23tlAsoYRy.png" alt="截屏2021-11-03 上午12.44.52" style="zoom:25%;" />
<h4 id="33-sliverappbar原理sliverpersistentheader">3.3 SliverAppBar原理——SliverPersistentHeader</h4>
<p>​	使用原理类似，</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dart" data-lang="dart"><span style="display:flex;"><span>SliverToBoxAdapter(),
</span></span><span style="display:flex;"><span><span style="color:#75715e">//防止SliverPersistentHeader成为最顶层的Sliver，以至于无法上拉刷新
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>SliverPersistentHeader(
</span></span><span style="display:flex;"><span>	delegate:
</span></span><span style="display:flex;"><span>  pinned: <span style="color:#66d9ef">true</span>,<span style="color:#75715e">//像AppBar一样钉在最顶部
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>)
</span></span></code></pre></div>]]></content:encoded>
    </item>
    
  </channel>
</rss>
