我在 HomePage 中有以下代码(我将在下面显示)将其从文章中取出,它是一个堆栈,我在 BottomNavigationBar 中有 5 个页面,
我想要做的是,从 HomeView 中,当触摸容器_publicity()
方法时,会打开一个“Publicity”屏幕,该屏幕必须保持 BottomNavigationBar,它正在正常打开并且 BottomNavigationBar 仍然存在(image1)。但是,当我从另一个容器_promotions()
方法中我想转到一个不包含 BottomNavigationBar 例如 Navigator.Push 的外部页面时,这会打开页面但带有 BottomNavigationBar !!和上面的主页AppBar,它似乎没有离开主页脚手架(image2),当它应该是一个完全独立的脚手架/页面时。
(忽略这 2 个 AppBars,将被修复)
图1:
图2:
是的,我希望 BottomNavigationBar 持续存在,但是当我尝试导航到另一个不必具有 BottomNavigationBar 的独立外部页面时,它会如我所说的在 HOMEPAGE 内显示,这是错误的,因为它应该是一个完全独立的脚手架,处理这个问题花了好几天,我找不到解决方案!
还有关于该代码的另一个问题,正如我所说的代码部分是堆栈并且 TabNavigator 将其从文章中取出,这是一种好的做法吗?因为我是初学者,我想了解更多。
主页:
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
PageController _pageController;
Future<EmpresaModel> empresaFuture;
Future<EmpresaModel> _getEmpresa = TestService().getEmpresa();
@override
void initState() {
super.initState();
_pageController = PageController();
empresaFuture = _getEmpresa;
}
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
Directory libCacheDir = Directory("");
final double dividerIndent = 10;
int currentButton = 0;
String _currentPage = "Page1";
List<String> pageKeys = ["Page1", "Page2", "Page3", "Page4", "Page5"];
Map<String, GlobalKey<NavigatorState>> _navigatorKeys = {
"Page1": GlobalKey<NavigatorState>(),
"Page2": GlobalKey<NavigatorState>(),
"Page3": GlobalKey<NavigatorState>(),
"Page4": GlobalKey<NavigatorState>(),
"Page5": GlobalKey<NavigatorState>(),
};
void _selectTab(String tabItem, int index) {
if (tabItem == _currentPage) {
_navigatorKeys[tabItem].currentState.popUntil((route) => route.isFirst);
} else {
setState(() {
_currentPage = pageKeys[index];
currentButton = index;
});
}
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
final isFirstRouteInCurrentTab =
!await _navigatorKeys[_currentPage].currentState.maybePop();
if (isFirstRouteInCurrentTab) {
if (_currentPage != "Page1") {
_selectTab("Page1", 1);
return false;
}
}
return isFirstRouteInCurrentTab;
},
child: SafeArea(
child: GestureDetector(
onTap: () async {
FocusScopeNode currentFocus = FocusScope.of(context);
currentFocus.unfocus();
},
child: Scaffold(
appBar: (currentButton == 4) ? SettingsAppBar() : CustomAppBar(),
body: FutureBuilder(
future: empresaFuture,
builder: (BuildContext context,
AsyncSnapshot<EmpresaModel> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
Center(
child: Text('Error: ${snapshot.error}'),
)
],
);
} else {
return SizedBox.expand(
child: Stack(
children: [
_buildOffstageNavigator(
"Page1",
snapshot.data.links,
snapshot.data.publi,
),
_buildOffstageNavigator("Page2"),
_buildOffstageNavigator("Page3"),
_buildOffstageNavigator("Page4"),
_buildOffstageNavigator("Page5"),
],
),
);
}
}),
// views[currentButton],
bottomNavigationBar: BottomNavigationBar(
selectedItemColor: Colors.black,
type: BottomNavigationBarType.fixed,
currentIndex: currentButton,
onTap: (int index) {
_selectTab(pageKeys[index], index);
},
//_onItemTapped,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home_filled),
label: S.of(context).homePageBottomBarHome),
BottomNavigationBarItem(
icon: Icon(Icons.local_mall),
label: S.of(context).homePageBottomBarBuy),
BottomNavigationBarItem(
icon: Icon(Icons.storefront),
label: S.of(context).homePageBottomBarTradeMark),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart),
label: S.of(context).homePageBottomBarCart),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: S.of(context).homePageBottomBarProfile),
],
),
))),
);
}
Widget _buildOffstageNavigator(
String tabItem, [
List<Link> listLink,
List<Publi> listPubli,
]) {
return Offstage(
offstage: _currentPage != tabItem,
child: TabNavigator(
navigatorKey: _navigatorKeys[tabItem],
tabItem: tabItem,
listLink: listLink,
listPubli: listPubli,
),
);
}
}
主页视图:
class HomeView extends StatefulWidget {
final listLink;
final listPubli;
const HomeView({
Key key,
this.listLink,
this.listPubli,
}) : super(key: key);
@override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
final double dividerIndent = 10;
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: <Widget>[
_searchBar(),
SizedBox(height: 5),
CategoryList(
listLinkCategorias: widget.listLink,
),
SizedBox(height: size.height * 0.03),
_promotions(size),
SizedBox(height: size.height * 0.025),
_publicity(widget.listPubli),
SizedBox(height: size.height * 0.03),
_pageViewProducts(),
SizedBox(height: 50),
],
),
),
);
}
_searchBar() {
return Container(
margin: EdgeInsets.symmetric(horizontal: 0, vertical: 15),
height: 60,
width: double.infinity,
child: FloatingSearchBar(
elevation: 1,
backdropColor: Colors.transparent,
backgroundColor: Colors.grey[200],
hint: S.of(context).homePageSearchBar,
scrollPadding: const EdgeInsets.only(top: 16, bottom: 56),
transitionDuration: const Duration(milliseconds: 800),
transitionCurve: Curves.easeInOut,
physics: const BouncingScrollPhysics(),
openAxisAlignment: 0.0,
debounceDelay: const Duration(milliseconds: 500),
onQueryChanged: (query) {
// Call your model, bloc, controller here.
},
// Specify a custom transition to be used for
// animating between opened and closed stated.
transition: CircularFloatingSearchBarTransition(),
actions: [
FloatingSearchBarAction.searchToClear(
showIfClosed: true,
),
],
builder: (context, transition) {
return ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Material(
color: Colors.white,
elevation: 0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: Colors.accents.map((color) {
return Container(height: 112, color: color);
}).toList(),
),
),
);
},
),
);
}
Widget _promotions(size) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => new ProductosPage()));
},
child: Container(
height: size.height * 0.34,
width: double.infinity,
margin: EdgeInsets.symmetric(horizontal: 8.0),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10), topRight: Radius.circular(10)),
child: Image.asset(
'assets/images/promociones.jpg',
fit: BoxFit.cover,
),
),
),
);
}
Widget _publicity(List<Publi> listPubli) {
// final _pagesBloc = BlocProvider.of<PagesBloc>(context);
return GestureDetector(
onTap: () {
// _pagesBloc.add(PagesEvents.publicityView);
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) => new PublicityPage()));
},
child: Container(
alignment: Alignment.center,
margin: EdgeInsets.symmetric(horizontal: 8.0),
height: 86,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), color: Colors.grey[300]
),
child: CachedNetworkImage(
imageUrl: TestService().baseURL + listPubli[0].img,
fit: BoxFit.contain,
errorWidget: (context, url, error) => Icon(Icons.error),
),
),
);
}
Widget _pageViewProducts() {
return Container(
height: 250,
width: double.infinity,
child: ListView.separated(
physics: PageScrollPhysics(),
separatorBuilder: (context, index) => Divider(
indent: dividerIndent,
),
scrollDirection: Axis.horizontal,
controller: PageController(viewportFraction: 0.5, initialPage: 0),
itemCount: products.length,
itemBuilder: (context, index) {
if (index == 0) {
return Padding(
child: _productSelector(index),
padding: EdgeInsets.only(left: dividerIndent),
);
} else if (index == products.length - 1) {
return Padding(
child: _productSelector(index),
padding: EdgeInsets.only(right: dividerIndent),
);
}
return _productSelector(index);
}),
);
}
Widget _productSelector(int index) {
return Container(
height: 250,
width: 150,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 150,
padding: EdgeInsets.all(14),
decoration: BoxDecoration(color: Colors.grey.shade300),
child: Stack(
children: <Widget>[
Container(
height: 160,
width: 130,
child: Center(
child: Image.asset(
products[index].imagename,
fit: BoxFit.contain,
),
),
),
Positioned(
bottom: 0,
right: 0,
child: Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: Colors.black),
child: Icon(
Icons.add,
color: Colors.white,
size: 15,
),
),
),
],
),
),
Container(
margin: EdgeInsets.only(left: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('${products[index].name}',
style: TextStyle(
fontSize: 12.8,
fontWeight: FontWeight.w500,
color: Colors.grey[600]),
overflow: TextOverflow.ellipsis),
Text('\$${products[index].price}',
style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600),
overflow: TextOverflow.ellipsis),
],
),
),
],
),
);
}
}
标签导航器:
class TabNavigatorRoutes {
static const String root = '/';
static const String detail = '/detail';
}
class TabNavigator extends StatelessWidget {
TabNavigator({this.navigatorKey, this.tabItem, this.listLink, this.listPubli});
final GlobalKey<NavigatorState> navigatorKey;
final String tabItem;
final listLink;
final listPubli;
@override
Widget build(BuildContext context) {
Widget child ;
if(tabItem == "Page1")
child = HomeView(listLink: listLink, listPubli: listPubli);
else if(tabItem == "Page2")
child = BuyView();
else if(tabItem == "Page3")
child = BrandView();
else if(tabItem == "Page4")
child = CartView();
else if(tabItem == "Page5")
child = SettingsView();
return Navigator(
key: navigatorKey,
onGenerateRoute: (routeSettings) {
return MaterialPageRoute(
builder: (context) => child
);
},
);
}
}