TabBar with bottom sheet - flutter

I am making Flutter app i which I want to design bottom sheet with TabBar view as below design.
I have seen option for bottom sheet in Scafold() but onlz tabs are visible. I dont know how to animate it as the above.
My code so far is as below
class MainScreen extends StatefulWidget {
static final String id = 'MainScreen';
const MainScreen({Key? key}) : super(key: key);
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> with SingleTickerProviderStateMixin {
TabController? _tabController;
bool isNull = false;
#override
void initState() {
super.initState();
_tabController = TabController(length: 4, vsync: this, initialIndex: 2);
_tabController!.addListener(_tabChanged);
}
void _tabChanged() {
if (_tabController!.indexIsChanging) {
print('tabChanged: ${_tabController!.index}');
}
}
#override
void dispose() {
_tabController!.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: TabBarView(
controller: _tabController,
children: [
HomePage(),
PersonalData(),
LoginPage(),
RegistrationPage()
],
)
),
bottomSheet: SafeArea(
child: TabBar(
controller: _tabController,
labelColor: color,
indicatorColor: Colors.black,
unselectedLabelColor: Colors.black,
tabs: [
const Tab(
icon: Icon(
Icons.home_outlined,
//color: Colors.white,
),
),
const Tab(
icon: Icon(
Icons.shopping_cart_outlined,
//color: Colors.white,
),
),
const Tab(
icon: Icon(
Icons.favorite_border,
//color: Colors.white,
),
),
const Tab(
icon: Icon(
Icons.send,
//color: Colors.white,
),
)
],
)
),
);
}
}
AnyOne has some idea how to do it?? If there is some package to use for this bottom sheet behaviour ??

Related

How to fix No TabController for TabBar

I'm new in flutter and I'm trying to make a TabBar view like in the figure. But it shows "No TabController for TabBar" and When creating a TabBarView, you must either provide an explicit TabController using the "controller" property, or you must ensure that there is a DefaultTabController above the TabBarView.
In this case, there was neither an explicit controller nor a default controller.
I have tried a suggestion that mentioned in the internet but still got error. Can anyone help me how to fix it?? Thank you
class _TransactionState extends State<Transaction> with SingleTickerProviderStateMixin {
int _value = 1;
TabController controller;
#override
void initState() {
controller = new TabController(vsync: this, length: 2);
super.initState();
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Transaction'),
actions: <Widget>[
DropdownButton(
dropdownColor: primary,
value: _value,
items: [
DropdownMenuItem(
child: Text(
"Daily",
style: TextStyle(color: Colors.white,
fontWeight: FontWeight.bold,
),
),
value: 1,
),
DropdownMenuItem(
child: Text("Monthly",
style: TextStyle(color: Colors.white,
fontWeight: FontWeight.bold,
),),
value: 2,
),
DropdownMenuItem(
child: Text("Yearly",
style: TextStyle(color: Colors.white,
fontWeight: FontWeight.bold,
),),
value: 3,
),
],
onChanged: (int value){
setState(() {
_value = value;
});
//Padding(padding: EdgeInsets.all(20.0));
style: new TextStyle(
color: Colors.white,
);
},
),
],
automaticallyImplyLeading: false,
backgroundColor: secondary,
bottom: new TabBar(
controller: controller,
tabs: <Widget>[
new Tab(icon: new Icon(Icons.add_shopping_cart),text: "Expense",),
new Tab(icon: new Icon(Icons.attach_money),text: "Income",),
],
),
),
body: TabBarView(
controller: controller,
children: <Widget>[
new expense.TransactionExpense(),
new income.TransactionIncome(),
],
),
);
}
}
This should solve it.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MyAppState()
);
}
}
class MyAppState extends StatefulWidget{
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyAppState> with TickerProviderStateMixin {
TabController _controller;
final List<Tab> topTabs = <Tab>[
new Tab(text: 'Profile'),
new Tab(text: 'Match'),
new Tab(text: 'Chat'),
];
#override
void initState() {
super.initState();
_controller = TabController(vsync: this, length: 3);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('MyApp'),
bottom: TabBar(
controller: _controller,
tabs: topTabs,
),
),
body: TabBarView(
controller: _controller,
children: [
new Container(
color: Colors.lightBlueAccent,
child: Center(child: Text('Profile', style: TextStyle(color: Colors.white),),),
),
new Container(
color: Colors.purpleAccent,
child: Center(child: Text('Match', style: TextStyle(color: Colors.white),),),
),
new Container(
color: Colors.lightGreenAccent,
child: Center(child: Text('Chat', style: TextStyle(color: Colors.white),),),
)
]),
);
}
}

