use only one page with DefaultTabController of 3 TabBars - flutter

I am using DefaultTabController for 3 TabBars. But i need to use only one page to be shown fetching the data from database all three TabBars are the same, But only the fetched data is different according to the index of its tap. How could i do so without create 3 copies of the same object WidgetOfTape?
the code is:
DefaultTabController(
length: 3,
child: Scaffold(
body: const TabBarView(
children: [
WidgetOfTape(),
WidgetOfTape(),
WidgetOfTape(),
],
),
WidgetOfTape code is:
class WidgetOfTape extends HookWidget {
const WidgetOfTape ();
#override
Widget build(BuildContext context) {
return BlocSelector<ScheduledPossibleDayCubit, ScheduledPossibleDayState,
int>(selector: (state) {
return state.indexOfTap;
}, builder: (context, state) {
return BlocProvider<DisplayNoteInsidePagesCubit>(
lazy: false,
create: (context) => getIt<DisplayNoteInsidePagesCubit>()
..countDoneNoteOutOfAllNotes()
..retrieveData(indexOfTap: state),
child: Column(children: [
Expanded(child: BlocBuilder<DisplayNoteInsidePagesCubit,
DisplayNoteInsidePagesState>(
builder: (context, state) {
return ListView.builder(
shrinkWrap: true,
itemCount: state.notes.length,
itemBuilder: (BuildContext context, int index) {
return Row(
children: [
Expanded(
child: Text(
state.notes[index]['content'],
textAlign: TextAlign.justify,
style: Theme.of(context).textTheme.bodyText2,
),
),
],
);
});
},
))
]));
});
}
}

Yes, you can do that, by sending a new parameter to your WidgetOfTape( ). The new variable you send as a parameter is defined by you. It could be based on the fetched data for example:
DefaultTabController(
length: 3,
child: Scaffold(
body: const TabBarView(
children: [
WidgetOfTape(newParameter1), //*** This line changed ***
WidgetOfTape(newParameter2), //*** This line changed ***
WidgetOfTape(newParameter3), //*** This line changed ***
],
),
Dont forget to add that parameter to your actual class WidgetOfTape( ).
If you dont know how to pass parameters, check here:
In Flutter, how do I pass data into a Stateless Widget?

Related

how to Add some design at top after that listview with dynamic size list and then below some some design for advertisement and comment in flutter

Scaffold(
appBar: AppBar(
title: Text("Design test..."),
),
body: Container(
margin:EdgeInsets.fromLTRB(0, MediaQuery.of(context).padding.top, 0, 0
),
child: Column(
children: [
Container(//for Some Kind of design at top),
Column(
children: [
ListView.builder(
itemCount: listLength.length,
itemBuilder: (BuildContext buildContext, int index) {
return ListTile(title: Text("hello world")
);
}),
//i want to add some design here after the list view for advertisement and comment
],
),
],
),
),
);
my listview.builder() item length is dynamic so i want to expand my list view as much as it requied and when it ends i need some design just like youtube privious design where on the top video player after that video list and at the end comment part.thank you.
Yes you can achieve this, Refer to this code.
use the build method like this.
#override
Widget build(BuildContext context) {
return Scaffold(
body : ListView(
//Base Listview, it can be scrollable if content is large also
children:[
Container(
//Sample widget you can use your own
child:Text("Here is some design At Top")
),
ListView.builder(
//use shrinkWrap:true and physics:NeverScrollableScrollPhysics()
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: 10, //it can be dynamic and null checks can be appield,
itemBuilder: (context, index){
return Text("ListItem $index");
},
),
Container(
//Sample widget you can use your own
child: Text("Some Design for Ads")
),
Container(
//Sample widget you can use your own
child: Text("Some Design for Commentes")
)
]
)
);
}
Mark answer as right if it helped !!

I can't refresh the screen

I use the get package, I have a bottom navigation that is updated with Obx. There is also a search for elements, at the top level of the pages everything is updated well, but when I do push, the current page is not updated, only when you call hot reload. There are suspicions that the nested page is not updated due to the fact that it goes beyond the BottomNavigation, and there is no Obx widget.
My Page Navigation controller:
Widget build(BuildContext context) {
SizeConfig().init(context);
final BottomPageController landingPageController =
Get.put(BottomPageController(), permanent: false);
return SafeArea(
child: Scaffold(
bottomNavigationBar:
BottomNavigationMenu(landingPageController: landingPageController),
body: Obx(
() => IndexedStack(
index: landingPageController.tabIndex.value,
children: [
ProductPage(),
MapPage(),
ClientPage(),
NotePage(),
],
),
),
),
);
}
My page where you need to update the ListView, depending on the entered value in the search bar:
class Product extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GetX<ProductController>(
init: ProductController(),
builder: (controller) {
return FutureBuilder<List<ProductsCombined>>(
future: controller.filterProduct.value,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Expanded(
child: Container(
child: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) =>
ProductCards(
product: snapshot.data[index],
),
),
),
);
} else {
return Center(child: CircularProgressIndicator());
}
},
);
},
);
}
}
There is also a nested page in the Product class, which is accessed in this way:
onTap: () => {
Get.toNamed(StoresScreen.routeName, arguments: companies)}
The Product class is updated immediately, you do not need to click Hot reload to do this, and the ProductScreen class that the transition is made to can no longer be updated, these 2 classes are completely identical. The search bar works, but it filters out the elements only after Hot reload.
If you need some other parts of my code, such as a controller that handles ListView, please write, I will attach it.
EDIT: I add a link to the video, with the screen that is not updated
Obx is a little tricky to work with. I always suggest to use GetX instead.
Try this :
Obx(
() => IndexedStack(
index: Get.find<BottomPageController>().tabIndex.value,
children: [
...
],
),
),
If it didn't work use GetX<BottomPageController> for this situation too. It works for all conditions

