How can I pass a buttonClick to a Function on another Page? - function

I'm trying to pass a simple buttonpress to performe something in another class. The point is to use one page for several different functions, instead of having one page for every function.
Right now the navigation to the textDeclaration-page works fine, but I can't get the right function do do its job.
If I press the First Button, the info from FirstButton Widget should display on the textDeclaration page, and if I press the Second Button, the info from SecondButton Widget should pop up on the displayText-page.
Main:
import 'package:flutter/material.dart';
import 'homePage.dart';
void main()=>runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
HomePage:
import 'package:flutter/material.dart';
import 'textDeclaration.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Function buttonChoice;
Widget outlineButton(String buttonName) {
return SizedBox(
height: 60.0,
width: 225.0,
child: OutlineButton(
highlightedBorderColor: Colors.lightBlueAccent,
child: Text(buttonName,
style: TextStyle(fontSize: 17.0, fontWeight:
FontWeight.bold)),
borderSide: BorderSide(
color: Colors.blue,
width: 2.0,
),
onPressed: () {
navigate(buttonName, buttonChoice);
}),
);
}
void navigate(String buttonName, Function buttonChoice) {
setState(() {
Navigator.of(context).popUntil(ModalRoute.withName('/'));
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => TextDeclaration(
buttonName: buttonName,
buttonChoice: buttonChoice,
)));
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('HOME PAGE')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
outlineButton('First Button'),
outlineButton('Second Button'),
],
),
),
);
}
}
textDeclarationPage:
import 'package:flutter/material.dart';
class TextDeclaration extends StatefulWidget {
final String buttonName;
final Function buttonChoice;
TextDeclaration({this.buttonName, this.buttonChoice});
#override
_TextDeclarationState createState() => _TextDeclarationState();
}
class _TextDeclarationState extends State<TextDeclaration> {
String buttonName = "";
buttonChoice(String buttonName) {
if (buttonName == 'First Button') {
firstButton(buttonName);
} else if (buttonName == 'Second Button') {
secondButton(buttonName);
}
}
Widget firstButton(buttonName) {
return Scaffold(
appBar: AppBar(
title: Text('First Button'),
),
body: Center(
child: Container(
height: 200.0,
width: 200.0,
child: Center(child: Text('First Button Text')),
),
),
);
}
Widget secondButton(buttonName) {
return Scaffold(
appBar: AppBar(
title: Text('Second Button'),
),
body: Center(
child: SizedBox(
height: 200.0,
width: 200.0,
child: Center(
child: Text('Second Button Text'),
),
),
),
);
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.blue),
child: buttonChoice(buttonName),
);
}
}
The code runs, but the functions from the different buttons won't work.
Any help at all would be great since I've been stuck with this for a very long time now. Thanks.

Related

How to send json data from on route to another route

