how to prevent rebuild all widget in IndexedStack? - flutter

I want to rebuild just one widget in IndexedStack.
my app has 5 widgets(PostListScreen,AgendaListScreen ....)in IndexedStack.
PostListSceen have PostContainer.
I can go to PostContainer when I click element in PostListScreen. and then go back to PostListScreen.
5 widgets are all rebuild. I think just PostListScreen widget have to rebuild.
why other widgets also rebuild????. It makes unnecessary communication with server.
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
PreferredSizeWidget? _appBarContainer(bottomSelectedIndex) {
return (bottomSelectedIndex == 0 || bottomSelectedIndex == 1)
? const AppBarRedContainer()
: AppBarNavigatorContainer(actions: [
IconButton(
padding: EdgeInsets.only(right: 15.0.w),
icon: SvgPicture.asset(
"assets/images/notification_b.svg",
),
iconSize: 24.0.r,
constraints: const BoxConstraints(),
onPressed: () {
Beamer.of(context).beamToNamed('/$locationAlarm');
},
)
], title: (bottomSelectedIndex == 3 ? "핫글 모음" : "내 정보"))
as PreferredSizeWidget;
}
#override
Widget build(BuildContext context) {
int bottomSelectedIndex =
Provider.of<IndexNotifier>(context, listen: false).bottomSelectedIndex;
StockModel stock = Provider.of<StockCodeNotifier>(context, listen: false).stock;
if (stock.code == null) {
Provider.of<StockCodeNotifier>(context, listen: false).getStocks();
stock = Provider.of<StockCodeNotifier>(context, listen: false).stock;
FlutterNativeSplash.remove();
}
return Scaffold(
appBar: _appBarContainer(bottomSelectedIndex),
body: SafeArea(
child: IndexedStack(
index: bottomSelectedIndex,
children: [
PostListScreen(stock: stock),
AgendaListScreen(
stock: stock,
),
WriteScreen(
stockCode: stock.code!,
),
const HotListScreen(),
const MyInfoScreen()
],
),
),
);
}
}
postListScreen.dart
class PostListScreen extends StatefulWidget {
const PostListScreen({Key? key, required this.stock}) : super(key: key);
final StockModel stock;
#override
State<PostListScreen> createState() => _PostListScreenState();
}
class _PostListScreenState extends State<PostListScreen> {
late Future<List<PostModel>> _postData;
bool init = false;
#override
void initState() {
if(!init){
_postData = _fetchPostData();
init = true;
}
super.initState();
}
Future<List<PostModel>> _fetchPostData() async {
return await PostListService().getPosts(widget.stock.code!);
}
Future<void> _onRefresh() async {
setState(() {});
Future.value(null);
}
#override
Widget build(BuildContext context) {
return FutureBuilder<List<PostModel>>(
future: _postData,
builder: (context, snapshot) {
return RefreshIndicator(
onRefresh: _onRefresh,
child: CustomScrollView(slivers: [
SliverAppBar(
floating: true,
expandedHeight: 148.0.h,
flexibleSpace: FlexibleSpaceBar(
background: StockInfo(
stockCount: widget.stock.count!,
stockName: widget.stock.name!,
),
),
),
(snapshot.hasData == false)
? const SliverFillRemaining(
child: Center(child: CircularProgressIndicator()))
: (snapshot.data!.isNotEmpty)
? _sliverList(snapshot.data!)
: SliverFillRemaining(
child: NoContentContainer(
onRefresh: _onRefresh,
noText: "이야기가 없어요",
offerText: '첫 이야기를 작성해 보시는 건 어떨까요?'),
),
]),
);
});
}
}

Related

