preface
A TAB bar with hidden top appears when the flutter is slid up. Scroll to the corresponding position to switch the TAB bar, similar to the effect of pulling up the baby details page on a shopping website.Copy the code
First, the effect picture:
An overview of the
CustomScrollView is a component provided by Flutter that can be used to customize the scrolling effect. It acts like glue to hold multiple slivers together. By using the suction a top SliverPersistentHeader, SliverAppBar is implemented based on this, SliverPersistentHeader SliverPersistentHeaderDelegate is one of the most important attributeCopy the code
Custom header
SliverPersistentHeaderDelegate implementation class must implement the four methods. Among them:
MinExtent: the height of a component when it is folded up. MaxExtent: the height of the component when expanded. ShouldRebuild: similar to shouldComponentUpdate in React; Build: Builds the rendered content. The code is as follows:
ShrinkOffset > this.thresholdValue Indicates the current header’s scroll offset, and is larger than its incoming threshold to hide and control the display.
class SliverCustomHeaderStatusDelegate extends SliverPersistentHeaderDelegate { BuildContext context; Widget tabs; Widget top; num thresholdValue; num minH; num maxH; SliverCustomHeaderStatusDelegate( {this.context, this.tabs, this.top, this.thresholdValue, this.maxH, this.minH}); @override double get minExtent => this.minH; @override double get maxExtent => this.maxH; @override bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) { return true; } bool makeStickyTab(shrinkOffset) {// It represents the current header roll offset. } else { return false; } } @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return Container( height: this.maxExtent, width: MediaQuery.of(context).size.width, child: this.makeStickyTab(shrinkOffset) ? tabs : top); }}Copy the code
measurement
Slide down the page to automatically switch the TAB bar according to the drop-down distance. You need to dynamically calculate the top distance of each TAB bar corresponding to the drop-down part, ranging as follows:
Apply for a global key first
var globalKeyOne = GlobalKey();
Copy the code
I can use it for layout
SliverToBoxAdapter(
child: Container(
key: globalKeyOne,
width: double.infinity,
height: ScreenUtil().setHeight(400),
color: Colors.red,
),
),
Copy the code
Then measure when initState. After a delay, size can be obtained only after state layout is finished
// Wait until the state layout is finished to get size future.delayed (Duration(milliseconds:) 100), () { oneY = getY(globalKeyOne.currentContext); twoY = getY(globalKeyTwo.currentContext); threeY = getY(globalKeyThree.currentContext); fourY = getY(globalKeyFour.currentContext); header = ScreenUtil().setHeight(this.headerMax - this.headerMin) + 10; //10 is error});Copy the code
Get the distance from the top of the widget by:
double getY(BuildContext buildContext) {
final RenderBox box = buildContext.findRenderObject();
//final size = box.size;
final topLeftPosition = box.localToGlobal(Offset.zero);
return topLeftPosition.dy;
}
Copy the code
rolling
Scroll is based on ScrollController’s jumpTo(Double offset), animateTo(Double offset,…) : These two methods are used to jump to a specified location. They differ in that the latter performs an animation while the former does not.
Click the TAB bar for each TAB to switch to the corresponding section, using the measured processing of the distance of each section and sliding the distance to dynamically jumpTo the specified position
TabBar( onTap: (index) { if (! mounted) { return; } switch (index) { case 0: _controller.jumpTo(0); _tabController.animateTo(0); break; case 1: _controller.jumpTo(header); _tabController.animateTo(1); break; case 2: _controller.jumpTo(header + (twoY - oneY)); _tabController.animateTo(2); break; case 3: _controller.jumpTo(header + (threeY - oneY)); _tabController.animateTo(3); break; case 4: _controller.jumpTo(header + (fourY - oneY)); _tabController.animateTo(4); break; }Copy the code
At the same time, listen in initState to scroll to what position, according to the scrolling position to dynamically switch TAB active position. Handles logic in ScrollController listener events.
_controller.addListener(() { var of = _controller.offset; Var distance_2 = header + (twoy-oney); Var distance_3 = header + (threey-oney); Var distance_4 = header + (foury-oney); var distance_4 = header + (foury-oney); if (of > header && of < distance_2) { _tabController.animateTo(1); } else if (of > distance_2 && of < distance_3) { _tabController.animateTo(2); } else if (of > distance_3 && of < distance_4) { _tabController.animateTo(3); } else if (of > distance_4) { _tabController.animateTo(4); }});Copy the code
NestedScrollView, SingleChildScrollView, SingleChildScrollView, SingleChildScrollView, SingleChildScrollView, SingleChildScrollView, SingleChildScrollView, SingleChildScrollView I still don’t understand sliver very well, but I changed it to CustomScrollView, and I put _controller on CustomScrollView,
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xFF201E24),
body: CustomScrollView(
controller: _controller,
slivers: [
SliverPersistentHeader(
pinned: true,
delegate: SliverCustomHeaderStatusDelegate(
tabs: _tab,
top: _top,
minH: ScreenUtil().setHeight(this.headerMin),
maxH: ScreenUtil().setHeight(this.headerMax),
thresholdValue:
ScreenUtil().setHeight(this.headerMax - this.headerMin),
context: context,
),
),
SliverToBoxAdapter(
child: Container(
key: globalKeyOne,
width: double.infinity,
height: ScreenUtil().setHeight(400),
color: Colors.red,
),
),
SliverToBoxAdapter(
child: Container(
key: globalKeyTwo,
width: double.infinity,
height: ScreenUtil().setHeight(1400),
color: Colors.green,
),
),
SliverToBoxAdapter(
child: Container(
key: globalKeyThree,
width: double.infinity,
height: ScreenUtil().setHeight(1800),
color: Colors.grey,
),
),
SliverToBoxAdapter(
child: Container(
key: globalKeyFour,
width: double.infinity,
height: ScreenUtil().setHeight(400),
color: Colors.pinkAccent,
),
),
],
),
),
);
Copy the code
Specific full code in the project address
Welcome to learn and share FLUTTER with me. The project will continue to update new learning demo
Github address of this project: project address
Here is our public account: Flutter Programming Notes (CODE9871)Copy the code
The official accounts share their learning ideas from time to time
Past review:
The Flutter implements a digital scale
Flutter implements simple rotation animations
The Flutter achieves a simple drawer effect
The flutter achieves top adsorption effect