Problem with BottomNavigationTab in Flutter - refreshing widgets other than the selected tab

i have some problems when i coded basic layout namely, I found that when I choose a card two indexes away, a notification is displayed in the console, which in each of the tabs in the function at the start of a given widget, I wrote, instead of refreshing one tab, the selected one, it refreshes the neighboring one and finally the target one. I will post photos with the code below and let me know what's wrong! :)
class HomePage extends StatefulWidget {
HomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_HomeScreen createState() => _HomeScreen();
}
class _HomeScreen extends State<HomePage> with TickerProviderStateMixin {
TabController controllerInMain;
#override
void initState() {
super.initState();
controllerInMain = TabController(length: 5, vsync: this, initialIndex: 2);
controllerInMain.addListener(() {
_handleTabSelection();
});
}
void _handleTabSelection() {
setState(() {});
}
#override
void dispose() {
controllerInMain.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Managly",
style: TextStyle(color: Colors.black),
),
),
resizeToAvoidBottomPadding: false,
body: SafeArea(
child: TabBarView(
children: <Widget>[
MenuTab(),
OrdersTab(),
StatisticsTab(),
EmployeeTab(),
TableTab(),
],
controller: controllerInMain,
),
),
bottomNavigationBar: TabBar(
controller: controllerInMain,
indicatorColor: Theme.of(context).primaryColor,
tabs: <Tab>[
Tab(
icon: Icon(
Icons.restaurant_menu,
color: Colors.amber,
),
),
Tab(
icon: Icon(
Icons.receipt_long,
color: Colors.amber,
),
),
Tab(
icon: Icon(
Icons.insights,
color: Colors.amber,
),
),
Tab(
icon: Icon(
Icons.group,
color: Colors.amber,
),
),
Tab(
icon: Icon(
Icons.weekend,
color: Colors.amber,
),
),
],
),
);
}
}
Panel UI
Console output

Flutter, setting screens with multiple stacks

