如何在 flutter 中从另一个页面调用选项卡控制器
How to call tab controller from another page in flutter
我有带 4 个选项卡的底部导航栏,一切正常,但我有另一个 class 调用 BannerImageItem,我想从那里调用选项卡 2。我尝试使用 Gloabal 键,但从选项卡控制器中获取 null 请帮助我,我被卡住了。
我有带 4 个选项卡的底部导航栏,一切正常,但我有另一个 class 调用 BannerImageItem,我想从那里调用选项卡 2。我尝试使用 Gloabal 键,但从选项卡控制器中获取 null 请帮助我,我被卡住了。
const int tabCount = 3;
const int turnsToRotateRight = 1;
const int turnsToRotateLeft = 3;
class MainTabControlDelegate {
int index;
Function(String nameTab) changeTab;
Function(int index) tabAnimateTo;
static MainTabControlDelegate _instance;
static MainTabControlDelegate getInstance() {
return _instance ??= MainTabControlDelegate._();
}
MainTabControlDelegate._();
}
class MainTabs extends StatefulWidget {
MainTabs({Key key}) : super(key: key);
@override
MainTabsState createState() => MainTabsState();
}
class MainTabsState extends State<MainTabs>
with
WidgetsBindingObserver,
SingleTickerProviderStateMixin,
AfterLayoutMixin {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final PageStorageBucket bucket = PageStorageBucket();
final StreamController<String> _controllerRouteWeb =
StreamController<String>.broadcast();
final _auth = FirebaseAuth.instance;
var tabData;
Map saveIndexTab = Map();
FirebaseUser loggedInUser;
bool isAdmin = false;
final List<Widget> _tabView = [];
TabController tabController;
@override
void afterFirstLayout(BuildContext context) {
loadTabBar(context);
}
Widget tabView(Map<String, dynamic> data) {
switch (data['layout']) {
case 'category':
return CategoriesScreen(
key: Key("category"),
layout: data['categoryLayout'],
categories: data['categories'],
images: data['images'],
showChat: data['showChat'],
);
case 'search':
return SearchScreen(key: Key("search"), showChat: data['showChat']);
case 'cart':
return CartScreen(showChat: data['showChat']);
case 'profile':
return UserScreen(
settings: data['settings'],
background: data['background'],
showChat: data['showChat']);
case 'blog':
return HorizontalSliderList(config: data);
case 'wishlist':
return screen.WishList(canPop: false, showChat: data['showChat']);
case 'page':
return WebViewScreen(
title: data['title'], url: data['url'], showChat: data['showChat']);
case 'html':
return StaticSite(data: data['data'], showChat: data['showChat']);
case 'static':
return StaticPage(data: data['data'], showChat: data['showChat']);
case 'postScreen':
return PostScreen(
pageId: data['pageId'],
pageTitle: data['pageTitle'],
isLocatedInTabbar: true,
showChat: data['showChat']);
case 'dynamic':
default:
return HomeScreen();
}
}
void changeTab(String nameTab) {
if (kLayoutWeb) {
_controllerRouteWeb.sink
.add(nameTab.contains("/") ? nameTab : '/$nameTab');
} else {
tabController?.animateTo(saveIndexTab[nameTab] ?? 0);
}
}
void loadTabBar(context) {
tabData = Provider.of<AppModel>(context, listen: false).appConfig['TabBar']
as List;
for (var i = 0; i < tabData.length; i++) {
Map<String, dynamic> _dataOfTab = Map.from(tabData[i]);
saveIndexTab[_dataOfTab['layout']] = i;
_tabView.add(tabView(_dataOfTab));
}
setState(() {
tabController = TabController(length: _tabView.length, vsync: this);
});
if (MainTabControlDelegate.getInstance().index != null) {
tabController.animateTo(MainTabControlDelegate.getInstance().index);
} else {
MainTabControlDelegate.getInstance().index = 0;
}
// Load the Design from FluxBuilder
tabController.addListener(() {
eventBus.fire('tab_${tabController.index}');
if (_tabView[tabController.index] is SearchScreen) {
eventBus.fire(UpdateSearchFilterEvent());
}
MainTabControlDelegate.getInstance().index = tabController.index;
});
}
Future<void> getCurrentUser() async {
try {
//Provider.of<UserModel>(context).getUser();
final user = await _auth.currentUser();
if (user != null) {
setState(() {
loggedInUser = user;
});
}
} catch (e) {
printLog("[tabbar] getCurrentUser error ${e.toString()}");
}
}
bool checkIsAdmin() {
if (loggedInUser.email == adminEmail) {
isAdmin = true;
} else {
isAdmin = false;
}
return isAdmin;
}
@override
void initState() {
if (!kIsWeb) {
getCurrentUser();
}
MainTabControlDelegate.getInstance().changeTab = changeTab;
MainTabControlDelegate.getInstance().tabAnimateTo = (int index) {
tabController?.animateTo(index);
};
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
tabController?.dispose();
_controllerRouteWeb?.close();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused) {
// went to Background
}
if (state == AppLifecycleState.resumed) {
// came back to Foreground
final appModel = Provider.of<AppModel>(context, listen: false);
if (appModel.deeplink?.isNotEmpty ?? false) {
if (appModel.deeplink['screen'] == 'NotificationScreen') {
appModel.deeplink = null;
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NotificationScreen()),
);
}
}
}
super.didChangeAppLifecycleState(state);
}
@override
Widget build(BuildContext context) {
printLog('[tabbar] ============== tabbar.dart DASHBOARD ==============');
final isDesktop = isDisplayDesktop(context);
Utils.setStatusBarWhiteForeground(false);
kLayoutWeb = (kIsWeb || isDesktop);
if (_tabView.isEmpty) {
return Container(
color: Colors.white,
child: kLoadingWidget(context),
);
}
return renderBody(context);
}
Widget renderBody(BuildContext context) {
final ThemeData theme = Theme.of(context);
if (kLayoutWeb) {
final isDesktop = isDisplayDesktop(context);
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
body: SafeArea(
// For desktop layout we do not want to have SafeArea at the top and
// bottom to display 100% height content on the accounts view.
top: !isDesktop,
bottom: !isDesktop,
child: Theme(
// This theme effectively removes the default visual touch
// feedback for tapping a tab, which is replaced with a custom
// animation.
data: theme.copyWith(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
child: LayoutWebCustom(
menu: MenuBar(controllerRouteWeb: _controllerRouteWeb),
content: StreamBuilder<String>(
initialData: RouteList.homeScreen,
stream: _controllerRouteWeb.stream,
builder: (context, snapshot) {
return Navigator(
key: Key(snapshot.data),
initialRoute: snapshot.data,
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute(
builder: Routes.getRouteByName(settings.name),
settings: settings,
maintainState: false,
fullscreenDialog: true,
);
},
);
},
),
)),
),
);
} else {
final screenSize = MediaQuery.of(context).size;
return Container(
color: Theme.of(context).backgroundColor,
child: Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
resizeToAvoidBottomPadding: false,
key: _scaffoldKey,
body: WillPopScope(
onWillPop: () async {
if (tabController.index != 0) {
tabController.animateTo(0);
return false;
} else {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(S.of(context).areYouSure),
content: Text(S.of(context).doYouWantToExitApp),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text(S.of(context).no),
),
FlatButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text(S.of(context).yes),
),
],
),
) ??
false;
}
},
child: TabBarView(
controller: tabController,
physics: NeverScrollableScrollPhysics(),
children: _tabView,
),
),
drawer: Drawer(child: MenuBar()),
bottomNavigationBar: SafeArea(
top: false,
child: Container(
width: screenSize.width,
child: FittedBox(
child: Container(
width: screenSize.width /
(2 / (screenSize.height / screenSize.width)),
child: TabBar(
controller: tabController,
tabs: renderTabbar(),
isScrollable: false,
labelColor: Theme.of(context).primaryColor,
indicatorSize: TabBarIndicatorSize.label,
indicatorPadding: EdgeInsets.all(4.0),
indicatorColor: Theme.of(context).primaryColor,
),
),
),
),
),
),
);
}
}
List<Widget> renderTabbar() {
final isTablet = Tools.isTablet(MediaQuery.of(context));
var totalCart = Provider.of<CartModel>(context).totalCartQuantity;
final tabData = Provider.of<AppModel>(context, listen: false)
.appConfig['TabBar'] as List;
List<Widget> list = [];
tabData.forEach((item) {
var icon = !item["icon"].contains('/')
? Icon(
featherIcons[item["icon"]],
color: Theme.of(context).accentColor,
size: 22,
)
: (item["icon"].contains('http')
? Image.network(
item["icon"],
color: Theme.of(context).accentColor,
width: 24,
)
: Image.asset(
item["icon"],
color: Theme.of(context).accentColor,
width: 24,
));
if (item["layout"] == "cart") {
icon = Stack(
children: <Widget>[
Container(
width: 30,
height: 25,
padding: const EdgeInsets.only(right: 6.0, top: 4),
child: icon,
),
if (totalCart > 0)
Positioned(
right: 0,
top: 0,
child: Container(
padding: const EdgeInsets.all(1),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(8),
),
constraints: BoxConstraints(
minWidth: 16,
minHeight: 16,
),
child: Text(
totalCart.toString(),
style: TextStyle(
color: Colors.white,
fontSize: isTablet ? 14 : 12,
),
textAlign: TextAlign.center,
),
),
)
],
);
}
if (item["label"] != null) {
list.add(Tab(icon: icon, text: item["label"]));
} else {
list.add(Tab(icon: icon));
}
});
return list;
}
}
这里是 BannerImageItem
/// The Banner type to display the image
class BannerImageItem extends StatefulWidget {
@override
final Key key;
final dynamic config;
final double width;
final double padding;
final BoxFit boxFit;
final double radius;
BannerImageItem({
this.key,
this.config,
this.padding,
this.width,
this.boxFit,
this.radius,
}) : super(key: key);
@override
_BannerImageItemState createState() => _BannerImageItemState();
}
class _BannerImageItemState extends State<BannerImageItem>
with AfterLayoutMixin {
List<Product> _products;
GlobalKey<MainTabsState> _scaffoldKey = GlobalKey<MainTabsState>();
@override
void afterFirstLayout(BuildContext context) {
/// for pre-load the list product
if (widget.config['data'] != null) {
print(widget.config['data']);
_products = widget.config['data'];
}
}
@override
Widget build(BuildContext context) {
double _padding =
Tools.formatDouble(widget.config["padding"] ?? widget.padding ?? 10.0);
double _radius = Tools.formatDouble(widget.config['radius'] ??
(widget.radius != null ? widget.radius : 0.0));
final screenSize = MediaQuery.of(context).size;
final screenWidth =
screenSize.width / (2 / (screenSize.height / screenSize.width));
final itemWidth = widget.width ?? screenWidth;
return GestureDetector(key: _scaffoldKey,
onTap: () { _scaffoldKey.currentState.tabController.animateTo(1);
},
child: Container(
width: itemWidth,
child: Padding(
padding: EdgeInsets.only(left: _padding, right: _padding),
child: ClipRRect(
borderRadius: BorderRadius.circular(_radius),
child: Tools.image(
fit: widget.boxFit ?? BoxFit.fitWidth,
url: widget.config["image"],
),
),
),
),
);
}
}
return GestureDetector(key: _scaffoldKey,
onTap: () { _scaffoldKey.currentState.tabController.animateTo(1);
},
child: Container(
width: itemWidth,
child: Padding(
padding: EdgeInsets.only(left: _padding, right: _padding),
child: ClipRRect(
borderRadius: BorderRadius.circular(_radius),
child: Tools.image(
fit: widget.boxFit ?? BoxFit.fitWidth,
url: widget.config["image"],
),
),
),
),
);
替换为
return GestureDetector(
onTap: () { MainTabControlDelegate.getInstance().tabAnimateTo(1);
},
child: Container(
width: itemWidth,
child: Padding(
padding: EdgeInsets.only(left: _padding, right: _padding),
child: ClipRRect(
borderRadius: BorderRadius.circular(_radius),
child: Tools.image(
fit: widget.boxFit ?? BoxFit.fitWidth,
url: widget.config["image"],
),
),
),
),
);
我有带 4 个选项卡的底部导航栏,一切正常,但我有另一个 class 调用 BannerImageItem,我想从那里调用选项卡 2。我尝试使用 Gloabal 键,但从选项卡控制器中获取 null 请帮助我,我被卡住了。
我有带 4 个选项卡的底部导航栏,一切正常,但我有另一个 class 调用 BannerImageItem,我想从那里调用选项卡 2。我尝试使用 Gloabal 键,但从选项卡控制器中获取 null 请帮助我,我被卡住了。
const int tabCount = 3;
const int turnsToRotateRight = 1;
const int turnsToRotateLeft = 3;
class MainTabControlDelegate {
int index;
Function(String nameTab) changeTab;
Function(int index) tabAnimateTo;
static MainTabControlDelegate _instance;
static MainTabControlDelegate getInstance() {
return _instance ??= MainTabControlDelegate._();
}
MainTabControlDelegate._();
}
class MainTabs extends StatefulWidget {
MainTabs({Key key}) : super(key: key);
@override
MainTabsState createState() => MainTabsState();
}
class MainTabsState extends State<MainTabs>
with
WidgetsBindingObserver,
SingleTickerProviderStateMixin,
AfterLayoutMixin {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final PageStorageBucket bucket = PageStorageBucket();
final StreamController<String> _controllerRouteWeb =
StreamController<String>.broadcast();
final _auth = FirebaseAuth.instance;
var tabData;
Map saveIndexTab = Map();
FirebaseUser loggedInUser;
bool isAdmin = false;
final List<Widget> _tabView = [];
TabController tabController;
@override
void afterFirstLayout(BuildContext context) {
loadTabBar(context);
}
Widget tabView(Map<String, dynamic> data) {
switch (data['layout']) {
case 'category':
return CategoriesScreen(
key: Key("category"),
layout: data['categoryLayout'],
categories: data['categories'],
images: data['images'],
showChat: data['showChat'],
);
case 'search':
return SearchScreen(key: Key("search"), showChat: data['showChat']);
case 'cart':
return CartScreen(showChat: data['showChat']);
case 'profile':
return UserScreen(
settings: data['settings'],
background: data['background'],
showChat: data['showChat']);
case 'blog':
return HorizontalSliderList(config: data);
case 'wishlist':
return screen.WishList(canPop: false, showChat: data['showChat']);
case 'page':
return WebViewScreen(
title: data['title'], url: data['url'], showChat: data['showChat']);
case 'html':
return StaticSite(data: data['data'], showChat: data['showChat']);
case 'static':
return StaticPage(data: data['data'], showChat: data['showChat']);
case 'postScreen':
return PostScreen(
pageId: data['pageId'],
pageTitle: data['pageTitle'],
isLocatedInTabbar: true,
showChat: data['showChat']);
case 'dynamic':
default:
return HomeScreen();
}
}
void changeTab(String nameTab) {
if (kLayoutWeb) {
_controllerRouteWeb.sink
.add(nameTab.contains("/") ? nameTab : '/$nameTab');
} else {
tabController?.animateTo(saveIndexTab[nameTab] ?? 0);
}
}
void loadTabBar(context) {
tabData = Provider.of<AppModel>(context, listen: false).appConfig['TabBar']
as List;
for (var i = 0; i < tabData.length; i++) {
Map<String, dynamic> _dataOfTab = Map.from(tabData[i]);
saveIndexTab[_dataOfTab['layout']] = i;
_tabView.add(tabView(_dataOfTab));
}
setState(() {
tabController = TabController(length: _tabView.length, vsync: this);
});
if (MainTabControlDelegate.getInstance().index != null) {
tabController.animateTo(MainTabControlDelegate.getInstance().index);
} else {
MainTabControlDelegate.getInstance().index = 0;
}
// Load the Design from FluxBuilder
tabController.addListener(() {
eventBus.fire('tab_${tabController.index}');
if (_tabView[tabController.index] is SearchScreen) {
eventBus.fire(UpdateSearchFilterEvent());
}
MainTabControlDelegate.getInstance().index = tabController.index;
});
}
Future<void> getCurrentUser() async {
try {
//Provider.of<UserModel>(context).getUser();
final user = await _auth.currentUser();
if (user != null) {
setState(() {
loggedInUser = user;
});
}
} catch (e) {
printLog("[tabbar] getCurrentUser error ${e.toString()}");
}
}
bool checkIsAdmin() {
if (loggedInUser.email == adminEmail) {
isAdmin = true;
} else {
isAdmin = false;
}
return isAdmin;
}
@override
void initState() {
if (!kIsWeb) {
getCurrentUser();
}
MainTabControlDelegate.getInstance().changeTab = changeTab;
MainTabControlDelegate.getInstance().tabAnimateTo = (int index) {
tabController?.animateTo(index);
};
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
tabController?.dispose();
_controllerRouteWeb?.close();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused) {
// went to Background
}
if (state == AppLifecycleState.resumed) {
// came back to Foreground
final appModel = Provider.of<AppModel>(context, listen: false);
if (appModel.deeplink?.isNotEmpty ?? false) {
if (appModel.deeplink['screen'] == 'NotificationScreen') {
appModel.deeplink = null;
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NotificationScreen()),
);
}
}
}
super.didChangeAppLifecycleState(state);
}
@override
Widget build(BuildContext context) {
printLog('[tabbar] ============== tabbar.dart DASHBOARD ==============');
final isDesktop = isDisplayDesktop(context);
Utils.setStatusBarWhiteForeground(false);
kLayoutWeb = (kIsWeb || isDesktop);
if (_tabView.isEmpty) {
return Container(
color: Colors.white,
child: kLoadingWidget(context),
);
}
return renderBody(context);
}
Widget renderBody(BuildContext context) {
final ThemeData theme = Theme.of(context);
if (kLayoutWeb) {
final isDesktop = isDisplayDesktop(context);
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
body: SafeArea(
// For desktop layout we do not want to have SafeArea at the top and
// bottom to display 100% height content on the accounts view.
top: !isDesktop,
bottom: !isDesktop,
child: Theme(
// This theme effectively removes the default visual touch
// feedback for tapping a tab, which is replaced with a custom
// animation.
data: theme.copyWith(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
child: LayoutWebCustom(
menu: MenuBar(controllerRouteWeb: _controllerRouteWeb),
content: StreamBuilder<String>(
initialData: RouteList.homeScreen,
stream: _controllerRouteWeb.stream,
builder: (context, snapshot) {
return Navigator(
key: Key(snapshot.data),
initialRoute: snapshot.data,
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute(
builder: Routes.getRouteByName(settings.name),
settings: settings,
maintainState: false,
fullscreenDialog: true,
);
},
);
},
),
)),
),
);
} else {
final screenSize = MediaQuery.of(context).size;
return Container(
color: Theme.of(context).backgroundColor,
child: Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
resizeToAvoidBottomPadding: false,
key: _scaffoldKey,
body: WillPopScope(
onWillPop: () async {
if (tabController.index != 0) {
tabController.animateTo(0);
return false;
} else {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(S.of(context).areYouSure),
content: Text(S.of(context).doYouWantToExitApp),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text(S.of(context).no),
),
FlatButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text(S.of(context).yes),
),
],
),
) ??
false;
}
},
child: TabBarView(
controller: tabController,
physics: NeverScrollableScrollPhysics(),
children: _tabView,
),
),
drawer: Drawer(child: MenuBar()),
bottomNavigationBar: SafeArea(
top: false,
child: Container(
width: screenSize.width,
child: FittedBox(
child: Container(
width: screenSize.width /
(2 / (screenSize.height / screenSize.width)),
child: TabBar(
controller: tabController,
tabs: renderTabbar(),
isScrollable: false,
labelColor: Theme.of(context).primaryColor,
indicatorSize: TabBarIndicatorSize.label,
indicatorPadding: EdgeInsets.all(4.0),
indicatorColor: Theme.of(context).primaryColor,
),
),
),
),
),
),
);
}
}
List<Widget> renderTabbar() {
final isTablet = Tools.isTablet(MediaQuery.of(context));
var totalCart = Provider.of<CartModel>(context).totalCartQuantity;
final tabData = Provider.of<AppModel>(context, listen: false)
.appConfig['TabBar'] as List;
List<Widget> list = [];
tabData.forEach((item) {
var icon = !item["icon"].contains('/')
? Icon(
featherIcons[item["icon"]],
color: Theme.of(context).accentColor,
size: 22,
)
: (item["icon"].contains('http')
? Image.network(
item["icon"],
color: Theme.of(context).accentColor,
width: 24,
)
: Image.asset(
item["icon"],
color: Theme.of(context).accentColor,
width: 24,
));
if (item["layout"] == "cart") {
icon = Stack(
children: <Widget>[
Container(
width: 30,
height: 25,
padding: const EdgeInsets.only(right: 6.0, top: 4),
child: icon,
),
if (totalCart > 0)
Positioned(
right: 0,
top: 0,
child: Container(
padding: const EdgeInsets.all(1),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(8),
),
constraints: BoxConstraints(
minWidth: 16,
minHeight: 16,
),
child: Text(
totalCart.toString(),
style: TextStyle(
color: Colors.white,
fontSize: isTablet ? 14 : 12,
),
textAlign: TextAlign.center,
),
),
)
],
);
}
if (item["label"] != null) {
list.add(Tab(icon: icon, text: item["label"]));
} else {
list.add(Tab(icon: icon));
}
});
return list;
}
}
这里是 BannerImageItem
/// The Banner type to display the image
class BannerImageItem extends StatefulWidget {
@override
final Key key;
final dynamic config;
final double width;
final double padding;
final BoxFit boxFit;
final double radius;
BannerImageItem({
this.key,
this.config,
this.padding,
this.width,
this.boxFit,
this.radius,
}) : super(key: key);
@override
_BannerImageItemState createState() => _BannerImageItemState();
}
class _BannerImageItemState extends State<BannerImageItem>
with AfterLayoutMixin {
List<Product> _products;
GlobalKey<MainTabsState> _scaffoldKey = GlobalKey<MainTabsState>();
@override
void afterFirstLayout(BuildContext context) {
/// for pre-load the list product
if (widget.config['data'] != null) {
print(widget.config['data']);
_products = widget.config['data'];
}
}
@override
Widget build(BuildContext context) {
double _padding =
Tools.formatDouble(widget.config["padding"] ?? widget.padding ?? 10.0);
double _radius = Tools.formatDouble(widget.config['radius'] ??
(widget.radius != null ? widget.radius : 0.0));
final screenSize = MediaQuery.of(context).size;
final screenWidth =
screenSize.width / (2 / (screenSize.height / screenSize.width));
final itemWidth = widget.width ?? screenWidth;
return GestureDetector(key: _scaffoldKey,
onTap: () { _scaffoldKey.currentState.tabController.animateTo(1);
},
child: Container(
width: itemWidth,
child: Padding(
padding: EdgeInsets.only(left: _padding, right: _padding),
child: ClipRRect(
borderRadius: BorderRadius.circular(_radius),
child: Tools.image(
fit: widget.boxFit ?? BoxFit.fitWidth,
url: widget.config["image"],
),
),
),
),
);
}
}
return GestureDetector(key: _scaffoldKey,
onTap: () { _scaffoldKey.currentState.tabController.animateTo(1);
},
child: Container(
width: itemWidth,
child: Padding(
padding: EdgeInsets.only(left: _padding, right: _padding),
child: ClipRRect(
borderRadius: BorderRadius.circular(_radius),
child: Tools.image(
fit: widget.boxFit ?? BoxFit.fitWidth,
url: widget.config["image"],
),
),
),
),
);
替换为
return GestureDetector(
onTap: () { MainTabControlDelegate.getInstance().tabAnimateTo(1);
},
child: Container(
width: itemWidth,
child: Padding(
padding: EdgeInsets.only(left: _padding, right: _padding),
child: ClipRRect(
borderRadius: BorderRadius.circular(_radius),
child: Tools.image(
fit: widget.boxFit ?? BoxFit.fitWidth,
url: widget.config["image"],
),
),
),
),
);