Render each individual list item in the data model, and render to a chip widget

I have a data model in my app that looks like this:
final DUMMY_THERAPISTS = [
Therapist(
id: 't1',
name: 'John Doe',
imageUrl:
'https://thumbs.dreamstime.com/b/avatar-del-terapeuta-icono-web-doctor-103706622.jpg',
specialties: [
'Acupuncture',
'Homeopathic',
'Floral Therapy',
],
),
]
I can access all the values from the class, except the array ones. It was defined as a List in the class model.
And this is the Widget where I am displaying the data:
class TherapistsOverviewScreen extends StatelessWidget {
final List<Therapist> loadedTherapists = DUMMY_THERAPISTS;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Therapists'),
),
body: GridView.builder(
itemCount: loadedTherapists.length,
itemBuilder: (ctx, i) => Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Wrap(
children: [
CircleAvatar(
radius: 25.0,
backgroundImage: NetworkImage(loadedTherapists[i].imageUrl),
),
Text(loadedTherapists[i].name),
Chip(
label: Text(loadedTherapists[i].specialties.toString()),
),
],
),
),
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
);
}
}
The way it is, it returns the entire collection inside the array, since it's iterating only through the list of the class, but not to the second-level, thus returning in the app a chip widget with the following content: '[Acupuncture, Homeopathy, Floral Therapy]', and not their own individual values.
I tried using the for loop from Dart, I managed to get each individual value, but I couldn't find a way to bind to the respective object group.
Thanks in advance.
Replace Chip(label: Text(loadedTherapists[i].specialties.toString()),),
with for (var specialty in loadedTherapists[i].specialties) Chip(label: Text(specialty.toString()))
You need to iterate through each value to build individual chip widgets.

How can I change the state of widget based on the action of another widget?