In my Flutter application, I am trying to pass JSON data from one route to another. The challenge I am facing is how to pass a list as a parameter. The first screen contains a list of JSON data that has been fetched, and I aim to show the complete details of each item when the user clicks on the respective ListTile.
you will find the onTap() in JsonParsingPodo.dart
here's my code :
posts.dart (plain old dart object file)
class PostList {
final List<Post> posts;
PostList({required this.posts});
factory PostList.fromJson(Map<String, dynamic> parsedJson) {
List<dynamic> postsJson = parsedJson['posts'] as List;
List<Post> posts = <Post>[];
posts = postsJson.map((e) => Post.fromJson(e)).toList();
return PostList(posts: posts);
}
}
class Post {
int userId;
int id;
String title;
String body;
Post(
{required this.id,
required this.body,
required this.title,
required this.userId});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
id: json['id'],
body: json['body'],
title: json['title'],
userId: json['userId']);
}
}
JsonParsingPodo.dart (First Screen)
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:podo_practice/posts.dart';
import 'display.dart';
class JsonParsingPodo extends StatefulWidget {
const JsonParsingPodo({super.key});
#override
State<JsonParsingPodo> createState() => _JsonParsingPodoState();
}
class _JsonParsingPodoState extends State<JsonParsingPodo> {
late Future<PostList> data;
#override
void initState() {
super.initState();
Network network = Network("https://dummyjson.com/posts");
data = network.loadPost();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("PODO: json"),
),
body: Center(
// ignore: avoid_unnecessary_containers
child: Container(
child: FutureBuilder(
future: data,
builder: (context, AsyncSnapshot<PostList> snapshot) {
List<Post> allposts;
if (snapshot.hasData) {
allposts = snapshot.data!.posts;
return createListView(allposts, context);
}
return const CircularProgressIndicator();
}),
),
));
}
Widget createListView(List<Post> data, BuildContext context) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, int index) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Divider(
height: 5.0,
),
ListTile(
title: Text("${data[index].title}"),
subtitle: Text("${data[index].body}"),
leading: Column(
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.green,
radius: 23,
child: Text("${data[index].id}"),
),
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DisplayData()),
// *what to pass here??*
);
},
),
],
);
});
}
}
class Network {
final String url;
Network(this.url);
Future<PostList> loadPost() async {
final response = await get(Uri.parse(Uri.encodeFull(url)));
if (response.statusCode == 200) {
//ok
return PostList.fromJson(json.decode(response.body));
} else {
throw Exception("Failed to load data. ");
}
}
}
DisplayData.dart (Second Screen)
import 'package:flutter/material.dart';
import 'package:podo_practice/posts.dart';
class DisplayData extends StatefulWidget {
const DisplayData({super.key});
#override
State<DisplayData> createState() => _DisplayDataState();
}
class _DisplayDataState extends State<DisplayData> {
late Future<PostList> data;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("Display Post"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: Column(
children: [
// Text(data);
],
),
),
),
);
}
}
I have recently started learning Flutter and don't have much knowledge. I tried reading articles on Stack Overflow about this thing, but I didn't understand much. So, I have decided to post a question for help. Please assist me in completing the following code.
On the "Display Data" page, I need to display the **title **and its **description **when the user clicks on the ListItem.
onListile tap send particular object using index
Widget createListView(List<Post> data, BuildContext context) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, int index) {
Post post = data[index]
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Divider(
height: 5.0,
),
ListTile(
title: Text("${data[index].title}"),
subtitle: Text("${data[index].body}"),
leading: Column(
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.green,
radius: 23,
child: Text("${data[index].id}"),
),
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DisplayData(post:post)),
// *what to pass here??*
);
},
),
],
);
});
}
}
get post on constructor to display
import 'package:flutter/material.dart';
import 'package:podo_practice/posts.dart';
class DisplayData extends StatefulWidget {
final Post post;
const DisplayData({super.key,required this.post});
#override
State<DisplayData> createState() => _DisplayDataState();
}
class _DisplayDataState extends State<DisplayData> {
late Future<PostList> data;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("Display Post"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: Column(
children: [
// Text(data);
],
),
),
),
);
}
}

how to get a data from HtmlElementView in flutter-web

