Home > OS >  Deleting Items in ListView not working properly
Deleting Items in ListView not working properly

Time:01-13

I'm trying to delete multiple items in a ListView after selecting them. Everything is working fine, the problem comes when I finish the deletion process. I can see that the items were deleted but the widgets in place are still highlighted.

Here is my code for the App:

class MultiSelect extends StatefulWidget {
  const MultiSelect({super.key});

  @override
  State<MultiSelect> createState() => _MultiSelectState();
}

class _MultiSelectState extends State<MultiSelect> {
  late List<Transaction> selectedTransactions;

  @override
  void initState() {
    super.initState();

    HiveAPI.loadTransactions();

    selectedTransactions = [];
  }

  void select(bool value, VoidCallback callback, Transaction item) {
    setState(() {
      value
          ? selectedTransactions.remove(item)
          : selectedTransactions.add(item);
      callback();
    });
  }

  void delete() {
    setState(() {
      HiveAPI.deleteTransaction(selectedTransactions);
      selectedTransactions = [];
      HiveAPI.loadTransactions();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Multi Select Example"),
        actions: <Widget>[
          IconButton(
            icon: const Icon(Icons.delete),
            onPressed: () {
              delete();
            },
          ),
        ],
      ),
      body: ListView.builder(
          itemCount: HiveAPI.transactions.length,
          itemBuilder: (context, index) {
            return CustomCard(
              onPress: (value, callback) =>
                  select(value, callback, HiveAPI.transactions[index]),
              transaction: HiveAPI.transactions[index],
            );
          }),
    );
  }
}

This is the code to my custom widget inside the ListView:

class CustomCard extends StatefulWidget {
  const CustomCard({
    Key? key,
    required this.transaction,
    required this.onPress,
  }) : super(key: key);

  final Transaction transaction;
  final Function(bool, VoidCallback) onPress;

  @override
  State<CustomCard> createState() => _CustomCardState();
}

class _CustomCardState extends State<CustomCard> {
  late bool selected;

  @override
  void initState() {
    super.initState();

    selected = false;
  }

  void updateUI() => setState(() => selected = !selected);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () => widget.onPress(selected, updateUI),
      child: Container(
        padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 8.0),
        decoration: BoxDecoration(
          color: selected ? Colors.lime.shade100 : Colors.transparent,
          borderRadius: const BorderRadius.all(Radius.circular(16)),
        ),
        child: Row(
          children: [
            Container(
              padding: const EdgeInsets.all(8.0),
              decoration: BoxDecoration(
                color: selected ? Colors.lime : Colors.black,
                borderRadius: const BorderRadius.all(Radius.circular(200)),
              ),
              child: Icon(
                selected ? Icons.check : Icons.wallet,
                color: selected ? Colors.black : Colors.white,
              ),
            ),
            const SizedBox(width: 8),
            Text(
              widget.transaction.title,
              style: Theme.of(context).textTheme.bodyText2,
            ),
          ],
        ),
      ),
    );
  }
}

My code for the HiveAPI and Transaction class:

class HiveAPI {
  static const String boxKey = 'transactionBox';
  static const String transactionsDataKey = 'transactions';

  static final box = Hive.box(boxKey);
  static final List<Transaction> transactions = [];

  static void loadTransactions() {
    for (var transaction in box.get(transactionsDataKey)) {
      transactions.add(
        Transaction(
          transaction[0],
          transaction[1],
          transaction[2],
          transaction[3],
          transaction[4],
        ),
      );
    }
  }

  static void _updateTransactions() {
    final List transactionsPrimitive = [];

    for (var transaction in transactions) {
      transactionsPrimitive.add([
        transaction.title,
        transaction.category,
        transaction.amount,
        transaction.type,
        transaction.date,
      ]);
    }

    box.put(transactionsDataKey, transactionsPrimitive);
  }

  static void deleteTransaction(List<Transaction> selectedTransaction) {
    transactions.removeWhere((item) => selectedTransaction.contains(item));

    _updateTransactions();
  }

}
class Transaction {
  late String title;
  late String category;
  late double amount;
  late int type;
  late DateTime date;

  Transaction(this.title, this.category, this.amount, this.type, this.date);
}

This is the list before deleting List before deletion

This is the list after deleting List after deletion

CodePudding user response:

You need to use Key if you want to move or delete item in ListView.

For example:

return CustomCard(
              key:Key(HiveAPI.transactions[index].title),
              onPress: (value, callback) =>
                  select(value, callback, HiveAPI.transactions[index]),
              transaction: HiveAPI.transactions[index],
            );

or use other unique key if the title isn't unique

  • Related