I am having trouble with the following problem:
In this page, I have a CheckBoxListTile and two radioButtons.
I need to implement some rules, like these one:
If any checkbox gets checked, disabled and unselect all radiobuttons
If any radiobuttons gets selected, uncheck and disable all checkboxes
However, I can't get this to work. I've tried using statefulWidgets for both checkbox and radiobutton, but the logic was getting very messy.
I've tried to use a stateful widget for the PostView class, but since I'm using a futureBuilder there, whenever I called setState(), the whole page would be rebuilt and the checkbox would not get checked.
I believe there is a cleaner solution to this, but right now I can't see it.
Here is the snippet of the code so you can see ( this is using a stateless widget, I know I cannot do it this way, but It is just to show you guys what I am trying to do ):
Widget _buildFooter(Post postInfo) {
return Container(
child: Column(
children: <Widget>[
_buildRadioButtons(postInfo),
RaisedButton(
child: Text('press'),
onPressed: () {},
),
],
),
);
}
class PostView extends StatelessWidget {
final String id;
PostView(this.id);
Post postInfo;
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppBar(),
body: FutureBuilder(
future: ApiService.getpostInfo(id),
builder: (BuildContext context, AsyncSnapshot snapShot) {
if (snapShot.connectionState == ConnectionState.done) {
if (snapShot.hasError) {
return Center(
child: Text('error'),
);
}
postInfo = postInfo.fromJson(snapShot.data);
return ListView.separated(
separatorBuilder: (BuildContext context, int index) {
return Divider();
},
itemBuilder: (BuildContext context, int index) {
if (index == 0) {
return _buildHeader(postInfo);
}
if (index == (postInfo.authors.length + 1)) {
return _buildFooter(postInfo);
}
index = index - 1;
return _buildCheckboxListTile(postInfo, index);
},
itemCount: (postInfo.authors.length) + 2,
);
}
return CircularProgressIndicator();
},
),
);
}
}
_buildCheckboxListTile(Post postInfo, index) {
return CheckboxListTile(
title: Text(postInfo.authors[index].name),
value: postInfo.authors[index].checked,
onChanged: (bool value) {
***Here I need to disabled the radiobuttons in case I get a true
},
);
}
_buildRadioButtons(Post postInfo) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: CheckboxListTile(
value: postInfo.value1,
title: Text('value1'),
onChanged: (bool value) {
*** here I need to uncheck all the checkboxes mentioned above
in case the radio button is selected
},
),
),
Expanded(
child: CheckboxListTile(
value: postInfo.value2,
title: Text('value2'),
onChanged: (bool value) {},
),
),
],
);
}
Would this behaviour be possible without a statefulWidget?
Since I'm learning Flutter, any other advices regarding the code are welcomed!
Thanks!
You could try State Management libraries to easily manage state without the code getting messy. Here is a great article on the best state management libraries to use:
https://medium.com/flutter-community/flutter-app-architecture-101-vanilla-scoped-model-bloc-7eff7b2baf7e
In the case of Scoped Model, which for me is the simplest,and which I personally use, you can set both to be a child of a ScopedModel widget and have them notify each other once the state changes.

How can I put a SearchView on top of a ListView?

I'm new to flutter and am trying to stack a searchView on top of a ListView. I would Look something like this:
I don't know how to achieve this layout on flutter, i tried using a column(which crashes the app), used the a stack (which overlaps the widgets) and i finally tried to add a search widget a the first item of the ListView but that didn't result am looking for.
Widget build(BuildContext context) {
return new Scaffold(
drawer: _makeDrawer(),
appBar: new AppBar(
title: new Center(
child: new Text("translate"),
),
actions: <Widget>[
new IconButton(icon: new Icon(Icons.people_outline), onPressed: () {})
],
),
body: _phraseListFutureBuilder(), // this part of the code renders the listview
);
}
FutureBuilder _phraseListFutureBuilder() {
return new FutureBuilder(
builder: (BuildContext context, AsyncSnapshot snapshot) {
return mPhrases.isEmpty
? new CircularProgressIndicator()
: _buildPhrases();
},
future: _fetchData());
}
A Column was the right choice, but you will also need an Expanded widget to specify which widget should fill the remaining space:
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
TextField(
decoration: InputDecoration(
labelText: 'Search'
),
),
Expanded(
child: _phraseListFutureBuilder(),
)
],
);