Provider
了官方說好用,那麼用就是了~bash
使用provider
是爲了更好的進行狀態管理,爲何要進行狀態管理?固然你怕你組件多了本身瞎搞,亂成一鍋粥~markdown
沒圖啊,效果圖再貼一遍吧,狗帶 less
double
)了,才能作出相應的改變/// 色盤: 寫兩個意思一下,十二個月,應該有十二個。。
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),
],
];
複製代碼
build
build
,只要我build
的足夠快,你的眼睛就跟不上我。。。動畫也不是這麼搞的嘛,笑摸我狗頭~provider
走起來有了上面的分析,咱們的provider
只要通知page
就夠了,ide
/// 哇靠,怎麼和官方的寫法有差異!!
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 get value => _ctrl?.page ?? 0;
int _curPage = 0;
void setPage(int index) {
_curPage = index;
notifyListeners();
}
void buildChild() {
notifyListeners();
}
}
複製代碼
哇靠,怎麼和官方的寫法有差異!!其實沒什麼差異,只是咱們有一個addListener
的操做,而咱們的PageController
不是由HomeState
來管理的。(實際上是能夠放在HomeState
管理,當時有一個什麼顧慮,我如今想不起來了,可怕。。繼續)動畫
這裏我能夠看到,只要滾動卡片就會buildChild
。ui
剛開始的時候,咱們的頁面都堆在一個頁面裏,看起來及其兇殘,如今外面來拆分一下,this
_FloatBtnWidget
懸浮的添加按鈕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),
);
}
}
複製代碼
_BottomNavWidget
底部導航欄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);
},
),
],
),
),
),
);
}
}
複製代碼
導航欄的菜單也進行的封裝GradientIconBtn
:spa
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) {
return IconButton(
onPressed: onPress,
icon: gradient == null
? Icon(icon, size: iconSize)
: GradientText(
iconData: icon,
iconSize: iconSize,
gradient: selected ? selectedGradient : gradient,
),
);
}
}
複製代碼
ChangeNotifierProvider
: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),
),
),
)
複製代碼
NoteYearViewPage
是卡片頁面,比較簡單,寫死的漸變。MinePage
是個人頁面,空蕩蕩。。code
能夠看到,咱們使用了ChangeNotifierProvider
,當收到buildChild
事件後,就會build
一個Scaffold
而咱們的child
則會原封不動的放進Scaffold
中,避免了從新build
。cdn
好像完成了,呵呵呵~貼代碼真是爽,整個過程只要28分鐘。。 中間有一些小細節可能沒有說明,想了解的小夥伴能夠查看源碼: gayhub