Flutter bottomNavigationBar not changing pages (when it's the "same page")

I have a bottom navigation bar and realized that the different pages/widgets that the navigator was going to were pretty much the exact same page (except for 2 parameters that changed). So instead of creating 2 pages/widgets which were pretty much identical (with only 2 differing parameters), I wanted to consolidate it into only one widget and pass the parameters from the page with the bottom navigator. The problem is that now that I did that it won't change the page it displays, or at least it won't change consistently (it usually will only show the page that corresponds to the first tab in the navigator (i.e., index = 0)). Here is my page with the bottom navigator:
class FreestylePage extends StatefulWidget {
const FreestylePage({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _FreestylePageState();
}
}
class _FreestylePageState extends State<FreestylePage> {
int _currentIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: showCategory(_currentIndex),
)),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.looks_one_outlined),
label: 'Single rope',
backgroundColor: Color.fromRGBO(204, 16, 138, 1)),
BottomNavigationBarItem(
icon: Icon(Icons.looks_two_outlined),
label: 'Double dutch',
backgroundColor: Color.fromRGBO(204, 16, 138, 1)),
],
onTap: (index) {
if (mounted) {
setState(() {
_currentIndex = index;
});
}
},
),
);
}
showCategory(index) {
if (index == 0) {
return [
WorkoutListPage(categoryIndex: 2, subCategories: Utils.srfDropdown)
];
} else {
return [
WorkoutListPage(categoryIndex: 3, subCategories: Utils.ddfDropdown)
];
}
}
}
And the WorkoutListPage looks as follows:
class WorkoutListPage extends StatefulWidget {
final int categoryIndex;
final List<String> subCategories;
const WorkoutListPage(
{Key? key, required this.categoryIndex, required this.subCategories})
: super(key: key);
#override
State<StatefulWidget> createState() {
return _WorkoutListPageState();
}
}
class _WorkoutListPageState extends State<WorkoutListPage> {
bool isLoading = true;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) =>
FutureBuilder<List<Map<String, dynamic>>>(
future: MyCard.getData(widget.categoryIndex, widget.subCategories)!
.whenComplete(() => setState(() {
isLoading = false;
})),
builder: ((context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
return FutureBuilder<List<MyCard>>(
future: MyCard.readData(snapshot.data),
builder: (context, cards) {
if (cards.hasData) {
final card = cards.data!;
return Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: card.length,
itemBuilder: (context, index) {
return MyCard.buildCard(card[index], context);
},
),
);
} else {
return const Text("No data");
}
});
} else {
return isLoading
? Column(
children: const [CircularProgressIndicator()],
)
: const Text("You do not have any workouts yet");
}
}),
);
}
This doesn't work, but ironically if I change my showCategory function in the widget with the bottom navigation bar to the following:
showCategory(index) {
if (index == 0) {
return [
WorkoutListPage(categoryIndex: 2, subCategories: Utils.srfDropdown)
];
} else {
return [const FreestyleDDPage()];
}
}
where the FreestyleDDPage is the following:
class FreestyleDDPage extends StatefulWidget {
const FreestyleDDPage({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _FreestyleDDPageState();
}
}
class _FreestyleDDPageState extends State<FreestyleDDPage> {
var isLoading = true;
#override
Widget build(BuildContext context) =>
FutureBuilder<List<Map<String, dynamic>>>(
future: MyCard.getData(3, Utils.ddfDropdown)!
.whenComplete(() => setState(() {
isLoading = false;
})),
builder: ((context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
return FutureBuilder<List<MyCard>>(
future: MyCard.readData(snapshot.data),
builder: (context, cards) {
if (cards.hasData) {
final card = cards.data!;
return Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: card.length,
itemBuilder: (context, index) {
return MyCard.buildCard(card[index], context);
},
),
);
} else {
return const Text("No data");
}
});
} else {
return isLoading
? Column(
children: const [CircularProgressIndicator()],
)
: const Text("You do not have any workouts yet");
}
}),
);
}
then it works.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
CustomWidgetWithParametr(index: 0 , categoryName: "HOME"),
CustomWidgetWithParametr(index: 1 , categoryName: "BUSINES"),
CustomWidgetWithParametr(index: 2 , categoryName: "SCHOOL"),
CustomWidgetWithParametr(index: 3 , categoryName: "Settings"),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
backgroundColor: Colors.red,
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Business',
backgroundColor: Colors.green,
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: 'School',
backgroundColor: Colors.purple,
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Settings',
backgroundColor: Colors.pink,
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
class CustomWidgetWithParametr extends StatefulWidget {
const CustomWidgetWithParametr({Key? key, required this.index, required this.categoryName}) : super(key: key);
final int index;
final String categoryName;
#override
State<CustomWidgetWithParametr> createState() => _CustomWidgetWithParametrState();
}
class _CustomWidgetWithParametrState extends State<CustomWidgetWithParametr> {
#override
Widget build(BuildContext context) {
return
Column(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(widget.index.toString()),
Text(widget.categoryName),
],
);
}
}

'RenderBox was not laid out' when using ExpansionPanelList