I am using the method of creating multiple stacks with the bottom navigation bar outline at the article here.
It all works well but as there are a few techniques I'm not aware of in the method I'm struggling to find a way to navigate in my app.
I'm just trying to create a screen for profile which has a button that takes you back to feed. As there are some fancy things done in the tab_navigator I'm not sure how to do this. Can anyone help?
The tab navigator code is below.
import 'package:flutter/material.dart';
import 'package:highline_app/bottom_navigation.dart';
import 'package:highline_app/color_detail_page.dart';
import 'package:highline_app/colors_list_page.dart';
import 'package:highline_app/pages/feed.dart';
class TabNavigatorRoutes {
static const String root = '/';
static const String detail = '/detail';
static const String feed = '/feed';
static const String profile = '/profile';
}
class TabNavigator extends StatelessWidget {
TabNavigator({this.navigatorKey, this.tabItem});
final GlobalKey<NavigatorState> navigatorKey;
final TabItem tabItem;
void _push(BuildContext context, {int materialIndex: 500}) {
var routeBuilders = _routeBuilders(context, materialIndex: materialIndex);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => routeBuilders[TabNavigatorRoutes.detail](context),
),
);
}
Map<String, WidgetBuilder> _routeBuilders(BuildContext context,
{int materialIndex: 500}) {
return {
TabNavigatorRoutes.feed: (context) => NewsFeed(),
TabNavigatorRoutes.root: (context) => ColorsListPage(
color: activeTabColor[tabItem],
title: tabName[tabItem],
onPush: (materialIndex) =>
_push(context, materialIndex: materialIndex),
),
TabNavigatorRoutes.detail: (context) => ColorDetailPage(
color: activeTabColor[tabItem],
title: tabName[tabItem],
materialIndex: materialIndex,
),
};
}
#override
Widget build(BuildContext context) {
final routeBuilders = _routeBuilders(context);
return Navigator(
key: navigatorKey,
initialRoute: TabNavigatorRoutes.root,
onGenerateRoute: (routeSettings) {
return MaterialPageRoute(
builder: (context) => routeBuilders[routeSettings.name](context),
);
},
);
}
}
Actually, you don't need to use Navigator. I advise you keep it simple. You can do this with TabController. You can check following code to navigate between Pages or Tabs whatever you need.
import 'package:flutter/material.dart';
void main() => runApp(TabLayoutDemo());
class TabLayoutDemo extends StatefulWidget {
#override
_TabLayoutDemoState createState() => _TabLayoutDemoState();
}
class _TabLayoutDemoState extends State<TabLayoutDemo>
with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 4);
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
color: Colors.yellow,
home: DefaultTabController(
length: 4,
child: Scaffold(
body: TabBarView(
controller: _tabController,
children: [
Container(
color: Colors.yellow,
),
Container(
color: Colors.orange,
),
// Feed Page.
Container(
color: Colors.lightGreen,
),
// Profile Page.
Container(
color: Colors.red,
child: Padding(
padding: EdgeInsets.only(top: 15.0),
child: SizedBox(
width: double.infinity,
child: RaisedButton.icon(
icon: Icon(Icons.arrow_back),
textColor: Colors.white,
color: Colors.lightBlue,
label: Text('Go To Feed Tab'),
onPressed: () {
setState(() {
_tabController.index = 2;
});
},
)),
),
),
],
),
bottomNavigationBar: TabBar(
controller: _tabController,
tabs: [
Tab(
icon: Icon(Icons.home),
),
Tab(
icon: Icon(Icons.settings),
),
// Here is feed tab button.
Tab(
icon: Icon(Icons.rss_feed),
),
// Here is profile tab button.
Tab(
icon: Icon(Icons.perm_identity),
),
],
labelColor: Colors.yellow,
unselectedLabelColor: Colors.blue,
indicatorSize: TabBarIndicatorSize.label,
indicatorPadding: EdgeInsets.all(5.0),
indicatorColor: Colors.red,
),
backgroundColor: Colors.black,
),
),
);
}
}

How to make a webview scrollable in tabbarwiew in Flutter

