Как использовать два и более провайдера для одного виджета, в одном и том же месте кода?
Как я мог бы использовать два и более провайдера для изменения состояния виджета?
К примеру, у меня есть мобильное приложение (магазин одежды). В нем есть категории товаров. Как мне для товаров, находящихся в разных категориях использовать один и тот же код, присваивающий товару, при нажатии на товар: название, изображение, описание.
Надеюсь, что смог грамотно объяснить свою проблему. Ниже оставлю код для присваивания товару названия и изображения. Комментариями отмечены места в коде, где я хочу использовать вариативность.
Я думаю, что это можно реализовать, если приложение будет проверять состояние экрана. То есть: когда пользователь свайпает на экран с одним товаром, приложение детектит экран и присваивает товарам название, описание и тд., те которые должны быть на данном экране. Точно по такому же принципу происходило бы присваивание для товаров в других категориях, на других экранах.
import 'package:flutter/material.dart';
import 'package:lvmarketapn/providers/women/wbags_data_provider.dart';
import 'package:provider/provider.dart';
import '../../constants.dart';
// ignore: must_be_immutable
class ProductTitleWithImage extends StatelessWidget {
final String wBagId;
final String wJewellId;
ProductTitleWithImage({Key key, this.wBagId, this.wJewellId})
: super(key: key);
@override
Widget build(BuildContext context) {
final wBags = Provider.of<WBags>(context).getWbag(wBagId);
final wJewells = Provider.of<WJewellery>(context).getWjewell(wJewellId); //!!!
return Padding(
padding: const EdgeInsets.symmetric(horizontal: lDP, vertical: lDP),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 10.0),
child: Text(
// I want it shows this provider values when user swipe to special screen
wBags.title,
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontWeight: FontWeight.bold, color: lTC),
//!!!
// And I want it shows another provider values when user swipe to another special page
// For example :
// wJewells.title,
// style: Theme.of(context)
// .textTheme
// .headline6
// .copyWith(fontWeight: FontWeight.bold, color: lTC),
),
),
SizedBox(height: lDP),
Row(
children: <Widget>[
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Price\n',
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontWeight: FontWeight.bold, color: lTC),
),
TextSpan(
// I want it shows this provider values when user swipe to special screen
text: '\$${wBags.price}',
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontWeight: FontWeight.bold, color: lTC),
//!!!
// And I want it shows another provider values when user swipe to another special //page
// For example :
/* text: '\$${wJewells.price}',
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontWeight: FontWeight.bold, color: lTC),*/
)
],
),
),
SizedBox(
width: lDP,
),
Expanded(
child: Hero(
// I want it shows this provider values when user swipe to special screen
tag: '${wBags.id}',
child: Image.asset(
wBags.image,
fit: BoxFit.cover,
//!!!
// And I want it shows another provider values when user swipe to another special //page
// For example :
// tag: '${wJewells.id}',
// child: Image.asset(
// wBags.image,
// fit: BoxFit.cover,
),
),
),
],
),
],
),
);
}
}
Ответы (2 шт):
Что тут происходит:
- Я сделал абстрактный класс, с общими полями и методами
- Реализовал его в WBags и WJewellery
- Через Generic пропихнул его в виджет
- И использовал его общие поля и методы
- При регистрации в provider, я использовал реализованные WBags и WJewellery
- При использовании в виджете я явно указываю нужный мне тип (на данном этапе вы знаете какой вам нужен тип, по этому сможете его подставить)
Примерно так будет:
abstract class WProduct {
const WProduct(this.id, this.title, this.price, this.image);
final String id;
final String title;
final String price;
final String image;
void getById(String id);
}
class WBags extends WProduct {
const WBags(String id, String title, String price, String image) : super(id, title, price, image);
@override
void getById(String id){
// ...
}
}
class WJewellery extends WProduct {
const WJewellery(String id, String title, String price, String image) : super(id, title, price, image);
@override
void getById(String id){
// ...
}
}
Виджет:
class ProductTitleWithImage<T extends WProduct> extends StatelessWidget {
final String id;
ProductTitleWithImage({Key key, this.id}) : super(key: key);
@override
Widget build(BuildContext context) {
final WProduct wProduct = Provider.of<T>(context).getById(id);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: lDP, vertical: lDP),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 10.0),
child: Text(
wProduct.title,
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontWeight: FontWeight.bold, color: lTC),
),
),
SizedBox(height: lDP),
Row(
children: <Widget>[
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Price\n',
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontWeight: FontWeight.bold, color: lTC),
),
TextSpan(
text: '\$${wProduct.price}',
style: Theme.of(context)
.textTheme
.headline6
.copyWith(fontWeight: FontWeight.bold, color: lTC),
)
],
),
),
SizedBox(
width: lDP,
),
Expanded(
child: Hero(
tag: '${wProduct.id}',
child: Image.asset(
wProduct.image,
fit: BoxFit.cover,
),
),
),
],
),
],
),
);
}
}
Регистрация в provider:
Provider(
create: (_) => WBags(),
child: ...
)
...
Provider(
create: (_) => WJewellery(),
child: ...
)
Использование:
ProductTitleWithImage<WBags>(id:...)
...
ProductTitleWithImage<WJewellery>(id:...)
Думаю стоит использовать класс MultiProvider
Пример:
MultiProvider(
providers: [
Provider<Something>(create: (_) => Something()),
Provider<SomethingElse>(create: (_) => SomethingElse()),
Provider<AnotherThing>(create: (_) => AnotherThing()),
],
child: someWidget,
)