I want to show a GridView on the left and a ExpansionPanelList on the right. I put them in a Row Widget but it did not work, error is :
Assertion failed:
D:\…\rendering\box.dart:1929
hasSize
"RenderBox was not laid out: RenderRepaintBoundary#bb5e9 NEEDS-LAYOUT NEEDS-PAINT"
The relevant error-causing widget was
Row
lib\main.dart:69
this is all my code in main.dart:
// ignore_for_file: prefer_const_constructors
// ignore_for_file: prefer_const_literals_to_create_immutables
import 'package:flutter/material.dart';
void main() => runApp(MyApp(UniqueKey()));
class MyApp extends StatelessWidget {
const MyApp(Key key) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MyHomePage(UniqueKey()),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage(Key key) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
List<int> getDataList() {
List<int> list = [];
for (int i = 0; i < 96; i++) {
list.add(i);
}
return list;
}
List<Widget> getWidgetList() {
return getDataList().map((item) => getItemContainer(item)).toList();
}
var i = 0;
Widget getItemContainer(int item) {
return Block(item);
}
//创建gridview
Widget buildGrid() {
return GridView.count(
//水平子Widget之间间距
crossAxisSpacing: 10.0,
//垂直子Widget之间间距
mainAxisSpacing: 30.0,
//GridView内边距
padding: EdgeInsets.all(10.0),
//一行的Widget数量
crossAxisCount: 4,
//子Widget宽高比例
childAspectRatio: 2.0,
//子Widget列表
children: getWidgetList(),
);
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("this is title"),
),
body: Container(
child: Row(
children: <Widget>[
Expanded(
child: buildGrid(),
),
ExpansionPanelPage(UniqueKey()),
],
)),
);
}
}
class Block extends StatelessWidget {
final int itemNo;
const Block(this.itemNo, {Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Listener(
onPointerHover: (event) => print(itemNo.toString()),
onPointerMove: (event) => print("aa" + itemNo.toString()),
child: Container(
alignment: Alignment.center,
child: Text(
"item",
style: TextStyle(color: Colors.white, fontSize: 20),
),
color: Colors.blue,
),
);
}
}
// stores ExpansionPanel state information
class Item {
Item({
required this.expandedValue,
required this.headerValue,
this.isExpanded = false,
});
String expandedValue;
String headerValue;
bool isExpanded;
}
List<Item> generateItems(int numberOfItems) {
return List.generate(numberOfItems, (int index) {
return Item(
headerValue: 'Panel $index',
expandedValue: 'This is item number $index',
);
});
}
class ExpansionPanelPage extends StatefulWidget {
ExpansionPanelPage(Key key) : super(key: key);
#override
_ExpansionPanelPageState createState() => _ExpansionPanelPageState();
}
class _ExpansionPanelPageState extends State<ExpansionPanelPage> {
List<Item> _data = generateItems(1);
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
width: 10,
height: 10,
child: _buildPanel(),
),
);
}
Widget _buildPanel() {
return ExpansionPanelList(
expansionCallback: (int index, bool isExpanded) {
setState(() {
_data[index].isExpanded = !isExpanded;
});
},
children: _data.map<ExpansionPanel>((Item item) {
return ExpansionPanelRadio(
headerBuilder: (BuildContext context, bool isExpanded) {
return ListTile(
title: Text(item.headerValue),
);
},
body: Column(
children :<Widget>[
Text("1"),
Text("1"),
Text("1"),
Text("1"),
]
),
value: item.headerValue,
);
}).toList(),
);
}
}
..........................................................................
..........................................................................
I know it might be a bit late to answer your question but for those who are facing the same issue, try wrapping ExpansionPanelList with the SingleChildScrollView widget. It helps your panel list to take all available space and to shrink-wrap in both axes. Check the docs for more info!

Flutter Scroll view to focused widget on a column