i am having a trouble with adding webview in side flutter web
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'dart:ui' as ui;
import 'dart:html' as html;
class UserAddress3 extends StatefulWidget {
const UserAddress3({Key? key}) : super(key: key);
#override
State<UserAddress3> createState() => _UserAddress3State();
}
class _UserAddress3State extends State<UserAddress3> {
#override
void initState() {
// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(
'html.iframeElement',
(int viewId) => html.IFrameElement()
..src = 'https://daum_postcode_mobile'
..style.width = '100%'
..style.height = '100%'
..style.border = 'none');
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('주소 검색'),
backgroundColor: Colors.white,
),
body: Container(
child: HtmlElementView(
viewType: 'html.iframeElement',
),
),
);
}
}
'https://daum_postcode_mobile' this link leads to where we can find a address
so the web-view displays fine but i can't have a datas if I click the address
I thought it would work as same as how Webview worked in Flutter App but it seems totaly different...
Is there any one knows how to get datas from HtmleElementView???
p.s and this is my codes which used in my app
class KakaoAddress extends StatefulWidget {
#override
_KakaoAddressState createState() => _KakaoAddressState();
}
class _KakaoAddressState extends State<KakaoAddress> {
final Completer<WebViewController> _controller = Completer<WebViewController>();
#override
Widget build(context) {
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(
color: Colors.black,
),
titleSpacing: 0.0,
elevation: 0.0,
title: const Text(
'주소 검색',
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w700, color: Colors.black),
),
actions: <Widget>[
SampleMenu(),
],
backgroundColor: Colors.white,
),
body: Builder(builder: (context) {
return WebView(
initialUrl: 'https://daum_postcode_mobile',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
// ignore: prefer_collection_literals
javascriptChannels: <JavascriptChannel>[
_toasterJavascriptChannel(context),
].toSet(),
);
}),
);
}
JavascriptChannel _toasterJavascriptChannel(context) {
return JavascriptChannel(
name: 'Daum',
onMessageReceived: (JavascriptMessage message) async {
final myJsonAsString = message.message;
dynamic received = json.decode(myJsonAsString);
dynamic address = received["address"];
Navigator.pop(context, address);
});
}
}
class SampleMenu extends StatelessWidget {
#override
Widget build(context) {
return FutureBuilder<WebViewController>(
builder: (context, AsyncSnapshot<WebViewController> controller) {
return IconButton(
icon: Icon(
Icons.close,
size: 25.0,
),
onPressed: () {
Navigator.pop(context);
});
},
);
}
}
I made something similar, which may help you. I handled mouse clicks performed inside HtmlElementView, with Dart code, the following way:
In the code passed to ui.platformViewRegistry.registerViewFactory() I used DOM manipulation to attach a listener to the onClick event of an element.
You can do the same with a custom event and trigger that event anytime from Javascript to call and pass data to the Dart side.

Web scraper using dart

I am trying to create a web scraper for a single website picking out just a title, Image and link to the website.
The title comes out fine but the image and link are not properly working can anyone please help me out in this.Here is my code and dependencies I used in .yaml
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart' as parser;
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> title;
List<String> image;
List<String> link;
#override
void initState() {
_getdataFromWeb();
}
void _getdataFromWeb() async {
final response = await http.get('https://www.bewakoof.com/men-shirts');
dom.Document document = parser.parse(response.body);
final pictures = document.getElementsByClassName('productGrid');
final description = document.getElementsByClassName('productCardDetail');
final nextPage =
//document.getElementsByClassName('entry-title');
document.getElementsByClassName('col-sm-4 col-xs-6');
image = pictures
.map((element) =>
element.getElementsByTagName("img")[0].attributes['src'])
.toList();
title = description
.map((element) => element.getElementsByTagName("h3")[0].innerHtml)
.toList();
link = nextPage
.map((element) => element.getElementsByTagName("a")[0].attributes['href'])
.toList();
print(link);
}
#override
Widget build(BuildContext context) {
print("hello");
if (image == null)
print("null");
else
print(image);
return SafeArea(
child: Scaffold(
backgroundColor: Colors.black87,
body: title == null || title.length == 0
? Text(
"No data",
style: TextStyle(
color: Colors.white,
),
)
: ListView.builder(
itemCount: title.length,
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 375),
child: SlideAnimation(
child: FadeInAnimation(
child: GestureDetector(
onTap: () async {
dynamic url = link[index];
if (await canLaunch(url))
launch(url);
else {
print('error');
}
},
child: Padding(
padding: const EdgeInsets.all(10),
child: Card(
child: Container(
color: Colors.black87,
child: Column(
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: Text(
title[index],
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.cyan,
fontSize: 20,
),
),
),
SizedBox(height: 15),
Image.network(image[0]),
],
),
),
),
),
),
),
),
);
},
),
),
);
}
}
cupertino_icons: ^1.0.1
http: ^0.12.0+4
html: ^0.14.0+3
flutter_staggered_animations: "^0.1.2"
url_launcher: ^5.4.0
I may need it tomorrow if it can be possible
enter image description here
Here I added the html pic for the elements rest part I debugged only the link is not working.
Here is the debugged code:
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart' as parser;
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> title;
List<String> image;
List<String> link;
#override
void initState() {
_getdataFromWeb();
}
void _getdataFromWeb() async {
final response = await http.get(
'https://www.bewakoof.com/');
dom.Document document = parser.parse(response.body);
final pictures =
document.getElementsByClassName('chWrprInner');
//document.getElementsByClassName('entry-header blog-entry-header');
final description =
//document.getElementsByClassName('entry-content');
document.getElementsByClassName('chWrprInner');
final nextPage =
//document.getElementsByClassName('entry-title');
document.getElementsByClassName('chWrprInner');
image = pictures
.map((element) =>
element.getElementsByTagName("img")[0]
.attributes['src'])
.toList();
title = description
.map((element) => element.getElementsByTagName("p")[0]
.innerHtml)
.toList();
link = nextPage
.map((element) =>
element.getElementsByTagName("a")[0]
.attributes['href'])
.toList();
print(link);
}
#override
Widget build(BuildContext context) {
print("hello");
if (image == null)
print("null");
else
print(image);
return SafeArea(
child: Scaffold(
backgroundColor: Colors.black87,
body: title == null || title.length == 0
? Text(
"No data",
style: TextStyle(
color: Colors.white,
),
)
: ListView.builder(
itemCount: title.length,
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 375),
child: SlideAnimation(
child: FadeInAnimation(
child: GestureDetector(
onTap: () async {
dynamic url = link[index];
if (await canLaunch(url))
launch(url);
else {
print('error');
}
},
child: Padding(
padding: const EdgeInsets.all(10),
child: Card(
child: Container(
color: Colors.black87,
child: Column(
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: Text(
title[index],
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.cyan,
fontSize: 20,
),
),
),
SizedBox(height: 15),
Text(
title[index],
style: TextStyle(
color: Colors.white,
),
),
Image.network(image[index]),
],
),
),
),
),
))),
);
},
),
),
);
}
}
you can use this package for web scraping:
web_scraper: ^0.0.9
if need see sample , you can visit this repository:
https://github.com/esmaeil-ahmadipour/Flutter_Web_Scraper

