How to fix No TabController for TabBar - flutter

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),),),
)
]),
);
}
}

Related

TabBar with bottom sheet

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 ??

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

Trying to use ListView inside YoutubePlayerBuilder in flutter

I'm trying to basically have a youtube video on top, with a scrollable Listview below. Can't get the listview to be scrollable though. Here's the code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.blueAccent,
),
);
runApp(YoutubePlayerDemoApp());
}
class YoutubePlayerDemoApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Youtube Player Flutter',
theme: ThemeData(
primarySwatch: Colors.blue,
appBarTheme: const AppBarTheme(
color: Colors.blueAccent,
textTheme: TextTheme(
headline6: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w300,
fontSize: 20.0,
),
),
),
iconTheme: const IconThemeData(
color: Colors.blueAccent,
),
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
YoutubePlayerController _controller;
TextEditingController _idController;
TextEditingController _seekToController;
PlayerState _playerState;
YoutubeMetaData _videoMetaData;
double _volume = 100;
bool _muted = false;
bool _isPlayerReady = false;
final List<String> _ids = [
'srqZ5jsvXEc',
];
final testData = ["## Ingredients", "### 1 cup peanuts", "### Example2", "### Example 2", "### Example100", "## ", "## Method", "### This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text. This is a paragraph with long text.", "### Set aside to cool. Then serve."];
#override
void initState() {
super.initState();
_controller = YoutubePlayerController(
initialVideoId: _ids.first,
flags: const YoutubePlayerFlags(
mute: false,
autoPlay: false,
disableDragSeek: false,
loop: false,
isLive: false,
forceHD: false,
enableCaption: true,
),
)..addListener(listener);
_idController = TextEditingController();
_seekToController = TextEditingController();
_videoMetaData = const YoutubeMetaData();
_playerState = PlayerState.unknown;
}
void listener() {
if (_isPlayerReady && mounted && !_controller.value.isFullScreen) {
setState(() {
_playerState = _controller.value.playerState;
_videoMetaData = _controller.metadata;
});
}
}
#override
void deactivate() {
// Pauses video while navigating to next page.
_controller.pause();
super.deactivate();
}
#override
void dispose() {
_controller.dispose();
_idController.dispose();
_seekToController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
final _markDownData = testData.map((x) => "$x\n").reduce((x, y) => "$x$y");
return YoutubePlayerBuilder(
onExitFullScreen: () {
// The player forces portraitUp after exiting fullscreen. This overrides the behaviour.
SystemChrome.setPreferredOrientations(DeviceOrientation.values);
},
player: YoutubePlayer(
controller: _controller,
showVideoProgressIndicator: true,
progressIndicatorColor: Colors.blueAccent,
topActions: <Widget>[
const SizedBox(width: 8.0),
Expanded(
child: Text(
_controller.metadata.title,
style: const TextStyle(
color: Colors.white,
fontSize: 18.0,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
],
onReady: () {
_isPlayerReady = true;
},
onEnded: (data) {
_controller
.load(_ids[(_ids.indexOf(data.videoId) + 1) % _ids.length]);
},
),
builder: (context, player) => Scaffold(
key: _scaffoldKey,
appBar: AppBar(
leading: Padding(
padding: const EdgeInsets.only(left: 12.0),
child: Image.asset(
'assets/ypf.png',
fit: BoxFit.fitWidth,
),
),
title: const Text(
'Youtube Player Flutter',
style: TextStyle(color: Colors.white),
),
),
body: ListView(
children: [
player,
Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('Vegan Burritos',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30.0),
),
),
FlatButton(child: Icon(Icons.favorite_border, color: Colors.redAccent,), onPressed: () {
print('favourite button was pressed');
},),
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Icon(Icons.star),
Icon(Icons.star),
Icon(Icons.star),
Icon(Icons.star_half),
Icon(Icons.star_border),
SizedBox(width: 10.0,),
Text('Rate Recipe'),
],
),
),
Container(
height: 1000.0,
child: Markdown(data: _markDownData),
),
],
),
),
],
),
),
);
}
}
Any ideas? I figure its probably because i'm trying to do it inside the YoutubePlayerBuilder but not sure how else to do it. I tried wrapping the YoutubePlayerBuilder inside a listview, but it didn't work.
Thanks in advance,
Jason
SOLVED!!! I just had to change
Container(
height: 1000.0,
child: Markdown(data: _markDownData),
),
to:
Container(
height: 1000.0,
child: MarkdownBody(data: _markDownData),
),
Hope this helps someone in the future!

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