I've spent almost two days trying to figure out how to make a webview scrollable in a tabbarview in Flutter. I understand that the TabBarWiew Widget should be wrapped in a fixed height widget, what can be a workaround for this?
I don't know if it can help but my minSdkVersion is 16 and targetSdkVersion is 28,
And this is the output of flutter --version command
Flutter 1.12.13+hotfix.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 27321ebbad (10 weeks ago) • 2019-12-10 18:15:01 -0800
Engine • revision 2994f7e1e6
Tools • Dart 2.7.0
Below is the code for the page I'm building.
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Pays'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
double screenHeight = MediaQuery.of(context).size.height;
final List<Tab> myTabs = <Tab>[
Tab(text: 'LEFT'),
Tab(text: 'RIGHT'),
];
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: myTabs.length);
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
backgroundColor: Colors.red[800],
),
body: Container(
color: Colors.grey[100],
child: ListView(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Image.network(
'https://lh3.googleusercontent.com/proxy/dThF-49TD0synkY_v1F0mh2HQFp_P5bxYvdLI1msK-aD7h4CtzctJpJP3Cm89LyAWAg21xqvUDdQjdRi2yDH4iEU1wr_LT3BO8iOmx141QOtzXPgUpXW7ulAlHUtAJ4Z0yea_Qr4sWZfApns3VuAbxNcTNISWdStSoJEZ9-OmRypu-3YTQ',
height: 150,
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter,
filterQuality: FilterQuality.high,
)),
],
),
SizedBox(
height: 1,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('237',
style: TextStyle(
color: Colors.black,
fontSize: 35,
fontWeight: FontWeight.bold)),
SizedBox(
width: 5,
),
Image.network(
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQJrM_W9cpz33KFyqL_L-meeCuH_Kyufoohxjlh06XdBnIbel0j&s',
height: 30,
),
Spacer(),
Image.network(
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTwnqIeW1RJHtAhRE7ccZ-4s4ymEh5zHRYAdidO7p9GfDnOwziY&s',
height: 50,
)
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
'Cameroun',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontSize: 25,
fontWeight: FontWeight.bold),
)
]),
),
SizedBox(height: 5),
NestedTabBar()
],
)),
// This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class NestedTabBar extends StatefulWidget {
#override
_NestedTabBarState createState() => _NestedTabBarState();
}
class _NestedTabBarState extends State<NestedTabBar>
with TickerProviderStateMixin {
TabController _nestedTabController;
ScrollController _scrollController;
#override
void initState() {
//_scrollController = ScrollController();
super.initState();
_nestedTabController = new TabController(length: 2, vsync: this);
//_nestedTabController.addListener(_handleTabSelection);
}
#override
void dispose() {
_nestedTabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
return Column(
children: <Widget>[
TabBar(
controller: _nestedTabController,
indicatorColor: Colors.teal,
labelColor: Colors.teal,
unselectedLabelColor: Colors.black54,
isScrollable: true,
tabs: <Widget>[
Tab(
text: "A propos & Statistiques",
),
Tab(
text: "Wiki",
)
],
),
Container(
height: screenHeight * 0.9,
margin: EdgeInsets.only(left: 8.0, right: 8.0),
child: TabBarView(
controller: _nestedTabController,
children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
child: Text('Simple text')),
/*GestureDetector(
child: MyWebView(selectedUrl: 'https://fr.wikipedia.org/wiki/Lewis_Hamilton'),
),*/
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
child: MyWebView(
selectedUrl: 'https://fr.wikipedia.org/wiki/Cameroun'),
),
],
),
),
// MyWebView(selectedUrl: 'https://fr.wikipedia.org/wiki/Lewis_Hamilton')
],
);
}
}
class MyWebView extends StatefulWidget {
final String selectedUrl;
MyWebView({
#required this.selectedUrl,
});
#override
_MyWebViewState createState() => _MyWebViewState();
}
class _MyWebViewState extends State<MyWebView> {
Completer<WebViewController> _controller;
#override
void initState() {
super.initState();
_controller = Completer<WebViewController>();
}
#override
void dispose() {
super.dispose();
_controller = null;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: WebView(
initialUrl: widget.selectedUrl,
gestureRecognizers: Set()
..add(Factory<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer())),
gestureNavigationEnabled: true,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
));
}
}
You can copy paste run full code below
You can use package https://pub.dev/packages/flutter_inappwebview
Step 1: change Android minSdkVersion to 17
Step 2: reference package with the following , because this issue. https://github.com/pichillilorenzo/flutter_inappwebview/issues/220
flutter_inappwebview:
git:
url: https://github.com/pichillilorenzo/flutter_inappwebview.git
ref: master
Step 3: code snippet
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
child: InAppWebView(
initialUrl: "https://fr.wikipedia.org/wiki/Lewis_Hamilton",
initialHeaders: {},
working demo
full code
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Pays'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
#override
Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
final List<Tab> myTabs = <Tab>[
Tab(text: 'LEFT'),
Tab(text: 'RIGHT'),
];
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: myTabs.length);
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
backgroundColor: Colors.red[800],
),
body: Container(
color: Colors.grey[100],
child: ListView(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Image.network(
'https://lh3.googleusercontent.com/proxy/dThF-49TD0synkY_v1F0mh2HQFp_P5bxYvdLI1msK-aD7h4CtzctJpJP3Cm89LyAWAg21xqvUDdQjdRi2yDH4iEU1wr_LT3BO8iOmx141QOtzXPgUpXW7ulAlHUtAJ4Z0yea_Qr4sWZfApns3VuAbxNcTNISWdStSoJEZ9-OmRypu-3YTQ',
height: 150,
fit: BoxFit.fitWidth,
alignment: Alignment.topCenter,
filterQuality: FilterQuality.high,
)),
],
),
SizedBox(
height: 1,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Text('237',
style: TextStyle(
color: Colors.black,
fontSize: 35,
fontWeight: FontWeight.bold)),
SizedBox(
width: 5,
),
Image.network(
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQJrM_W9cpz33KFyqL_L-meeCuH_Kyufoohxjlh06XdBnIbel0j&s',
height: 30,
),
Spacer(),
Image.network(
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTwnqIeW1RJHtAhRE7ccZ-4s4ymEh5zHRYAdidO7p9GfDnOwziY&s',
height: 50,
)
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text(
'Cameroun',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontSize: 25,
fontWeight: FontWeight.bold),
)
]),
),
SizedBox(height: 5),
NestedTabBar()
],
)),
// This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class NestedTabBar extends StatefulWidget {
#override
_NestedTabBarState createState() => _NestedTabBarState();
}
class _NestedTabBarState extends State<NestedTabBar>
with TickerProviderStateMixin {
TabController _nestedTabController;
ScrollController _scrollController;
InAppWebViewController webView;
String url = "";
double progress = 0;
#override
void initState() {
//_scrollController = ScrollController();
super.initState();
_nestedTabController = new TabController(length: 2, vsync: this);
//_nestedTabController.addListener(_handleTabSelection);
}
#override
void dispose() {
_nestedTabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
double screenHeight = MediaQuery.of(context).size.height;
return Column(
children: <Widget>[
TabBar(
controller: _nestedTabController,
indicatorColor: Colors.teal,
labelColor: Colors.teal,
unselectedLabelColor: Colors.black54,
isScrollable: true,
tabs: <Widget>[
Tab(
text: "A propos & Statistiques",
),
Tab(
text: "Wiki",
)
],
),
Container(
height: screenHeight * 0.9,
margin: EdgeInsets.only(left: 8.0, right: 8.0),
child: TabBarView(
controller: _nestedTabController,
children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
child: Text('Simple text')),
/*GestureDetector(
child: MyWebView(selectedUrl: 'https://fr.wikipedia.org/wiki/Lewis_Hamilton'),
),*/
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
),
child: InAppWebView(
initialUrl: "https://fr.wikipedia.org/wiki/Lewis_Hamilton",
initialHeaders: {},
initialOptions: InAppWebViewWidgetOptions(
crossPlatform: InAppWebViewOptions(
debuggingEnabled: true,
)
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (InAppWebViewController controller, String url) {
setState(() {
this.url = url;
});
},
onLoadStop: (InAppWebViewController controller, String url) async {
setState(() {
this.url = url;
});
},
onProgressChanged: (InAppWebViewController controller, int progress) {
setState(() {
this.progress = progress / 100;
});
},
),
),
],
),
),
// MyWebView(selectedUrl: 'https://fr.wikipedia.org/wiki/Lewis_Hamilton')
],
);
}
}
Add gestureRecognizers as a WebView parameter:
WebView(
gestureRecognizers: {
Factory<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer()
)
},
initialUrl: widget.url,
);
As mentioned here: https://github.com/flutter/flutter/issues/33565