I'm developing an app for Android TV, and use DPAD navigation.
I have multiple widgets inside a column. when i navigate to a widget which is outside the view, the widget/view is not moving to reflect the selected widget.
// ignore_for_file: avoid_print
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatelessWidget(),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final TextTheme textTheme = Theme.of(context).textTheme;
return DefaultTextStyle(
style: textTheme.headline4!,
child: ChangeNotifierProvider<SampleNotifier>(
create: (context) => SampleNotifier(), child: const CardHolder()),
);
}
}
class CardHolder extends StatefulWidget {
const CardHolder({Key? key}) : super(key: key);
#override
_CardHolderState createState() => _CardHolderState();
}
class _CardHolderState extends State<CardHolder> {
late FocusNode _focusNode;
late FocusAttachment _focusAttachment;
#override
void initState() {
super.initState();
_focusNode = FocusNode(debugLabel: "traversal_node");
_focusAttachment = _focusNode.attach(context, onKey: _handleKeyPress);
_focusNode.requestFocus();
}
#override
Widget build(BuildContext context) {
_focusAttachment.reparent();
return Focus(
focusNode: _focusNode,
autofocus: true,
onKey: _handleKeyPress,
child: Consumer<SampleNotifier>(
builder: (context, models, child) {
int listSize = Provider.of<SampleNotifier>(context).listSize;
return SingleChildScrollView(
child: SampleRow(cat: "Test", models: models.modelList),
);
},
),
);
}
KeyEventResult _handleKeyPress(FocusNode node, RawKeyEvent event) {
if (event is RawKeyDownEvent) {
print("t:FocusNode: ${node.debugLabel} event: ${event.logicalKey}");
if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
Provider.of<SampleNotifier>(context, listen: false).moveRight();
return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
Provider.of<SampleNotifier>(context, listen: false).moveLeft();
return KeyEventResult.handled;
}
}
// debugDumpFocusTree();
return KeyEventResult.ignored;
}
}
class SampleCard extends StatefulWidget {
final int number;
final SampleModel model;
final bool focused;
const SampleCard(
{required this.number,
required this.focused,
required this.model,
Key? key})
: super(key: key);
#override
_SampleCardState createState() => _SampleCardState();
}
class _SampleCardState extends State<SampleCard> {
late Color _color;
#override
void initState() {
super.initState();
_color = Colors.red.shade900;
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: widget.focused
? Container(
width: 150,
height: 300,
color: Colors.white,
child: Center(
child: Text(
"${widget.model.text} ${widget.model.num}",
style: TextStyle(color: _color),
),
),
)
: Container(
width: 150,
height: 300,
color: Colors.black,
child: Center(
child: Text(
"${widget.model.text} ${widget.model.num}",
style: TextStyle(color: _color),
),
),
),
);
}
}
class SampleRow extends StatelessWidget {
final String cat;
final List<SampleModel> models;
SampleRow({Key? key, required this.cat, required this.models}) : super(key: key);
#override
Widget build(BuildContext context) {
final int selectedIndex =
Provider.of<SampleNotifier>(context).selectedIndex;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.only(left: 16, bottom: 8),
),
models.isNotEmpty
? SizedBox(
height: 200,
child: ListView.custom(
padding: const EdgeInsets.all(8),
scrollDirection: Axis.horizontal,
childrenDelegate: SliverChildBuilderDelegate(
(context, index) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: SampleCard(
focused: index == selectedIndex,
model: models[index],
number: index,
),
),
childCount: models.length,
findChildIndexCallback: _findChildIndex,
),
),
)
: SizedBox(
height: 200,
child: Container(
color: Colors.teal,
),
)
],
);
}
int _findChildIndex(Key key) => models.indexWhere((model) =>
"$cat-${model.text}_${model.num}" == (key as ValueKey<String>).value);
}
class SampleNotifier extends ChangeNotifier {
final List<SampleModel> _models = [
SampleModel(0, "zero"),
SampleModel(1, "one"),
SampleModel(2, "two"),
SampleModel(3, "three"),
SampleModel(4, "four"),
SampleModel(5, "five"),
SampleModel(6, "six"),
SampleModel(7, "seven"),
SampleModel(8, "eight"),
SampleModel(9, "nine"),
SampleModel(10, "ten")
];
int _selectedIndex = 0;
List<SampleModel> get modelList => _models;
int get selectedIndex => _selectedIndex;
int get listSize => _models.length;
void moveRight() {
if (_selectedIndex < _models.length - 1) {
_selectedIndex = _selectedIndex + 1;
}
notifyListeners();
}
void moveLeft() {
if (_selectedIndex > 0) {
_selectedIndex = _selectedIndex - 1;
}
notifyListeners();
}
}
class SampleModel {
int num;
String text;
SampleModel(this.num, this.text);
}
I need a way to move/scroll the widget into view. Is there any way to do this, using the DPAD navigation on android tv
Here is the gist
You could use the scrollable_positioned_list package.
Instead of a ListView.custom which scrolls based on pixels, this widgets its based on index:
final ItemScrollController itemScrollController = ItemScrollController();
ScrollablePositionedList.builder(
itemCount: 500,
itemBuilder: (context, index) => Text('Item $index'),
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionsListener,
);
So you could maintain an index of the current scroll position and on DPAD press just :
itemScrollController.jumpTo(index: currentItem);
setState((){currentItem++;})