How to use TabController

I just learned flutter, I was confused how to use the TabController, I had followed what was described on the official website, but an error appeared, and I don't know how to fix it.
I just want to change the title and leading from the appbar when changing tabs.
final List<ChangeTitleAndLeading> _data = [
new ChangeTitleAndLeading(title: "Home", leading: Icon(Icons.home)),
new ChangeTitleAndLeading(title: "Profile", leading: Icon(Icons.person)),
new ChangeTitleAndLeading(title: "Friends", leading: Icon(Icons.people))
];
ChangeTitleAndLeading _handler;
TabController _controller;
#override
void initState() {
super.initState();
_checkEmailVerification();
_controller = TabController(vsync: this, length: 3);
_handler = _data[0];
_controller.addListener(_handleSelected);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
void _handleSelected() {
setState(() {
_handler = _data[_controller.index];
});
}
return MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.teal,
),
home: new Scaffold(
appBar: new AppBar(
leading: Icon(Icons.home),
title: new Text("Home"),
bottom: new TabBar(
controller: _controller,
tabs: _tabs,
),
),
body: TabBarView(
controller: _controller,
children: _pages,
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
print('Current Index: ${_handler.title}');
}
),
class ChangeTitleAndLeading {
final String title;
final Widget leading;
ChangeTitleAndLeading({
#required this.title,
#required this.leading
}) :
assert(title != null),
assert(leading != null);
}
Error log:
Error Log:
I/flutter (19638): No TabController for TabBarView.
I/flutter (19638): When creating a TabBarView, you must either provide an explicit TabController using the "controller"
I/flutter (19638): property or you must ensure that there is a DefaultTabController above the TabBarView.
I/flutter (19638): In this case, there was neither an explicit controller nor a default controller.
════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (19638): Another exception was thrown: No TabController for TabBar.
And when i change this:
leading: Icon(Icons.home), to leading: _handler.leading,
and this:
title: new Text("Home"), to title: new Text(_handler.title),
always return error _handler.leading or _handler.title was null
Image
Try this solution :-
don't forget to inhert
TickerProviderStateMixin
class HomePage extends StatefulWidget {
const HomePage();
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
late TabController tabController;
#override
void initState() {
super.initState();
tabController = TabController(
initialIndex: 0,
length: 2,
vsync: this,
);
}
#override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Scaffold(
appBar: AppBar(
title: Row(
children: [
Image.asset(
'assets/images/png/logo.png',
height: 60,
width: 60,
),
Spacer(),
Container(
width: 400,
child: TabBar(
labelColor: Color.fromRGBO(4, 2, 46, 1),
labelStyle: theme.textTheme.headline1,
indicatorColor: Color.fromRGBO(4, 2, 46, 1),
unselectedLabelColor: Colors.grey,
controller: tabController,
tabs: [
Text('الفاتورة'),
Text('دليفري'),
],
),
),
],
),
),
body: Container(
child: TabBarView(
controller: tabController,
children: [
Container(
color: Colors.red,
),
Container(
color: Colors.orange,
),
],
),
),
);
}
#override
void dispose() {
tabController.dispose();
super.dispose();
}
}
The issue is that you are missing a tabbarcontroller
Your code should be:
return MaterialApp(
theme: new ThemeData(
primarySwatch: Colors.teal,
),
home: DefaultTabController(
length: 3,
child: new Scaffold(
appBar: new AppBar(
leading: Icon(Icons.home),
title: new Text("Home"),
bottom: new TabBar(
controller: _controller,
tabs: _tabs,
),
),
body: TabBarView(
controller: _controller,
children: _pages,
)...