Flutter - Change the animation of TabBarView

I implemented a basic TabBar and TabBarView with a DefaultTabController, see code below.
class MyApp2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: BOTTOM_TABS,
child: Scaffold(
appBar: AppBar(title: const Text('Bottom App Bar')),
body: _tabBarView(),
bottomNavigationBar: _bottomTabBar(),
),
);
}
_tabBarView() {
return TabBarView(
physics: NeverScrollableScrollPhysics(),
children: [
Container(
color: Colors.blue,
),
Container(
color: Colors.orange,
),
Container(
color: Colors.lightGreen,
),
Container(
color: Colors.red,
),
],
);
}
_bottomTabBar() {
return TabBar(
tabs: [
Tab(
icon: new Icon(Icons.home),
),
Tab(
icon: new Icon(Icons.public),
),
Tab(
icon: new Icon(Icons.group),
),
Tab(
icon: new Icon(Icons.person),
)
],
);
}
}
Works great! Now what I want to do is change the animation between the two tabs from the default animation. But I can't find an easy way to do that.
After a bit of research it seems like I need to use a custom TabController and somehow use its animateTo method. To me that seems like a pretty big change just to change the animation. What I wonder is if that is the correct way or if I am missing some easier way to just change the default animation between the tabviews?
If someone could give me some good resources to point me in the right direction I'd greatly appreciate it.
This is not hard, just use TabController (to do so you need to use SingleTickerProviderStateMixin ) and AnimatedBuilder.
class MyApp2 extends StatefulWidget {
#override
_MyApp2State createState() => _MyApp2State();
}
class _MyApp2State extends State<MyApp2> with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
_tabController = TabController(length: 4, vsync: this);
super.initState();
}
_tabBarView() {
return AnimatedBuilder(
animation: _tabController.animation,
builder: (BuildContext context, snapshot) {
return Transform.rotate(
angle: _tabController.animation.value * pi,
child: [
Container(
color: Colors.blue,
),
Container(
color: Colors.orange,
),
Container(
color: Colors.lightGreen,
),
Container(
color: Colors.red,
),
][_tabController.animation.value.round()],
);
},
);
}
_bottomTabBar() {
return TabBar(
controller: _tabController,
labelColor: Colors.black,
tabs: [
Tab(
icon: new Icon(Icons.home),
),
Tab(
icon: new Icon(Icons.public),
),
Tab(
icon: new Icon(Icons.group),
),
Tab(
icon: new Icon(Icons.person),
)
],
);
}
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(title: const Text('Bottom App Bar')),
body: _tabBarView(),
bottomNavigationBar: _bottomTabBar(),
),
);
}
}
Screenshot (Null safe):
Code:
If you want fine-grained control, you can make use of the AnimationController.
class _MyPageState extends State<MyPage> with TickerProviderStateMixin {
late final TabController _tabController;
late final AnimationController _controller;
#override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 400),
value: 1,
);
_tabController = TabController(
length: 3,
vsync: this,
)..addListener(() {
if (_tabController.indexIsChanging) {
setState(() => _controller.forward(from: 0.5));
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ScaleTransition(
scale: _controller,
child: [
Container(color: Colors.red),
Container(color: Colors.green),
Container(color: Colors.blue),
][_tabController.index],
),
bottomNavigationBar: TabBar(
controller: _tabController,
tabs: [
Tab(child: Text('Red')),
Tab(child: Text('Green')),
Tab(child: Text('Blue')),
],
),
);
}
}
I don't know if you want to completely change the animation.
But if you just need some customization, did you try to use a TabController instead of a DefaultTabController ?
You just need to pass the tabController as an arg to the TabBar & TabBarView.
To customize the animation with the tabController, you should specify an Animation for the tabController and also specify the curve and duration with the animateTo function of the tabController.
https://api.flutter.dev/flutter/material/TabController/animateTo.html
https://api.flutter.dev/flutter/material/TabController-class.html
Disable animation between flutter tabs by setting animation duration to zero like this
tabController = TabController(
animationDuration: Duration.zero,
length: 4, vsync: this, initialIndex: 0);
Thank me later.