The considerationProvider
the
Official says it works, so just use it
The purpose of using a provider is to better manage the status. Why do YOU need to manage the status? Of course, you are afraid of your component more than their own mess, chaos into a pot of porridge ~
There is no picture, the effect picture is posted again, dog belt
Seemingly rational analysis
- In order to scroll through the diary card, the navigation button below must know the current page as it changes color.
double
) in order to make corresponding changes - Use the same color palette for navigation and journal cards:
/// Color plate: Write two meanings, twelve months, there should be twelve. static const List<List<Color>> linerColor = [ [ Color.fromARGB(255.87.211.255), Color.fromARGB(255.86.173.254), ], [ Color.fromARGB(255.86.173.254), Color.fromARGB(255.82.118.254),]];Copy the code
- Diary cards minimize other components when scrolling
build
- Do I want to animate the gradient in the bottom navigation? No, the scrolling of the card will notify the navigation bar, making it re-run
build
As long as Ibuild
Fast enough, your eyes won’t follow me… Animation is not so do, laugh touch my dog head ~
provider
Go up
With the above analysis, our provider simply notifies the page,
/// What is the difference?
class HomeState with ChangeNotifier {
HomeState(this._ctrl) : assert(_ctrl ! =null) {
_ctrl.addListener(() {
_curPage = _ctrl.page.floor();
notifyListeners();
});
}
final PageController _ctrl;
int get curPage => _curPage;
double getvalue => _ctrl? .page ??0;
int _curPage = 0;
void setPage(int index) {
_curPage = index;
notifyListeners();
}
voidbuildChild() { notifyListeners(); }}Copy the code
Wow depend, how and the official writing method have difference!! There is no difference, except that we have an addListener operation and our PageController is not managed by HomeState. (In fact, it can be put in HomeState management, there was a concern, I can’t remember now, terrible. Continue)
And here I can see that whenever I scroll the card it will buildChild.
Break up the component
When we started, our pages were all on one page, and it looked like it was going to be horrible, but now let’s break it up outside,
_FloatBtnWidget
Hover add button
class _FloatBtnWidget extends StatelessWidget {
_FloatBtnWidget(this._homeProvider);
final HomeState _homeProvider;
@override
Widget build(BuildContext context) {
double cil = _homeProvider.value - _homeProvider.value.floor();
double lerp = cil == 0 ? 1 : cil;
return Container(
width: 56,
height: 56,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color.lerp(
StaticStyle.linerColor[_homeProvider.curPage][0],
StaticStyle.linerColor[_homeProvider.value.ceil()][0],
lerp,
),
Color.lerp(
StaticStyle.linerColor[_homeProvider.curPage][1],
StaticStyle.linerColor[_homeProvider.value.ceil()][1],
lerp,
),
],
),
boxShadow: [
BoxShadow(
color: Color.fromARGB(100.87.211.255),
blurRadius: 8, ) ], ), child: Icon(Icons.add, color: Colors.white), ); }}Copy the code
_BottomNavWidget
Bottom navigation bar
class _BottomNavWidget extends StatelessWidget {
_BottomNavWidget(this._homeProvider, this.tabState);
final TabState tabState;
final HomeState _homeProvider;
@override
Widget build(BuildContext context) {
double cil = _homeProvider.value - _homeProvider.value.floor();
double lerp = cil == 0 ? 1 : cil;
final Gradient gradient = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.black54,
Colors.black,
],
);
final Gradient selectedGradient = LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color.lerp(
StaticStyle.linerColor[_homeProvider.curPage][0],
StaticStyle.linerColor[_homeProvider.value.ceil()][0],
lerp,
),
Color.lerp(
StaticStyle.linerColor[_homeProvider.curPage][1],
StaticStyle.linerColor[_homeProvider.value.ceil()][1],
lerp,
),
],
);
return DecoratedBox(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Color.fromARGB(100.200.200.200),
blurRadius: 8,
)
]),
child: ClipRRect(
borderRadius: BorderRadius.only(topRight: Radius.circular(20), topLeft: Radius.circular(20)),
child: BottomAppBar(
elevation: 0,
notchMargin: 6,
shape: CircularNotchedRectangle(),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
GradientIconBtn(
Icons.note_add,
key: ValueKey('page-index-0'),
iconSize: 26,
gradient: gradient,
selectedGradient: selectedGradient,
selected: tabState.tabIndex == 0,
onPress: () {
tabState.setTab(0);
},
),
Text(' '),
GradientIconBtn(
Icons.person,
key: ValueKey('page-index-1'),
iconSize: 26,
gradient: gradient,
selectedGradient: selectedGradient,
selected: tabState.tabIndex == 1,
onPress: () {
tabState.setTab(1); }, [, [, (), (), (), (); }}Copy the code
The navigation bar menu also carries the encapsulation GradientIconBtn:
class GradientIconBtn extends StatelessWidget {
GradientIconBtn(
this.icon, {
Key key,
@required this.onPress,
this.iconSize,
this.gradient,
this.selectedGradient,
this.selected = false,
}) : super(key: key);
final VoidCallback onPress;
final IconData icon;
final double iconSize;
final Gradient gradient;
final Gradient selectedGradient;
final bool selected;
@override
Widget build(BuildContext context) {
returnIconButton( onPressed: onPress, icon: gradient == null ? Icon(icon, size: iconSize) : GradientText( iconData: icon, iconSize: iconSize, gradient: selected ? selectedGradient : gradient, ), ); }}Copy the code
Final assemblyChangeNotifierProvider
:
ChangeNotifierProvider<HomeState>(
builder: (_) => HomeState(_pageController),
child: Consumer<HomeState>(
child: IndexedStack(
index: widget.tabState.tabIndex,
children: <Widget>[
NoteYearViewPage(_pageController),
MinePage(),
],
),
builder: (_, HomeState homeProvider, Widget child) => Scaffold(
body: child,
floatingActionButton: _FloatBtnWidget(homeProvider),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: _BottomNavWidget(homeProvider, widget.tabState),
),
),
)
Copy the code
NoteYearViewPage is a card page, simple, write dead gradient. MinePage is my page, empty..
As you can see, we use the ChangeNotifierProvider. When we receive the buildChild event, a Scaffold is built and our child is put into that Scaffold intact, avoiding the need to build again.
Do call it a day
Seems to be done, ha ha ha ~ paste code is really cool, the whole process only takes 28 minutes. There are a few minor details that may not be explained, but you can check out the source code: gayHub