您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
221 行
7.9 KiB
221 行
7.9 KiB
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Unity.UIWidgets.foundation;
|
|
using Unity.UIWidgets.painting;
|
|
using Unity.UIWidgets.rendering;
|
|
using Unity.UIWidgets.ui;
|
|
using Unity.UIWidgets.widgets;
|
|
|
|
namespace Unity.UIWidgets.cupertino {
|
|
public class CupertinoTabScaffold : StatefulWidget {
|
|
public CupertinoTabScaffold(
|
|
Key key = null,
|
|
CupertinoTabBar tabBar = null,
|
|
IndexedWidgetBuilder tabBuilder = null,
|
|
Color backgroundColor = null,
|
|
bool resizeToAvoidBottomInset = true
|
|
) : base(key: key) {
|
|
D.assert(tabBar != null);
|
|
D.assert(tabBuilder != null);
|
|
this.tabBar = tabBar;
|
|
this.tabBuilder = tabBuilder;
|
|
this.backgroundColor = backgroundColor;
|
|
this.resizeToAvoidBottomInset = resizeToAvoidBottomInset;
|
|
}
|
|
|
|
|
|
public readonly CupertinoTabBar tabBar;
|
|
|
|
public readonly IndexedWidgetBuilder tabBuilder;
|
|
|
|
public readonly Color backgroundColor;
|
|
|
|
public readonly bool resizeToAvoidBottomInset;
|
|
|
|
public override State createState() {
|
|
return new _CupertinoTabScaffoldState();
|
|
}
|
|
}
|
|
|
|
class _CupertinoTabScaffoldState : State<CupertinoTabScaffold> {
|
|
int _currentPage;
|
|
|
|
public override void initState() {
|
|
base.initState();
|
|
this._currentPage = this.widget.tabBar.currentIndex;
|
|
|
|
}
|
|
|
|
public override void didUpdateWidget(StatefulWidget _oldWidget) {
|
|
CupertinoTabScaffold oldWidget = _oldWidget as CupertinoTabScaffold;
|
|
base.didUpdateWidget(oldWidget);
|
|
if (this._currentPage >= this.widget.tabBar.items.Count) {
|
|
this._currentPage = this.widget.tabBar.items.Count - 1;
|
|
D.assert(this._currentPage >= 0,
|
|
() => "CupertinoTabBar is expected to keep at least 2 tabs after updating"
|
|
);
|
|
}
|
|
|
|
if (this.widget.tabBar.currentIndex != oldWidget.tabBar.currentIndex) {
|
|
this._currentPage = this.widget.tabBar.currentIndex;
|
|
}
|
|
}
|
|
|
|
public override Widget build(BuildContext context) {
|
|
List<Widget> stacked = new List<Widget> { };
|
|
|
|
MediaQueryData existingMediaQuery = MediaQuery.of(context);
|
|
MediaQueryData newMediaQuery = MediaQuery.of(context);
|
|
|
|
Widget content = new _TabSwitchingView(
|
|
currentTabIndex: this._currentPage,
|
|
tabNumber: this.widget.tabBar.items.Count,
|
|
tabBuilder: this.widget.tabBuilder
|
|
);
|
|
EdgeInsets contentPadding = EdgeInsets.zero;
|
|
|
|
if (this.widget.resizeToAvoidBottomInset) {
|
|
newMediaQuery = newMediaQuery.removeViewInsets(removeBottom: true);
|
|
contentPadding = EdgeInsets.only(bottom: existingMediaQuery.viewInsets.bottom);
|
|
}
|
|
|
|
if (this.widget.tabBar != null &&
|
|
(!this.widget.resizeToAvoidBottomInset ||
|
|
this.widget.tabBar.preferredSize.height > existingMediaQuery.viewInsets.bottom)) {
|
|
float bottomPadding = this.widget.tabBar.preferredSize.height + existingMediaQuery.padding.bottom;
|
|
|
|
if (this.widget.tabBar.opaque(context)) {
|
|
contentPadding = EdgeInsets.only(bottom: bottomPadding);
|
|
}
|
|
else {
|
|
newMediaQuery = newMediaQuery.copyWith(
|
|
padding: newMediaQuery.padding.copyWith(
|
|
bottom: bottomPadding
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
content = new MediaQuery(
|
|
data: newMediaQuery,
|
|
child: new Padding(
|
|
padding: contentPadding,
|
|
child: content
|
|
)
|
|
);
|
|
|
|
stacked.Add(content);
|
|
|
|
if (this.widget.tabBar != null) {
|
|
stacked.Add(new Align(
|
|
alignment: Alignment.bottomCenter,
|
|
child: this.widget.tabBar.copyWith(
|
|
currentIndex: this._currentPage,
|
|
onTap: (int newIndex) => {
|
|
this.setState(() => { this._currentPage = newIndex; });
|
|
if (this.widget.tabBar.onTap != null) {
|
|
this.widget.tabBar.onTap(newIndex);
|
|
}
|
|
}
|
|
)
|
|
));
|
|
}
|
|
|
|
return new DecoratedBox(
|
|
decoration: new BoxDecoration(
|
|
color: this.widget.backgroundColor ?? CupertinoTheme.of(context).scaffoldBackgroundColor
|
|
),
|
|
child: new Stack(
|
|
children: stacked
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
class _TabSwitchingView : StatefulWidget {
|
|
public _TabSwitchingView(
|
|
int currentTabIndex,
|
|
int tabNumber,
|
|
IndexedWidgetBuilder tabBuilder
|
|
) {
|
|
D.assert(tabNumber > 0);
|
|
D.assert(tabBuilder != null);
|
|
this.currentTabIndex = currentTabIndex;
|
|
this.tabNumber = tabNumber;
|
|
this.tabBuilder = tabBuilder;
|
|
}
|
|
|
|
public readonly int currentTabIndex;
|
|
public readonly int tabNumber;
|
|
public readonly IndexedWidgetBuilder tabBuilder;
|
|
|
|
public override State createState() {
|
|
return new _TabSwitchingViewState();
|
|
}
|
|
}
|
|
|
|
class _TabSwitchingViewState : State<_TabSwitchingView> {
|
|
List<Widget> tabs;
|
|
List<FocusScopeNode> tabFocusNodes;
|
|
|
|
public override void initState() {
|
|
base.initState();
|
|
this.tabs = new List<Widget>(this.widget.tabNumber);
|
|
for (int i = 0; i < this.widget.tabNumber; i++) {
|
|
this.tabs.Add(null);
|
|
}
|
|
this.tabFocusNodes = Enumerable.Repeat(new FocusScopeNode(), this.widget.tabNumber).ToList();
|
|
}
|
|
|
|
public override void didChangeDependencies() {
|
|
base.didChangeDependencies();
|
|
this._focusActiveTab();
|
|
}
|
|
|
|
public override void didUpdateWidget(StatefulWidget _oldWidget) {
|
|
_TabSwitchingView oldWidget = _oldWidget as _TabSwitchingView;
|
|
base.didUpdateWidget(oldWidget);
|
|
this._focusActiveTab();
|
|
}
|
|
|
|
void _focusActiveTab() {
|
|
FocusScope.of(this.context).setFirstFocus(this.tabFocusNodes[this.widget.currentTabIndex]);
|
|
}
|
|
|
|
public override void dispose() {
|
|
foreach (FocusScopeNode focusScopeNode in this.tabFocusNodes) {
|
|
focusScopeNode.detach();
|
|
}
|
|
|
|
base.dispose();
|
|
}
|
|
|
|
public override Widget build(BuildContext context) {
|
|
List<Widget> children = new List<Widget>();
|
|
for (int index = 0; index < this.widget.tabNumber; index++) {
|
|
bool active = index == this.widget.currentTabIndex;
|
|
|
|
var tabIndex = index;
|
|
if (active || this.tabs[index] != null) {
|
|
this.tabs[index] = this.widget.tabBuilder(context, tabIndex);
|
|
}
|
|
|
|
children.Add(new Offstage(
|
|
offstage: !active,
|
|
child: new TickerMode(
|
|
enabled: active,
|
|
child: new FocusScope(
|
|
node: this.tabFocusNodes[index],
|
|
child: this.tabs[index] ?? new Container()
|
|
)
|
|
)
|
|
));
|
|
}
|
|
|
|
return new Stack(
|
|
fit: StackFit.expand,
|
|
children: children
|
|
);
|
|
}
|
|
}
|
|
}
|