Sort dynamically ListView in Flutter

I would like to sort a ListView based on a StreamController in a BottomNavigationBar.
The problem is that the Listview doesn't refresh when I click the button on the app bar.
I would like to pass as parameter the function (Comparable of Company) which the user chooses.
Here's my code:
Home.dart
final CompanyService _companyService = CompanyService();
final AuthService _auth = AuthService();
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
Home createState() => Home();
}
class Home extends State<HomePage> {
Comparator<Company> _sortFunction;
int _currentIndex;
var _tabs = [];
#override
void initState() {
super.initState();
_currentIndex = 0;
_sortFunction = (a, b) => a.name.compareTo(b.name);
}
PreferredSize getDoubleHomeAppBar() {
return PreferredSize(
preferredSize: Size.fromHeight(55.0),
child: Row(
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.only(left: 12.0),
margin:
const EdgeInsets.only(left: 12.0, bottom: 8.0, right: 12.0),
color: PRIMARY_COLOR,
),
),
FlatButton.icon(
icon: Icon(Icons.sort_by_alpha),
label: Text(
'Sort',
),
onPressed: () {
setState(() {
_sortFunction = (a, b) => b.city.compareTo(a.city);
_tabs[0] = CompanyTab(sortFunction: _sortFunction);
});
},
),
],
));
}
#override
Widget build(BuildContext context) {
_tabs = [
CompanyTab(sortFunction: _sortFunction),
MapTab(),
Center(child: Text('Profile')),
Center(child: Text('Settings')),
];
return Scaffold(
backgroundColor: BACKGROUND_COLOR,
appBar: AppBar(
elevation: 0.0,
centerTitle: true,
title: Text(
'JobAdvisor',
style: TextStyle(
fontSize: MediaQuery.of(context).size.height / 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
bottom: _currentIndex == 0 ? getDoubleHomeAppBar() : null,
actions: <Widget>[...],
),
body: _tabs[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
backgroundColor: BACKGROUND_COLOR,
type: BottomNavigationBarType.fixed,
items: [
...
],
onTap: (index) {
setState(() {
_currentIndex = index;
print('Index: $index');
print('Current index: $_currentIndex');
});
},
),
);
}
}
CompanyTab.dart
#immutable
class CompanyTab extends StatefulWidget {
final CompanyService _companyService = CompanyService();
final Comparator<Company> sortFunction;
CompanyTab({Key key, this.sortFunction}) : super(key: key);
#override
_CompanyTabState createState() =>
_CompanyTabState(_companyService, sortFunction);
}
class _CompanyTabState extends State<CompanyTab> {
StreamController<List<Company>> _streamController;
final CompanyService _companyService;
Comparator<Company> sortFunction;
_CompanyTabState(this._companyService, this.sortFunction);
#override
void initState() {
super.initState();
}
StreamBuilder companyList() {
return StreamBuilder<List<Company>>(
initialData: [],
stream: _streamController.stream,
builder: (BuildContext context, AsyncSnapshot<List<Company>> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.connectionState == ConnectionState.waiting ||
snapshot.connectionState == ConnectionState.none ||
snapshot.data == null) {
return LoadingWidget();
} else {
return ListView.builder(
padding: const EdgeInsets.all(10),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
Company company = snapshot.data.elementAt(index);
...
}
}
});
}
#override
void dispose() {
_streamController.close();
super.dispose();
}
void _getData() {
_streamController = new StreamController<List<Company>>();
_companyService.getCompanies().then((value) => {_elaborateList(value)});
}
void _elaborateList(List<Company> list) {
List<Company> tmp = list;
tmp.sort(sortFunction);
print(tmp.toString());
_streamController.sink.add(tmp);
}
#override
Widget build(BuildContext context) {
_getData();
return Center(
child: Container(
child: companyList(),
),
);
}
}
I think the problem is in your sort method. It should be like this:
_sortFunction.sort((a, b) => a.name.compareTo(b.name));
You can read from the official document.
EDIT:
And you need to use sortFunction of the widget in here:
tmp.sort(widget.sortFunction);
You are not using the same sortFunction in CompanyTab. You should use the sortFunction which comes as a parameter. Here is a blog about it.

