I'm currently writing a flashcard app. The texts in the cards are supplied from a List<String>. Now, I want to make two buttons for tagging card with "Easy" and "Difficult" respectively. From here, I want to be able to categorize them and give the user options to show only those tagged with Easy or only Difficult or etc.
My problem is I don't know how to "connect" the buttons to the List, e.g. how will the button tag the card since each card is generated with a PageView.builder from said List. Is there a way to let the app know which element of the List is currently shown on the card so that the button know what to tag?
I'm lost.
Here is the simplified code of the app.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: const MyHomePage(),
theme: ThemeData(primarySwatch: Colors.deepOrange),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView.builder(
itemCount: KontenModeFlashcards.teksDepan.length,
itemBuilder: (context, index) {
final isiTeksDepan = KontenModeFlashcards.teksDepan[index];
return PageView(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
isiTeksDepan,
),
],
),
],
);
},
),
);
}
}
// the list of texts that will go in the cards
class KontenModeFlashcards {
static const List<String> teksDepan = [
'text 1',
'text 2',
'text 3',
];
}
Thanks in advance!
CodePudding user response:
First let's fix the data structure, change the type of teksDepan from List<String> to List<Map<String, dynamic>>, so that it will list maps and that can be used to store the "difficulty-level" (you can set the difficulty level to be a bool "isEasy", as well). It will look something like this:
class KontenModeFlashcards {
static const List<Map<String, dynamic>> teksDepan = [
{'text': 'text 1', 'isEasy': true},
{'text': 'text 2', 'isEasy': true},
{'text': 'text 3', 'isEasy': true},
];
}
Now that you have a right structure for the data you can now use that in your UI, like this:
@override
Widget build(BuildContext context) {
return SafeArea(
child: PageView.builder(
itemCount: KontenModeFlashcards.teksDepan.length,
itemBuilder: (BuildContext context, int index) {
String? text = KontenModeFlashcards.teksDepan[index]['text'];
bool isEasy = KontenModeFlashcards.teksDepan[index]['isEasy'] ?? false;
return PageView(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Card(
child: ListTile(
contentPadding: const EdgeInsets.all(12),
trailing: Icon(
isEasy ? Icons.cake : Icons.anchor,
),
title: Text(text ?? 'No Text was provided'),
subtitle: ElevatedButton.icon(
onPressed: () {
setState(() {
KontenModeFlashcards.teksDepan[index]['isEasy'] = !isEasy;
});
},
icon: isEasy
? const Icon(Icons.anchor)
: const Icon(Icons.cake),
label: Text(isEasy ? 'Difficult' : 'Easy'),
),
),
),
],
),
],
);
},
),
);
}
);
Make sure your MyHomePage is Stateful Widget. Which you can do by right clicking on where it says StatelessWidget (on the same line) and select Refactor... and then Convert to StatefulWidget.
I think that should do it. Let me know if you have any more questions, or if you want me to simply something.
This code include Offstage toggle feature:
@override
Widget build(BuildContext context) {
return SafeArea(
child: PageView.builder(
itemCount: KontenModeFlashcards.teksDepan.length,
itemBuilder: (BuildContext context, int index) {
String? text = KontenModeFlashcards.teksDepan[index]['text'];
bool isEasy = KontenModeFlashcards.teksDepan[index]['isEasy'] ?? false;
return PageView(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Offstage(
offstage: !isEasy,
child: Card(
child: ListTile(
contentPadding: const EdgeInsets.all(12),
trailing: Icon(
isEasy ? Icons.cake : Icons.anchor,
),
title: Text(text ?? 'No Text was provided'),
),
),
),
ElevatedButton.icon(
onPressed: () {
setState(() {
KontenModeFlashcards.teksDepan[index]['isEasy'] = !isEasy;
});
},
icon: isEasy
? const Icon(Icons.cake)
: const Icon(Icons.anchor),
label: Text(isEasy ? 'Easy' : 'Difficult'),
),
],
),
],
);
},
),
);
}
The reason it hiding when it was set to Difficult was because that how I had set it up in the ElevatedButton widget you can review at by comparing the two code snippets.