Flutter exception caught by widgets library failed assertion

I am getting below exception. I am just learning Flutter.
Below is my code:
import 'package:flutter/material.dart';
void main() => runApp(new FriendlyChatApp());
const String _name = "Hammad Tariq";
class FriendlyChatApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: "Friendly Chat",
home: new ChatScreen(),
);
}
}
class ChatScreen extends StatelessWidget {
ChatScreen({this.text});
final String text;
#override
Widget build(BuildContext context) {
return new Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
margin: const EdgeInsets.only(right: 10.0),
child: new CircleAvatar(
child: new Text(_name),
),
),
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(_name, style: Theme.of(context).textTheme.subhead),
new Container(
margin: const EdgeInsets.only(top: 5.0),
child: new Text(text),
),
],
)
],
),
);
/*return new Scaffold(
appBar: AppBar(
title: new Text("Chat App"),
),
);*/
}
}
The issue is in the line
child: new Text(text)
where String text is null.
You've defined text as an optional parameter and you are not passing it from FriendlyChatApp.
If you require some inputs from parent page for the child to work properly then you can define it with #required annotation because you won't miss it accidentally.

How to create a dynamic TabBarView/ Render a new Tab with a function in Flutter?

So I have been learning flutter in a while and I am stuck in this. Sorry if it is a noobish question. I am currently trying to build something like a Card Tab. The information and widget will be stored in a card.
Imagine something like Tinder, where they have multiple card stack and swipe left and right to navigate.
I plan to create that but I cannot seems to find a way to add/render a new card with a button.
It's like adding something to the list, Flutter will use a ListView builder where we add to the list. But there is no TabBarView builder. Is this something that is not possible to do? I try putting a list inside a tab but it's still wont be the same.
I created some basic skeleton here to help convey my meaning. So the card will be swipe left and right and there is a button in the appBar to add card. Lenght is 2 now and I wanted the button to render the 3rd card. Is this possible?
Thanks in advance!
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
home: new CardStack(),
));
}
class CardStack extends StatefulWidget {
#override
_MainState createState() => new _MainState();
}
class _MainState extends State<CardStack> with SingleTickerProviderStateMixin {
TabController _cardController;
#override
void initState() {
super.initState();
_cardController = new TabController(vsync: this, length: 2);
}
#override
void dispose() {
_cardController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.grey[300],
appBar: new AppBar(
actions: <Widget>[
new IconButton(
icon: const Icon(Icons.add),
tooltip: 'Add Tabs',
onPressed: null,
),
],
title: new Text("Title Here"),
bottom: new PreferredSize(
preferredSize: const Size.fromHeight(20.0),
child: new Theme(
data: Theme.of(context).copyWith(accentColor: Colors.grey),
child: new Container(
height: 50.0,
alignment: Alignment.center,
child: new TabPageSelector(controller: _cardController),
),
)
)
),
body: new TabBarView(
controller: _cardController,
children: <Widget>[
new Center(
child: new Card(
child: new Container(
height: 450.0,
width: 300.0,
child: new IconButton(
icon: new Icon(Icons.favorite, size: 100.0),
tooltip: 'Favorited',
onPressed: null,
)
),
),
),
new Center(
child: new Card(
child: new Container(
height: 450.0,
width: 300.0,
child: new IconButton(
icon: new Icon(Icons.local_pizza, size: 50.0,),
tooltip: 'Pizza',
onPressed: null,
)
),
),
),
],
),
);
}
}
Problems arise if you need to modify the arrays. They consist in the fact that when modifying an array you do not have the opportunity to use the same controller.
You can use the next custom widget for this case:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
#override
MyHomePageState createState() => MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
List<String> data = ['Page 0', 'Page 1', 'Page 2'];
int initPosition = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: CustomTabView(
initPosition: initPosition,
itemCount: data.length,
tabBuilder: (context, index) => Tab(text: data[index]),
pageBuilder: (context, index) => Center(child: Text(data[index])),
onPositionChange: (index) {
print('current position: $index');
initPosition = index;
},
onScroll: (position) => print('$position'),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
data.add('Page ${data.length}');
});
},
child: const Icon(Icons.add),
),
);
}
}
class CustomTabView extends StatefulWidget {
const CustomTabView({
super.key,
required this.itemCount,
required this.tabBuilder,
required this.pageBuilder,
this.stub,
this.onPositionChange,
this.onScroll,
this.initPosition,
});
final int itemCount;
final IndexedWidgetBuilder tabBuilder;
final IndexedWidgetBuilder pageBuilder;
final Widget? stub;
final ValueChanged<int>? onPositionChange;
final ValueChanged<double>? onScroll;
final int? initPosition;
#override
CustomTabsState createState() => CustomTabsState();
}
class CustomTabsState extends State<CustomTabView>
with TickerProviderStateMixin {
late TabController controller;
late int _currentCount;
late int _currentPosition;
#override
void initState() {
_currentPosition = widget.initPosition ?? 0;
controller = TabController(
length: widget.itemCount,
vsync: this,
initialIndex: _currentPosition,
);
controller.addListener(onPositionChange);
controller.animation!.addListener(onScroll);
_currentCount = widget.itemCount;
super.initState();
}
#override
void didUpdateWidget(CustomTabView oldWidget) {
if (_currentCount != widget.itemCount) {
controller.animation!.removeListener(onScroll);
controller.removeListener(onPositionChange);
controller.dispose();
if (widget.initPosition != null) {
_currentPosition = widget.initPosition!;
}
if (_currentPosition > widget.itemCount - 1) {
_currentPosition = widget.itemCount - 1;
_currentPosition = _currentPosition < 0 ? 0 : _currentPosition;
if (widget.onPositionChange is ValueChanged<int>) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted && widget.onPositionChange != null) {
widget.onPositionChange!(_currentPosition);
}
});
}
}
_currentCount = widget.itemCount;
setState(() {
controller = TabController(
length: widget.itemCount,
vsync: this,
initialIndex: _currentPosition,
);
controller.addListener(onPositionChange);
controller.animation!.addListener(onScroll);
});
} else if (widget.initPosition != null) {
controller.animateTo(widget.initPosition!);
}
super.didUpdateWidget(oldWidget);
}
#override
void dispose() {
controller.animation!.removeListener(onScroll);
controller.removeListener(onPositionChange);
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
if (widget.itemCount < 1) return widget.stub ?? Container();
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
alignment: Alignment.center,
child: TabBar(
isScrollable: true,
controller: controller,
labelColor: Theme.of(context).primaryColor,
unselectedLabelColor: Theme.of(context).hintColor,
indicator: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context).primaryColor,
width: 2,
),
),
),
tabs: List.generate(
widget.itemCount,
(index) => widget.tabBuilder(context, index),
),
),
),
Expanded(
child: TabBarView(
controller: controller,
children: List.generate(
widget.itemCount,
(index) => widget.pageBuilder(context, index),
),
),
),
],
);
}
void onPositionChange() {
if (!controller.indexIsChanging) {
_currentPosition = controller.index;
if (widget.onPositionChange is ValueChanged<int>) {
widget.onPositionChange!(_currentPosition);
}
}
}
void onScroll() {
if (widget.onScroll is ValueChanged<double>) {
widget.onScroll!(controller.animation!.value);
}
}
}
Try this.
To make dynamic tab you can use a List and keep appending the list on every button click.
Trick: Clear List and redraw an empty widget and again draw the widgets as per your list.
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
home: new CardStack(),
));
}
class DynamicTabContent {
IconData icon;
String tooTip;
DynamicTabContent.name(this.icon, this.tooTip);
}
class CardStack extends StatefulWidget {
#override
_MainState createState() => new _MainState();
}
class _MainState extends State<CardStack> with TickerProviderStateMixin {
List<DynamicTabContent> myList = new List();
TabController _cardController;
TabPageSelector _tabPageSelector;
#override
void initState() {
super.initState();
myList.add(new DynamicTabContent.name(Icons.favorite, "Favorited"));
myList.add(new DynamicTabContent.name(Icons.local_pizza, "local pizza"));
_cardController = new TabController(vsync: this, length: myList.length);
_tabPageSelector = new TabPageSelector(controller: _cardController);
}
#override
void dispose() {
_cardController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.grey[300],
appBar: new AppBar(
actions: <Widget>[
new Padding(
padding: const EdgeInsets.all(1.0),
child: new IconButton(
icon: const Icon(
Icons.add,
size: 30.0,
color: Colors.white,
),
tooltip: 'Add Tabs',
onPressed: () {
List<DynamicTabContent> tempList = new List();
myList.forEach((dynamicContent) {
tempList.add(dynamicContent);
});
setState(() {
myList.clear();
});
if (tempList.length % 2 == 0) {
myList.add(new DynamicTabContent.name(Icons.shopping_cart, "shopping cart"));
} else {
myList.add(new DynamicTabContent.name(Icons.camera, "camera"));
}
tempList.forEach((dynamicContent) {
myList.add(dynamicContent);
});
setState(() {
_cardController = new TabController(vsync: this, length: myList.length);
_tabPageSelector = new TabPageSelector(controller: _cardController);
});
},
),
),
],
title: new Text("Title Here"),
bottom: new PreferredSize(
preferredSize: const Size.fromHeight(10.0),
child: new Theme(
data: Theme.of(context).copyWith(accentColor: Colors.grey),
child: myList.isEmpty
? new Container(
height: 30.0,
)
: new Container(
height: 30.0,
alignment: Alignment.center,
child: _tabPageSelector,
),
))),
body: new TabBarView(
controller: _cardController,
children: myList.isEmpty
? <Widget>[]
: myList.map((dynamicContent) {
return new Card(
child: new Container(
height: 450.0,
width: 300.0,
child: new IconButton(
icon: new Icon(dynamicContent.icon, size: 100.0),
tooltip: dynamicContent.tooTip,
onPressed: null,
)),
);
}).toList(),
),
);
}
}
Hope this helps :)