флаттер У меня проблема, когда я использую два StateFullWidgets
из TabController
, он перестраивается два раза, когда я прокручиваю каждый StateFullWidget
, отображающий ListView.Builder
с ScrollController
флаттером.Мне нужно восстановить только один раз.Here is the reproducible code
.
Экран вкладок
class OrdersScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() => OrderScreenState();
}
class OrderScreenState extends State<OrdersScreen>
with SingleTickerProviderStateMixin {
TabController _tabController;
final List<Color> tabColors = <Color>[Color(0xff185397), Colors.black54];
List<Widget> _orderScreens = [ToDeliverScreen(), DeliveredScreen()];
@override
void initState() {
_tabController = TabController(vsync: this, length: 2);
super.initState();
}
void _updateTabItemColor(int index) {
setState(() {
if (index == 0) {
tabColors[0] = Color(0xff185397);
tabColors[1] = Colors.black54;
} else {
tabColors[0] = Colors.black54;
tabColors[1] = Color(0xff185397);
}
});
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(kToolbarHeight),
child: Container(
color: Colors.white,
child: SafeArea(
child: Column(
children: <Widget>[
Container(),
TabBar(
indicatorColor: Color(0xff185397),
onTap: (int index) {
_updateTabItemColor(index);
},
controller: _tabController,
tabs: [
tabItem('TO DELIVER', tabColors[0]),
tabItem('DELIVERED', tabColors[1])
],
),
],
),
),
),
),
body: TabBarView(
controller: _tabController,
children: _orderScreens,
),
),
);
}
Widget tabItem(String text, Color color) {
return InkWell(
child: Container(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: Text(
text,
style: TextStyle(
color: color, fontWeight: FontWeight.bold, fontSize: 16.0),
),
),
);
}
}
Первый элемент вкладки
class ToDeliverScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() => ToDeliverScreenState();
}
class ToDeliverScreenState extends State<ToDeliverScreen> {
ToDeliverBloc _toDeliverBloc;
ScrollController _scrollController = ScrollController();
bool isLoading = false;
bool isInitPage = true;
int page = 2;
List<Order> orders = [];
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
@override
void initState() {
_toDeliverBloc = BlocProvider.of<ToDeliverBloc>(context);
this._getMoreData(1);
super.initState();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_getMoreData(page);
this.page++;
print(page);
}
});
}
_getMoreData(int page) async {
if (!isLoading) {
setState(() {
isLoading = true;
});
Map<String, dynamic> params = {'page': page, 'type': '0'};
_toDeliverBloc.inOrdersSink.add(LoadToDeliverCommand(params));
setState(() {
isLoading = false;
});
}
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
//resizeToAvoidBottomPadding: false,
body: StreamBuilder(
stream: _toDeliverBloc.outProgressOrders,
builder: (context, AsyncSnapshot<List<Order>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: CircularProgressIndicator(backgroundColor: Color(0xff185397),),
);
else if (snapshot.connectionState == ConnectionState.none) {
return Center(
child: Text(
'No data',
style: TextStyle(fontSize: 16.0),
),
);
} else {
if(snapshot.data!=null){
orders.addAll(snapshot.data);
if (orders.length > 0) {
return ListView.builder(
itemCount: orders.length+1,
controller: _scrollController,
itemBuilder: (BuildContext context, int index) {
if(index == orders.length)
return _buildProgressIndicator();
else{
return _orderItem(context, orders[index]);
}
});
} else {
return Center(
child: Text(
'No data',
style: TextStyle(fontSize: 16.0),
),
);
}
}
}
},
),
);
}
Widget _orderItem(BuildContext context, Order order) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 8),
child: GestureDetector(
onTap: () {
_toDeliverBloc.inOrdersSink.add(ToDeliverItemCommand(order));
//Navigator.pushNamed(context, "/order-detail");
},
child: Card(
elevation: 2.0,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.all(16.0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'${order.customerName}',
style: TextStyle(
color: Colors.black,
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
Text(
'${formatDate(order.orderDate)}',
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
color: Colors.black54),
),
],
)),
Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Order #${order.orderId}',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.normal,
color: Colors.black54)),
SizedBox(height: 8),
Text('Total \$${order.totalAmount}',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.normal,
color: Colors.black87)),
],
)),
ButtonTheme.bar(
// make buttons use the appropriate styles for cards
child: Container(
padding:
EdgeInsets.symmetric(horizontal: 16, vertical: 16),
color: const Color(0xffF2F2F4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(
Icons.directions_car,
color: Colors.black54,
),
SizedBox(
width: 8,
),
Text(
order.deliveryStatus == '0'
? 'pending deliver'
: order.deliveryStatus == '1'
? 'delivering'
: 'delivered',
style: TextStyle(
fontSize: 14,
color: Colors.black54,
fontWeight: FontWeight.normal),
)
],
),
Text(
order.paymentStatus == '0' ? 'unpaid' : 'paid',
style: TextStyle(
fontSize: 14,
color: Colors.redAccent,
fontWeight: FontWeight.bold),
)
],
)),
),
],
),
)),
);
}
Widget _buildProgressIndicator() {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Opacity(
opacity: isLoading ? 1.0 : 00,
child: new CircularProgressIndicator(backgroundColor: Color(0xff185397),),
),
),
);
}
}
второй элемент вкладки
class DeliveredScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() => DeliveredScreenState();
}
class DeliveredScreenState extends State<DeliveredScreen> {
ScrollController _scrollController = ScrollController();
DeliveredBloc _deliveredBloc;
int _page = 2;
bool isLoading = false;
List<Order> orders = [];
_loadMoreOrders(int page) {
if (!isLoading) {
setState(() {
isLoading = true;
});
Map<String, dynamic> params = {'page': page, 'type': '2'};
_deliveredBloc.inDoneOrdersSink.add(LoadDeliveredCommand(params));
setState(() {
isLoading = false;
});
}
}
@override
void initState() {
_deliveredBloc = BlocProvider.of<DeliveredBloc>(context);
_loadMoreOrders(1);
super.initState();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
_loadMoreOrders(_page);
_page++;
print("page >> ${_page}");
}
});
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
child: StreamBuilder(
stream: _deliveredBloc.outDoneOrders,
builder: (context, AsyncSnapshot<List<Order>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: CircularProgressIndicator(),
);
else if (snapshot.connectionState == ConnectionState.none) {
return Center(
child: Text(
'No data',
style: TextStyle(fontSize: 16.0),
),
);
} else {
print("orders >>>${snapshot.data.length}");
orders.addAll(snapshot.data);
if (orders.length > 0) {
return ListView.builder(
itemCount: isLoading==true ? orders.length+1:orders.length,
controller: _scrollController,
itemBuilder: (BuildContext context, int index) {
if (orders.length == index)
return _buildProgressIndicator();
else
return _orderItem(context, orders[index]);
},
);
} else {
return Center(
child: Text(
'No data',
style: TextStyle(fontSize: 16.0),
),
);
}
}
},
),
);
}
Widget _buildProgressIndicator() {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Center(
child: new Opacity(
opacity: isLoading ? 1.0 : 00,
child: new CircularProgressIndicator(
backgroundColor: Color(0xff185397),
),
),
),
);
}
Widget _orderItem(BuildContext context, Order order) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 4, horizontal: 8),
child: GestureDetector(
onTap: () {
//Navigator.pushNamed(context, "order-detail");
},
child: Card(
elevation: 2.0,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.all(16.0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'${order.customerName}',
style: TextStyle(
color: Colors.black,
fontSize: 16.0,
fontWeight: FontWeight.bold),
),
Text(
'${formatDate(order.orderDate)}',
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
color: Colors.black54),
),
],
)),
Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Order #${order.orderId}',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.normal,
color: Colors.black54)),
SizedBox(height: 8),
Text('Total \$${order.totalAmount}',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.normal,
color: Colors.black87)),
],
)),
ButtonTheme.bar(
// make buttons use the appropriate styles for cards
child: Container(
padding:
EdgeInsets.symmetric(horizontal: 16, vertical: 16),
color: const Color(0xffF2F2F4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(
Icons.directions_car,
color: Colors.black54,
),
SizedBox(
width: 8,
),
Text(
order.deliveryStatus == '0'
? 'pending deliver'
: order.deliveryStatus == '1'
? 'delivering'
: 'delivered',
style: TextStyle(
fontSize: 14,
color: Colors.black54,
fontWeight: FontWeight.normal),
)
],
),
Text(
order.paymentStatus == '0' ? 'unpaid' : 'paid',
style: TextStyle(
fontSize: 14,
color: Colors.redAccent,
fontWeight: FontWeight.bold),
)
],
)),
),
],
),
)),
);
}
}