Child widget send dynamic data

I have a two-page app. On-Page One I am showing an UUID which changes every 1 second. It is shown using listview. Once the user clicks on the list view it goes to the second page and shows the data on that card.
It should have been the changing UUID. but the data shown is static UUID. How I can pass the data changed on page 1 to page 2?
import 'dart:async';
import 'package:uuid/uuid.dart';
import 'package:uuid/uuid_util.dart';
import 'package:flutter/material.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: 'Flutter Demo Home Page'),
);
}
}
List<EuropeanCountries> europeanCountries = [];
class EuropeanCountries {
String myText;
String myUuid;
EuropeanCountries({
this.myText,
this.myUuid,
});
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
int _perPage = 50;
ScrollController _myScrollController = ScrollController();
void _incrementCounter() async {
const ThreeSec = const Duration(seconds: 1);
this._counter++;
europeanCountries.insert(
0,
EuropeanCountries(
myText: this._counter.toString(),
));
print(europeanCountries[0].myText);
setState(() {});
}
void getMoreData() {
print('adding More Product ');
europeanCountries.add(EuropeanCountries(
myText: this._counter.toString(),
));
//europeanCountries.insert(0, EuropeanCountries(myText:this._counter.toString(), myButtonText: "", myColor: Colors.blue));
setState(() {});
}
void generateUUID() async {
var uuid = Uuid();
for (int i = 0; i < 6000; i++) {
await new Future.delayed(new Duration(milliseconds: 1000));
for (EuropeanCountries currCountry in europeanCountries) {
currCountry.myUuid = uuid.v1();
}
setState(() {});
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
generateUUID();
_myScrollController.addListener(() {
double maxscroll = _myScrollController.position.maxScrollExtent;
double currentScroll = _myScrollController.position.pixels;
double delta = MediaQuery.of(context).size.height * 0.25;
print("mac Scroll Controller - " + maxscroll.toString());
print("Current Scroll Controller - " + currentScroll.toString());
print("delta Scroll Controller - " + delta.toString());
if ((maxscroll - currentScroll) < delta) {
getMoreData();
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _myListView(context),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
Widget _myListView(BuildContext context) {
// backing data
return Container(
child: europeanCountries.length == 0
? Center(
child: Text('No Product to Display'),
)
: ListView.builder(
controller: _myScrollController,
itemCount: europeanCountries.length,
reverse: false,
itemBuilder: (context, index) {
return myContainer(index: index);
},
),
);
}
}
class myContainer extends StatefulWidget {
final int index;
const myContainer({Key key, this.index}) : super(key: key);
#override
_myContainerState createState() => _myContainerState();
}
class _myContainerState extends State<myContainer> {
#override
Widget build(BuildContext context) {
return Container(
height: 120,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue[700]),
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(8)),
),
margin: EdgeInsets.all(20),
child: Column(
children: <Widget>[
Text(europeanCountries[widget.index].myText),
SizedBox(
height: 15,
),
RaisedButton(
child: Text('Detail'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondRoute(
myCountry: europeanCountries[widget.index],
)),
);
},
color: Colors.blue[700],
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
splashColor: Colors.black,
),
Text(europeanCountries[widget.index].myUuid != null
? europeanCountries[widget.index].myUuid
: 'Default')
],
),
);
}
}
class SecondRoute extends StatefulWidget {
final EuropeanCountries myCountry;
const SecondRoute({Key key, this.myCountry}) : super(key: key);
#override
_SecondRouteState createState() => _SecondRouteState();
}
class _SecondRouteState extends State<SecondRoute> {
#override
void didUpdateWidget(SecondRoute oldWidget) {
// TODO: implement didUpdateWidget
super.didUpdateWidget(oldWidget);
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Text(widget.myCountry.myUuid != null
? widget.myCountry.myText
: 'default'),
),
SizedBox(height: 15),
Center(
child: Text(widget.myCountry.myUuid != null
? widget.myCountry.myUuid
: 'default'),
),
],
),
),
),
);
}
}
https://imgur.com/VqRfcZY
<blockquote class="imgur-embed-pub" lang="en" data-id="VqRfcZY"></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>