前言
在上一篇文章中,咱们了解了Flutter Slivers中SliverToBoxAdapter
、SliverPersistentHeader
、SliverFixedExtentList
等常用的组件。本章则是一些不那么常用的Slivers组件,大家仅需快速阅读一遍,有个形象即可,方便遇到一些业务时,能快速定位到需求运用的组件。
SliverLayoutBuilder
在依据Box协议的组件布局中,常常会运用LayoutBuilder
,由于能够经过它获取在布局进程中父组件的约束,然后就能够依据约束信息动态的创建布局。例如:
LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
if (constraints.maxWidth < 200) {
// 最大宽度小于200,显示一张图片
return Image.network("");
} else {
return Container();
}
},
),
那么在slivers中对应的就是SliverLayoutBuilder
,能够经过SliverLayoutBuilder
创建一个折叠的sliver widget树,依据组件的约束条件供给不同子组件。
CustomScrollView(
slivers: [
SliverLayoutBuilder(
builder: (BuildContext context, SliverConstraints constraints) {
if (constraints.userScrollDirection == ScrollDirection.forward) {
_color = Colors.blue; //向下滑动显示蓝色
} else if (constraints.userScrollDirection ==
ScrollDirection.idle) {
_color = Colors.yellow; //正常显示黄色
} else {
_color = Colors.purple; //向上滑动显示紫色
}
return SliverToBoxAdapter(
child: Container(
height: 200,
color: _color,
),
);
}),
SliverList(
delegate:
SliverChildBuilderDelegate(childCount: 20, (ctx, index) {
return Container(
color: Colors.primaries[index % Colors.primaries.length],
height: 50,
);
}))
],
),
SliverAnimatedList
在一个有很多子Item的列表中,假如用户需求删去或增加事情,假如没有任何过渡动画,那么很有可能会让用户混淆刚刚发生的工作,不知道列表item是否增加或删去了。所以为了解决这样的问题,能够运用AnimatedContainer
这样带动画的组件,而在Slivers中,能够运用SliverAnimatedList
,经过SliverAnimatedListState
用于动态刺进item
或删去item
。让咱们经过一个比如来学习SliverAnimatedList
。
增加SliverAnimatedList
这儿_listKey
是一个SliverAnimatedListStateGlobalKey
类型。该GlobalKey
有助于刺进和删去列表项。initialItemCount
是界说列表初始化有几个item
。itemBuilder
是需求延迟构建的组件。
final GlobalKey<SliverAnimatedListState> _listKey =
GlobalKey<SliverAnimatedListState>();
SliverAnimatedList(
key: _listKey,
initialItemCount: _list.length,
itemBuilder: _buildItem,
),
再来看下_buildItem
:该index
参数指示项目在列表中的方位。参数的值index
将介于0和initialItemCount
加上已刺进insertItem
的项目总数和减去已删去removeItem
的项目总数。
Widget _buildItem(
BuildContext context, int index, Animation<double> animation) {
return CardItem(
animation: animation,
item: _list[index],
selected: _selectedItem == _list[index],
onTap: () {
setState(() {
_selectedItem = _selectedItem == _list[index] ? null : _list[index];
});
},
);
}
实现将刺进列表的_insert函数和从列表中删去的_remove函数
void _insert() {
final int index =
_selectedItem == null ? _list.length : _list.indexOf(_selectedItem!);
//增加
_list.insert(index, _nextItem++);
//更新UI
_listKey.currentState!.insertItem(index);
}
void _remove() {
final int index = _selectedItem == null
? _list.length - 1
: _list.indexOf(_selectedItem!);
_list.removeAt(index);
//之所以需求这个方法,是由于移除的item在动画完结之前都是可见的。
_listKey.currentState!.removeItem(
index,
(context, animation) => SizeTransition(
sizeFactor: animation,
child: Card(
child: Center(
child: Text(
'Item $index',
style: Theme.of(context).textTheme.headline4,
),
),
),
),
);
setState(() {
_selectedItem = null;
});
}
具体代码详见:点击跳转github详情代码地址
SliverOpacity
运用Opacity
能够使组件变得透明,而在slivers
中能够运用SliverOpacity
。它们的不同之处只在于:Opacity
适用于依据Box
协议的组件,SliverOpacity
适用于依据sliver
协议的组件。
可操控特点有:
opacity: 它一般取值介于0.0到之间1.0。当值为 0.0,则不会制作 sliver child
,若值为1.0,则会立即制作 sliver child
。除了0.0和1.0之外,运用其他的值是非常昂贵的,例如0.5,由于需求将sliver child
制作到缓冲区中。
alwaysIncludeSemantics:是否总是包含语义信息,默许是 false。该特点主要是用于辅助访问的 , 关于视障人员来说会更友爱。假如特点的值是 true,则不论透明度是多少,都会显示语义信息(能够辅助朗读)。
运用也非常简略:
bool _isVisible = true;
...
CustomScrollView(
slivers: [
SliverOpacity(
opacity: _isVisible ? 1.0 : 0.0,
sliver: SliverList(
delegate: SliverChildListDelegate(
[
Container(
height: 50,
color: Colors.green,
child: Center(
child: Text(
"Taxze & SliverOpacity",
style: TextStyle(fontSize: 20, color: Colors.white),
),
),
),
],
),
),
),
SliverPadding(
padding: EdgeInsets.only(top: 24),
sliver: SliverToBoxAdapter(
child: FloatingActionButton(
child: const Icon(Icons.flip),
onPressed: () {
setState(() {
_isVisible = !_isVisible;
});
},
),
),
)
],
),
SliverAnimatedOpacity
假如运用SliverOpacity
,那么组件的不透明度会直接从0.0跳到1.0,转变的进程看起来不光滑。为了让Opacity
滑润的过渡,能够运用SliverAnimatedOpacity
。
bool _visible = true;
CustomScrollView(
slivers: [
SliverAnimatedOpacity(
//动画履行完毕
onEnd: () => print("动画完结"),
curve: Curves.linear,
opacity: _visible ? 1.0 : 0.0,
duration: const Duration(seconds: 2),
sliver: SliverFixedExtentList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Image.network(
"https://p3-passport.byteimg.com/img/user-avatar/af5f7ee5f0c449f25fc0b32c050bf100~180x180.awebp");
}, childCount: 1),
itemExtent: 200.0),
),
SliverPadding(
padding: EdgeInsets.only(top: 18),
sliver: SliverToBoxAdapter(
child: FloatingActionButton(
onPressed: () {
setState(() {
_visible = !_visible;
});
},
tooltip: 'Toggle opacity',
child: const Icon(Icons.flip),
)),
),
],
),
SliverFadeTransition
这也是运用opacity
为sliver
组件设置动画的。仅有的区别是,运用Animation<double>
值而不是double
值。
class _SliverPart3SliverFadeTransitionState
extends State<SliverPart3SliverFadeTransition>
with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(
duration: const Duration(milliseconds: 1000),
vsync: this,
);
late final Animation<double> animation = CurvedAnimation(
parent: controller,
curve: Curves.easeIn,
);
@override
void initState() {
super.initState();
animation.addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
controller.reverse();
} else if (status == AnimationStatus.dismissed) {
controller.forward();
}
});
controller.forward();
}
@override
Widget build(BuildContext context) {
return CustomScrollView(slivers: <Widget>[
SliverAppBar(
title: Text('SliverPart3SliverFadeTransition'),
pinned: true,
),
SliverFadeTransition(
opacity: animation,
sliver: SliverToBoxAdapter(
child: Center(
child: Image.network(
"https: //p3-passport.byteimg.com/img/user-avatar/af5f7ee5f0c449f25fc0b32c050bf100~180x180.awebp",
width: double.infinity,
height: 300,
fit: BoxFit.cover,
),
),
))
]);
}
}
SliverVisibility
SliverVisibility
与Visibility
组件相同,仅仅它是依据sliver
协议的组件。
SliverVisibility
有许多的参数,如:
-
maintainAnimation: 用于判别
animations
不行见时是否保持在sliver
子树内。 -
maintainInteractivity : 用于判别
sliver
隐藏时是否允许交互。 -
maintainSemantics : 用于确定隐藏时是否保持
sliver
的语义。 -
maintainSize: 用于确定是否为
sliver
所在的方位保留空间。 -
maintainState : 用于判别不行见时是否保护
sliver
子树的State
目标。 -
replacementSliver: 当
sliver
不行见时,此处界说的 Widget 可见。
一个简略的比如来了解SliverVisibility:
bool _visible = true;
CustomScrollView(
slivers: <Widget>[
SliverVisibility(
visible: _visible,
replacementSliver: SliverToBoxAdapter(
child: Container(
width: double.infinity,
height: 300,
color: Colors.brown,
child: Center(
child: Text(
"Image is hidden. Tap below button to show",
style: TextStyle(color: Colors.white),
),
),
),
),
sliver: SliverToBoxAdapter(
child: Image.network(
"https://p3-passport.byteimg.com/img/user-avatar/af5f7ee5f0c449f25fc0b32c050bf100~180x180.awebp",
width: double.infinity,
height: 300,
fit: BoxFit.cover,
),
)),
SliverPadding(
padding: EdgeInsets.only(top: 18),
sliver: SliverToBoxAdapter(
child: FloatingActionButton(
onPressed: () {
setState(() {
_visible = !_visible;
});
},
tooltip: 'Toggle visibility',
child: Icon(!_visible ? Icons.visibility : Icons.visibility_off),
)),
),
],
),
SliverIgnorePointer
假如期望sliver
疏忽点击或其他任何类型的交互时,只需将sliver
组件包裹在里面SliverIgnorePointer
。它将禁用该小部件的交互。
当ignoring
特点为true
时,组件不行交互。当ignoringSemantics
特点为true时,子树将对Semantics
(语义)层不行见。
就用SliverVisibility
组件的比如,只需求在操控按钮上,包裹上一层SliverIgnorePointer
即可疏忽点击事情。
SliverIgnorePointer(
sliver: SliverPadding(
padding: EdgeInsets.only(top: 18),
sliver: SliverToBoxAdapter(
child: FloatingActionButton(
onPressed: () {
setState(() {
_visible = !_visible;
});
},
tooltip: 'Toggle visibility',
child:
Icon(!_visible ? Icons.visibility : Icons.visibility_off),
)),
),
),
SliverSafeArea
假如你从前运用过SafeArea
,那么SliverSafeArea
除了它依据sliver协议外,它也在做同样的工作。例如当你想要显示一篇长文章时,便可运用SliverSafeArea
来避免 iPhone X 上的缺口或其他相似的。
SliverSafeArea(sliver: SliverList(
delegate: SliverChildBuilderDelegate((ctx, index) {
return Container(
color: Colors.primaries[index % Colors.primaries.length],
height: 100,
);
},childCount: 20),
))
尾述
三篇文章,从为什么要运用Sliver,再依据运用频率逐一解析Slivers系列的组件。信任您已经入门了Sliver的世界。那么鄙人一章,将独自详解NestedScrollView
,包括SliverOverlapAbsorber
和 SliverOverlapInjector
…的优化
关于我
Hello,我是Taxze,假如您觉得文章对您有价值,期望您能给我的文章点个❤️,有问题需求联络我的话:我在这儿,也能够经过的新的私信功用联络到我。假如您觉得文章还差了那么点东西,也请经过重视督促我写出更好的文章~万一哪天我前进了呢?