I am relatively new to flutter_bloc, so forgive me if this is a simple question. I have a ListView.builder that renders out a list from my API, and my goal is to paginate this list. I have accomplished that, but the problem is that when I add new items to the list from my bloc, the entire ListView is rebuilt and the page jumps back up to the first item in the list.
Here is my bloc: I think the problem is that I am emitting the "MemesBlocLoaded" state at the end again? Or is it something else?
final ApiRepository apiRepository;
int page = 0;
MemesBlocBloc(this.apiRepository) : super(MemesBlocInitial()) {
on<GetMemesList>((event, emit) async {
try {
emit(MemesBlocLoading());
List memesList = await apiRepository.fetchMemes(page);
emit(MemesBlocLoaded(memesList));
page++;
on<GetMore>((event, emit) async {
emit(const MemesBlocLoadingMore(true));
List memesListMore = await apiRepository.fetchMemes(page);
memesList.addAll(memesListMore);
emit(const MemesBlocLoadingMore(false));
emit(MemesBlocLoaded(memesList));
page++;
});
} on NetworkError {
emit(const MemesBlocError("Failed to fetch data."));
}
});
}
}
Edited with the build method:
if (state is MemesBlocLoaded) {
return SingleChildScrollView(
child: Column(
children: [
ListView.builder(
primary: false,
shrinkWrap: true,
itemCount: state.memes.length,
itemBuilder: (context, index) {
return Stack(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.network(
state.memes[index].url,
width: double.infinity,
height: 400,
fit: BoxFit.cover,
),
),
),
Positioned(
right: 16,
bottom: 16,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.arrow_upward),
color: Colors.white,
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.arrow_downward),
color: Colors.white,
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.comment),
color: Colors.white,
),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.save_alt_outlined,
color: Colors.white,
)),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.share,
color: Colors.white,
)),
IconButton(
onPressed: () {},
icon: const Icon(Icons.report_outlined),
color: Colors.white,
),
Padding(
padding:
const EdgeInsets.only(right: 4.0),
child: GestureDetector(
onTap: () {
print('profile');
},
child: const CircleAvatar(
radius: 16,
backgroundImage: NetworkImage(
'https://images.unsplash.com/photo-1554151228-14d9def656e4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=686&q=80'),
)),
)
],
),
)
],
);
}),
state.memes.length >= 1
? state is MemesBlocLoadingMore
? const Center(
child: CircularProgressIndicator(
color: Colors.black),
)
: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white),
onPressed: () async {
context
.read<MemesBlocBloc>()
.add(GetMore());
},
child: const Text('View more',
style:
TextStyle(color: Colors.black))),
)
: const SizedBox()
],
),
);
}
I bought an online template app and i am trying to hardcode my email and password credentials in my flutter frontend because i don't have access to the backend api yet to change from email/password auth to phone auth, so i want to force code the logic into my flutter widget.
This means i am trying to implement the onPressed: () { controller.login(); }, function on a login button to get me to the home screen with my customized widget.
The original code given to me works fine when i hardcode the credentials in the text form field but when i hardcode the text form field in my customized widget and use same onPressed: () { controller.login(); }, function it don't work.
I want to know if it's because of i'm in a different state management or there's something i'm failing to do.
I will give the original code and my customized UI code in the snippets for comparison.
PS: i even tried to use same text form field in my widget but hide it with Visibility() in flutter. When i use Visibility() in the original code, onPressed: () { controller.login(); }, works but when i use it in my customized widget, it doest.
How do work around this? If you need more clarification, i am willing to offer. Thanks.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../../../common/helper.dart';
import '../../../../../common/ui.dart';
import '../../../../models/setting_model.dart';
import '../../../../routes/app_routes.dart';
import '../../../../services/settings_service.dart';
import '../../../global_widgets/block_button_widget.dart';
import '../../../global_widgets/circular_loading_widget.dart';
import '../../../global_widgets/text_field_widget.dart';
import '../../controllers/auth_controller.dart';
class LoginView extends GetView<AuthController> {
final Setting _settings = Get.find<SettingsService>().setting.value;
#override
Widget build(BuildContext context) {
controller.loginFormKey = new GlobalKey<FormState>();
return Visibility(
visible: false,
child: WillPopScope(
onWillPop: Helper().onWillPop,
child: Scaffold(
appBar: AppBar(
title: Text(
"Login".tr,
style: Get.textTheme.headline6
.merge(TextStyle(color: context.theme.primaryColor)),
),
centerTitle: true,
backgroundColor: Get.theme.colorScheme.secondary,
automaticallyImplyLeading: false,
elevation: 0,
),
body: Form(
key: controller.loginFormKey,
child: ListView(
primary: true,
children: [
Stack(
alignment: AlignmentDirectional.bottomCenter,
children: [
Container(
height: 180,
width: Get.width,
decoration: BoxDecoration(
color: Get.theme.colorScheme.secondary,
borderRadius:
BorderRadius.vertical(bottom: Radius.circular(10)),
boxShadow: [
BoxShadow(
color: Get.theme.focusColor.withOpacity(0.2),
blurRadius: 10,
offset: Offset(0, 5)),
],
),
margin: EdgeInsets.only(bottom: 50),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Text(
_settings.salonAppName,
style: Get.textTheme.headline6.merge(TextStyle(
color: Get.theme.primaryColor, fontSize: 24)),
),
SizedBox(height: 5),
Text(
"Welcome to the best salon service system!".tr,
style: Get.textTheme.caption.merge(
TextStyle(color: Get.theme.primaryColor)),
textAlign: TextAlign.center,
),
// Text("Fill the following credentials to login your account", style: Get.textTheme.caption.merge(TextStyle(color: Get.theme.primaryColor))),
],
),
),
),
Container(
decoration: Ui.getBoxDecoration(
radius: 14,
border:
Border.all(width: 5, color: Get.theme.primaryColor),
),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(10)),
child: Image.asset(
'assets/icon/icon.png',
fit: BoxFit.cover,
width: 100,
height: 100,
),
),
),
],
),
Obx(() {
if (controller.loading.isTrue)
return CircularLoadingWidget(height: 300);
else {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Visibility(
visible: false,
maintainState: true,
child: TextFieldWidget(
labelText: "Email Address".tr,
hintText: "johndoe#gmail.com".tr,
initialValue: 'salon#demo.com',
onSaved: (input) =>
controller.currentUser.value.email = input,
validator: (input) => !input.contains('#')
? "Should be a valid email".tr
: null,
iconData: Icons.alternate_email,
),
),
Obx(() {
return Visibility(
visible: false,
maintainState: true,
child: TextFieldWidget(
labelText: "Password".tr,
hintText: "••••••••••••".tr,
initialValue: '123456',
onSaved: (input) =>
controller.currentUser.value.password = input,
validator: (input) => input.length < 3
? "Should be more than 3 characters".tr
: null,
),
);
}),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Get.toNamed(Routes.FORGOT_PASSWORD);
},
child: Text("Forgot Password?".tr),
),
],
).paddingSymmetric(horizontal: 20),
BlockButtonWidget(
onPressed: () {
controller.login();
},
color: Get.theme.colorScheme.secondary,
text: Text(
"Login".tr,
style: Get.textTheme.headline6.merge(
TextStyle(color: Get.theme.primaryColor)),
),
).paddingSymmetric(vertical: 10, horizontal: 20),
TextButton(
onPressed: () {
//Get.toNamed(Routes.REGISTER);
},
child: Text("You don't have an account?".tr),
).paddingOnly(top: 20),
GestureDetector(
onTap: () {
Get.toNamed(Routes.SETTINGS_LANGUAGE);
},
child: Text(
Get.locale.toString().tr,
textAlign: TextAlign.center,
),
),
],
);
}
}),
],
),
),
),
),
);
}
}
THIS IS THE ORIGINAL WIDGET CODE
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../../routes/app_routes.dart';
import '../../../global_widgets/circular_loading_widget.dart';
import '../../../global_widgets/text_field_widget.dart';
import '../../controllers/auth_controller.dart';
import 'login_view.dart';
import 'pin_number.dart';
import 'keyboard_number.dart';
class PinScreen extends StatefulWidget {
const PinScreen({Key key}) : super(key: key);
#override
State<PinScreen> createState() => _PinScreenState();
}
class _PinScreenState extends State<PinScreen> {
List<String> currentPin = ["", "", "", ""];
TextEditingController pinOneController = TextEditingController();
TextEditingController pinTwoController = TextEditingController();
TextEditingController pinThreeController = TextEditingController();
TextEditingController pinFourController = TextEditingController();
var outlineInputBorder = OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Colors.transparent),
);
int pinIndex = 0;
#override
Widget build(BuildContext context) {
final controller = Get.find<AuthController>();
controller.loginFormKey = new GlobalKey<FormState>();
return Form(
key: controller.loginFormKey,
child: SafeArea(
child: Column(
children: [
buildExitButton(),
Obx(() {
if (controller.loading.isTrue)
return CircularLoadingWidget(height: 300);
else {
return Expanded(
child: Container(
alignment: Alignment(0, 0.5),
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
buildSecurityText(),
SizedBox(height: 20.0),
buildPinRow(),
SizedBox(height: 10.0),
buildNumberPad(),
SizedBox(height: 20.0),
Visibility(
visible: false,
maintainState: true,
child: TextFieldWidget(
labelText: "Email Address".tr,
hintText: "johndoe#gmail.com".tr,
initialValue: 'salon#demo.com',
validator: (input) => !input.contains('#')
? "Should be a valid email".tr
: null,
iconData: Icons.alternate_email,
),
),
Obx(() {
return Visibility(
visible: false,
maintainState: true,
child: TextFieldWidget(
labelText: "Password".tr,
hintText: "••••••••••••".tr,
initialValue: '123456',
validator: (input) => input.length < 3
? "Should be more than 3 characters".tr
: null,
iconData: Icons.lock_outline,
keyboardType: TextInputType.visiblePassword,
suffixIcon: IconButton(
onPressed: () {
controller.hidePassword.value =
!controller.hidePassword.value;
},
color: Theme.of(context).focusColor,
icon: Icon(controller.hidePassword.value
? Icons.visibility_outlined
: Icons.visibility_off_outlined),
),
),
);
}),
Container(
child: new RichText(
text: new TextSpan(
children: [
new TextSpan(
recognizer: TapGestureRecognizer()
..onTap = () {
// Get.toNamed(Routes.REGISTER);
},
text: 'Forgot Pin ?',
style: new TextStyle(
color: Color(0xff3498DB),
fontSize: 14,
fontWeight: FontWeight.w500),
),
],
),
),
),
SizedBox(height: 20.0),
MaterialButton(
onPressed: () {
controller.login();
},
color: Color(0xff34495E),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.18),
),
padding: EdgeInsets.symmetric(
horizontal: 30, vertical: 10),
minWidth: double.infinity,
child: Text(
'Next',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600),
),
),
SizedBox(height: 32.0),
],
),
),
);
}
})
],
),
),
);
}
buildNumberPad() {
return Expanded(
child: Container(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
KeyboardNumber(
n: 1,
onPressed: () {
pinIndexSetup("1");
},
),
KeyboardNumber(
n: 2,
onPressed: () {
pinIndexSetup("2");
},
),
KeyboardNumber(
n: 3,
onPressed: () {
pinIndexSetup("3");
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
KeyboardNumber(
n: 4,
onPressed: () {
pinIndexSetup("4");
},
),
KeyboardNumber(
n: 5,
onPressed: () {
pinIndexSetup("5");
},
),
KeyboardNumber(
n: 6,
onPressed: () {
pinIndexSetup("6");
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
KeyboardNumber(
n: 7,
onPressed: () {
pinIndexSetup("7");
},
),
KeyboardNumber(
n: 8,
onPressed: () {
pinIndexSetup("8");
},
),
KeyboardNumber(
n: 9,
onPressed: () {
pinIndexSetup("9");
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: 60.0,
child: MaterialButton(
onPressed: null,
child: SizedBox(),
),
),
KeyboardNumber(
n: 0,
onPressed: () {
pinIndexSetup("0");
},
),
Container(
width: 60.0,
child: MaterialButton(
onPressed: () {
clearPin();
},
height: 60.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(60.0),
),
child: Image.asset(
'assets/icon/clear-symbol.png',
),
),
)
],
),
],
),
),
),
);
}
clearPin() {
if (pinIndex == 0)
pinIndex = 0;
else if (pinIndex == 4) {
setPin(pinIndex, "");
currentPin[pinIndex - 1] = "";
pinIndex--;
} else {
setPin(pinIndex, "");
currentPin[pinIndex - 1] = "";
pinIndex--;
}
}
pinIndexSetup(String text) {
if (pinIndex == 0)
pinIndex = 1;
else if (pinIndex < 4) pinIndex++;
setPin(pinIndex, text);
currentPin[pinIndex - 1] = text;
String strPin = "";
currentPin.forEach((e) {
strPin += e;
});
if (pinIndex == 4) print(strPin);
}
setPin(int n, String text) {
switch (n) {
case 1:
pinOneController.text = text;
break;
case 2:
pinTwoController.text = text;
break;
case 3:
pinThreeController.text = text;
break;
case 4:
pinFourController.text = text;
break;
}
}
buildExitButton() {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: MaterialButton(
onPressed: () {
Navigator.pop(context);
},
height: 50.0,
minWidth: 50.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
child: Icon(
Icons.clear,
color: Colors.black54,
),
),
),
],
);
}
buildSecurityText() {
return Column(
children: [
Align(
alignment: Alignment.topLeft,
child: Text(
'Enter PIN',
style: TextStyle(
color: Color(0xff151515),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(
height: 12,
),
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(right: 80),
child: Text(
'Enter 4 digit PIN to access your account ',
style: TextStyle(
color: Color(0xff151515),
fontSize: 14,
fontWeight: FontWeight.w500,
fontStyle: FontStyle.normal,
),
),
),
),
],
);
}
buildPinRow() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
PINNumber(
outlineInputBorder: outlineInputBorder,
textEditingController: pinOneController,
),
PINNumber(
outlineInputBorder: outlineInputBorder,
textEditingController: pinTwoController,
),
PINNumber(
outlineInputBorder: outlineInputBorder,
textEditingController: pinThreeController,
),
PINNumber(
outlineInputBorder: outlineInputBorder,
textEditingController: pinFourController,
),
],
);
}
}
THIS IS MY CUSTOMIZED WIDGET TREE/CODE
I'm currently trying to create a row that consist of maximum 3 column widget with each of them have the property of profile picture, nickname, and status. I wanted each of them to have fixed size so that even when the nickname is long it will still take the same amount of space.
Currently I just make the column to be spaced-evenly and some of the widget still take more space than the other 2. How can I fixed this ? maybe make the nickname turned into dotted (...) when it's too long.
here's my current code:
solverWidgets.add(
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
BuildRoundedRectProfile(
height: 40,
width: 40,
name: solverTicket[solver]['nickname'],
profileLink: solverTicket[solver]['profile_picture_link'] ?? '',
),
SizedBox(height: 3),
Text(
solverTicket[solver]['nickname'],
style: weight600Style.copyWith(
color: primaryColor,
fontSize: 13,
),
),
if (solversStatus[solver] != null && (povStatus == 'pic' || povStatus == 'pic-client'))
GestureDetector(
onTap: () {
if (solversStatus[solver] == 'Done') {
setState(() {
needToLoadSolverWidgets = true;
isNotExpandedSolverWidgets[solver] = !isNotExpandedSolverWidgets[solver];
});
if (isExpandedSolverWidgetsContent[solver]) {
Future.delayed(Duration(milliseconds: 300), () {
setState(() {
needToLoadSolverWidgets = true;
isExpandedSolverWidgetsContent[solver] = false;
});
});
} else {
setState(() {
needToLoadSolverWidgets = true;
isExpandedSolverWidgetsContent[solver] = true;
});
}
}
},
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
height: isNotExpandedSolverWidgets[solver] ? 20 : 55,
padding: EdgeInsets.only(top: 5, bottom: 5, left: 5, right: 5),
decoration: BoxDecoration(
color: defaultProfileColor.withOpacity(0.2),
borderRadius: BorderRadius.circular(10),
),
child: solversStatus[solver] != 'Done' ?
Text(
solversStatus[solver],
style: primaryColor600Style.copyWith(
fontSize: fontSize9,
),
).tr() : isNotExpandedSolverWidgets[solver] ?
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
solversStatus[solver],
style: primaryColor600Style.copyWith(
fontSize: fontSize10,
),
).tr(),
Icon(
Icons.arrow_drop_down,
size: fontSize15,
),
],
) : ClipRRect(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
children: [
Text(
solversStatus[solver],
style: primaryColor600Style
.copyWith(
fontSize: fontSize9,
),
).tr(),
Icon(
Icons.arrow_drop_down,
size: fontSize18,
),
],
),
GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (BuildContext
context) =>
ReusableConfirmationDialog(
titleText: 'changeWorkStatus'.tr(),
contentText: 'rejectWorkStatus'.tr(),
confirmButtonText: 'yes'.tr(),
onConfirm: () async {
await Database.changeWorkStatus(
ticketId: widget.ticketId,
ticketData: ticketData,
targetId: solver as String,
oldWorkStatus: 'done',
workStatus: 'todo');
Navigator.pop(context);
setState(() {
isNotExpandedSolverWidgets[solver] = true;
needToLoadTicket = true;
});
}));
},
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
color: warningColor,
borderRadius:
BorderRadius.circular(5),
),
child: Text(
'disagree',
style: primaryColor600Style
.copyWith(
fontSize: fontSize9,
color: Colors.white,
),
).tr(),
),
)
]),
),
),
),
if(solversStatus[solver] != null && (povStatus != 'pic' && povStatus != 'pic-client'))
Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
color: formBackgroundColor,
borderRadius: BorderRadius.all(
Radius.circular(10))),
child: Text(
solversStatus[solver],
style: weight600Style.copyWith(
color: primaryColor,
fontSize: 9,
),
),
),
],
),
);
use Text overflow
Text(
'You have pushed the button this many times:dfjhejh dskfjkawejfkjadshfkljhaskdfhekjnkjvnkjasdklfjjekjlkj',
maxLines: 1,
overflow: TextOverflow.ellipsis,
)
or You can use https://pub.dev/packages/marquee package, it will scroll your text infinitly. make sure to wrap this marquee widget in a sizedbox with height and width defined.
I'm new to the flutter and I don't know how to solve this problem.
I have a List with await method, but my screen does not await for the list to load to list, only when I update with the hot-reload, the screen works.
My async method
ListaRefeitorio? _selecione;
List<ListaRefeitorio> _refeitorios = <ListaRefeitorio>[];
RefeitorioController controller = new RefeitorioController();
#override
void initState() {
super.initState();
_listarRefeitorios();
}
My Screen
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBarControleAcessoWidget("Refeitório"),
body: Column(
children: [
SizedBox(height: 30),
Container(
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.only(left: 16, right: 16),
decoration: BoxDecoration(
border:
Border.all(color: AppColors.chartSecondary, width: 1),
borderRadius: BorderRadius.circular(15),
),
child: DropdownButton<ListaRefeitorio>(
hint: Text("Selecione Refeitório"),
dropdownColor: AppColors.white,
icon: Icon(Icons.arrow_drop_down),
iconSize: 36,
isExpanded: true,
underline: SizedBox(),
style: TextStyle(
color: AppColors.black,
fontSize: 20,
),
value: _selecione,
onChanged: (ListaRefeitorio? novoValor) {
setState(() {
_selecione = novoValor;
});
},
items: _refeitorios.map((ListaRefeitorio valueItem) {
return new DropdownMenuItem<ListaRefeitorio>(
value: valueItem,
child: new Text(valueItem.acessoPontoAcessoDescricao),
);
}).toList(),
),
),
),
),
),
Container(),
Expanded(
child: GridView.count(
crossAxisSpacing: 12,
mainAxisSpacing: 12,
crossAxisCount: 2,
children: [
Container(
child: SizedBox.expand(
child: FlatButton(
child: CardsWidget(
label: "Ler QR Code",
imagem: AppImages.scanQrCode,
),
onPressed: () {
scanQRCode();
},
),
),
),
Container(
child: SizedBox.expand(
child: FlatButton(
child: CardsWidget(
label: "Sincronizar Dados", imagem: AppImages.sync),
onPressed: () {
controller.sincronizar();
// RefeitorioService.listarRefeitorio();
},
),
),
),
SizedBox(height: 30),
Text("Resultado"),
Text(QRCode),
Text(DataHora),
Text(_selecione.toString()),
],
),
),
],
));
}
I've tried using the futurebuilder but I don't think that's my problem.
I don't know what to do anymore
I had the same issue with the DropDownButton list only displaying because of the Hot Reload refreshing the state.
When using a custom mapping of a List remember to use setState() in the method that populates the List with data (in my case it was pulling from Sqflite).
//This populate method would be called in either initstate or afterFirstLayout
populateDataList() {
await controller.getList().then((list) =>
setState(() {
_refeitorios = list;
})
);
}
I am trying to dynamically add a card in a row in my app after pressing a button.
I tried different things but nothing seems to work properly, right now I reached this point:
cardList = [];
setState(() {
cardList.add(new DynamicCard());
});
}
This is the method that I call to add a new card and it is called in the following alertDialog:
return Alert(
context: context,
title: "Add activity",
content: Column(
children: <Widget>[
DropdownButton(
hint: Text('Select your activity'),
icon: Icon(Icons.arrow_drop_down),
value: selectedActivity,
onChanged: (value){
setState(() {
value = selectedActivity;
print(value);
});
},
//value: selectedActivity,
items: activityList.map((value) {
return DropdownMenuItem(
value: value,
child: Text(value));
}).toList()
),
TextField(
decoration: InputDecoration(
labelText: 'Where',
),
),
],
),
buttons: [
DialogButton(
onPressed: () {
addCard();
Navigator.pop(context);
},
child: Text(
"Add Activity",
style: TextStyle(color: Colors.white, fontSize: 20),
),
)
]).show();
This is the card I'd like to add after pressing on the button:
import 'package:flutter/material.dart';
import 'package:wildnature/widgets/sizeConfig.dart';
class DynamicCard extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SizedBox(
height: 250,
width: 350,
child: Card(
elevation: 6,
clipBehavior: Clip.antiAlias,
child: Column(
children: [
ListTile(
title: Text('Last Activity:'),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Test123',
style:
TextStyle(fontSize: 5 * SizeConfig.blockSizeHorizontal),
)),
Container(
width: 200,
height: 160,
child: Image.asset('assets/camping.png', fit: BoxFit.fill),
)
],
),
),
);
}
}
Also, how can I render this widget in the exact place I want it to be?
Solution:
Created a new variable:
bool addWidget = false;
created a new widget:
Widget createActivityCard(String activy, String activityDesc){
return SizedBox(
height: 250,
width: 350,
child: Card(
elevation: 6,
clipBehavior: Clip.antiAlias,
child: Column(
children: [
ListTile(
title: Text(activy),
),
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
activityDesc,
style:
TextStyle(fontSize: 5 * SizeConfig.blockSizeHorizontal),
)),
Container(
width: 200,
height: 160,
child: Image.asset('assets/camping.png', fit: BoxFit.fill),
)
],
),
),
);
}
Set the value of addWidget to 'true' when pressing on a button
Added a simple if statement where the condition is addWidget:
if(addWidget)
Container(
child: createActivityCard('Added by user', 'WE DID IT'))
```