Flutter: tinder likes cards without a stack

158 views Asked by At

I am developing a language learning quiz app. The person selects a topic (30 words) and I make a request to the server via the API to get a list of translations and transcriptions.

Because it takes a long time to get the data, I want to only get data for a couple of words. The first card is shown, and the second is already loaded. When the user has worked with the first one (swipe it), the second one appears, and the data for the third one is loaded in parallel.

How can you get data like that? All tinder-cards widgets request a stack, i.e. already prepared data. In my case, this is not allowed.

I'm assuming it should look like this: displaying not a stack but only a single card like this

1

There are 1 answers

2
Tuan On

Ui with stack is fine, you need to do a little bit with fetch data logic, using Future, List and setState.

Example: when i swipe, the top data object was swiped and new data object was create at the last (begin fetch and seft setState when done).

import 'package:flutter/material.dart';
import 'dart:math';

void main() => runApp(MaterialApp(home: MyApp()));

class MyApp extends StatefulWidget {
  final int cardSizes = 3;

  @override
  MyAppState createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
  var datas = <AGirl>[];

  @override
  void initState() {
    // generate stack when init
    datas = List.generate(widget.cardSizes, (_) => getNewGirl());
  }

  // function that return a AGirl and register a `setState` when data fetched
  AGirl getNewGirl() => AGirl()..fetch().then((_) => setState(() {}));

  // function that `swipe` top data object and add new unfetched data object at the last
  void swipe() {
    datas.removeAt(0);
    datas.add(getNewGirl());
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: renderCards(),
      ),
    );
  }

  List<Widget> renderCards() {
    render(AGirl data, int index) {
      return Positioned(
        left: index * 200,
        child: SizedBox(
          width: 200,
          height: 300,
          child: Card(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                Text('Card $index'),
                Text('AGirl id ${data.id}'),
                data.hasData
                    ? const Center(child: Text('loaded'))
                    : const CircularProgressIndicator(),
                ElevatedButton(
                  onPressed: index == 0 ? swipe : null,
                  child: const Text('swipe'),
                ),
              ],
            ),
          ),
        ),
      );
    }

    return datas.reversed
        .map((data) => render(data, datas.indexOf(data)))
        .toList();
  }
}

class AGirl {
  final int id;
  dynamic data;
  AGirl() : id = Random().nextInt(99999);
  bool get hasData => data != null;

  Future<AGirl> fetch() async {
    await Future.delayed(const Duration(milliseconds: 1000));
    data = {};
    return this;
  }
}

enter image description here