Lärm: kuidas viktoriinimängu üles ehitada

UPDATE (01.06.2019): alternatiivse versiooni leiate ümberehituspaketi abil siit.

Sissejuhatus

Selles artiklis tahaksin teile näidata, kuidas ma lõin selle trivia mängu näite koos Flutteri ja frideos-paketiga (vaadake neid kahte näidet, et teada saada, kuidas see töötab näide1, näide2). See on üsna lihtne mäng, kuid hõlmab erinevaid huvitavaid argumente.

Rakendusel on neli ekraani:

  • Pealeht, kus kasutaja valib kategooria ja alustab mängu.
  • Seadete leht, kus kasutaja saab valida küsimuste arvu, andmebaasi tüübi (kohalik või kaughaldus), iga küsimuse tähtaja ja raskused.
  • Trivia leht, kus kuvatakse küsimused, punktisumma, paranduste, eksimuste arv ja vastamata jätmine.
  • Kokkuvõttev leht, kus kuvatakse kõik küsimused koos õigete / valede vastustega.

See on lõpptulemus:

Paremat gifit näete siit.
  • 1. osa: projekti seadistamine
  • 2. osa: rakenduse arhitektuur
  • 3. osa: API ja JSON
  • 4. osa: koduleht ja muud ekraanid
  • 5. osa: TriviaBloc
  • 6. osa: animatsioonid
  • 7. osa: kokkuvõtte leht
  • Järeldus
1. osa - projekti seadistamine

1 - looge uus laperdusprojekt:

loksutage oma_projekti_nimi loomiseks

2 - redigeerige faili „pubspec.yaml” ja lisage paketid http ja frideos:

sõltuvused:
  laperdus:
    sdk: laperdus
  http: ^ 0.12.0
  frideod: ^ 0.6.0

3 - Kustutage faili main.dart sisu

4. Looge projekti struktuur järgmise pildina:

Struktuuri üksikasjad

  • API: siin on noolefailid, mis käsitlevad avatud trivia andmebaasi API-d, ja piltide API kohalikuks testimiseks: api_interface.dart, mock_api.dart, trivia_api.dart.
  • Blokid: rakenduse trivia_bloc.dart ainsa BLoC-i koht.
  • Mudelid: appstate.dart, category.dart, models.dart, question.dart, theme.dart, trivia_stats.dart.
  • Ekraanid: main_page.dart, settings_page.dart, summary_page.dart, trivia_page.dart.
2. osa - rakenduste arhitektuur

Oma viimases artiklis kirjutasin erinevatest viisidest andmete saatmiseks ja jagamiseks mitme vidina ja lehe vahel. Sel juhul hakkame kasutama pisut keerukamat lähenemisviisi: vidinapuule pakutakse üksikklassi AppState nimega eksemplari InheritedWidget pakkuja (AppStateProvider) abil, see hoiab rakenduse olekut, mõni ettevõte loogika ja ainus BLoC, mis tegeleb rakenduse viktoriini osaga. Nii et lõpuks on see omamoodi segu singletoni ja BLoC mustri vahel.

Iga vidina sees on võimalik saada AppState klassi eksemplar helistades:

final appState = AppStateProvider.of  (kontekst);

1 - main.dart

See on rakenduse sisenemispunkt. Klass Appis on kodakondsuseta vidin, kus see kuulutatakse AppState klassi eksemplariks ja kus see, kasutades rakendust AppStateProvider, edastatakse siis vidinate puule. AppState eksemplar utiliseeritakse, sulgedes kõik vood, AppStateProvideri klassi dispositsioonimeetodis.

MaterialApp-vidin mähitakse ValueBuilderi vidina sisse nii, et iga uue teema valimisel taastatakse kogu vidinate puu, ajakohastades seda teemat.

2 - Riigi juhtimine

Nagu varem öeldud, hoiab appState eksemplar rakenduse olekut. Seda klassi kasutatakse:

  • Seadistused: kasutatav teema, laadige / salvestage see SharedPreferences abil. API rakendamine, pilkav või kaugjuhtimispult (kasutades saidi opentdb.com API-d). Igale küsimusele määratud aeg.
  • Kuvatakse praegune sakk: avaleht, tühiasi, kokkuvõte.
  • Küsimuste laadimine.
  • (kui serveri API-l) Salvestage küsimuste kategooria, arvu ja raskuse seaded.

Klassi konstruktoris:

  • _createThemes ehitab rakenduse teemad.
  • _loadCategories laadib avalehe rippmenüüsse valitud küsimuste kategooriad.
  • countdown on tüüpi frideos-paketi StreamedTransformeeritud vorming, mida kasutatakse tekstiväljalt loenduri väärtuse saamiseks.
  • questionsAmount sisaldab trivia mängu ajal kuvatavate küsimuste arvu (vaikimisi 5).
  • ClassTriviaBloci eksemplar initsialiseeritakse, suunates sinna voogedastamise, küsimuste loendi ja kuvatava lehe.
3. osa - API ja JSON

Lubamaks kasutajal valida kohaliku ja kaugandmebaasi vahel, lõin QuestionApi liidese kahe meetodi ja kahe seda rakendava klassiga: MockApi ja TriviaApi.

abstraktse klassi küsimusedAPI {
  Tulevased  getCategories (StreamedList  kategooriad);
  
  Tulevased  saadaKüsimused (
    {StreamedList  küsimused,
     int number,
     Kategooria kategooria,
     KüsimusProbleemide raskused,
     QuestionType type});
}

MockApi juurutamine on vaikeseade (rakenduse seadete lehel saab seda muuta) rakendusesState:

// API
KüsimusedAPI api = MockAPI ();
lõplik apiType = StreamedValue  (InitData: ApiType.mock);

Kuigi apiTypeis on andmebaaside muutmise seadistuste lehel vaid enum:

enum ApiType {pilk, kaugjuhtimispult}

mock_api.dart:

trivia_api.dart:

1 - API valik

Seadete lehel saab kasutaja rippmenüü kaudu valida, millist andmebaasi kasutada:

ValueBuilder  (
  voogesitus: appState.apiType,
  ehitaja: (kontekst, hetktõmmis) {
    tagasi rippmenüü  (
      väärtus: snapshot.data,
      on muudetud: appState.setApiType,
      üksused: [
        const DropdownMenuItem  (
          väärtus: ApiType.mock,
          laps: tekst ('demo'),
        ),
        const DropdownMenuItem  (
          väärtus: ApiType.remote,
          laps: tekst ('opentdb.com'),
       ),
    ]);
}),

Iga kord, kui valitakse uus andmebaas, muudab setApiType meetod API rakendamist ja kategooriaid värskendatakse.

void setApiType (ApiType tüüp) {
  if (apiType.value! = type) {
    apiType.value = tüüp;
    if (tippige == ApiType.mock) {
      api = MockAPI ();
    } veel {
      api = TriviaAPI ();
    }
    _loadCategories ();
  }
}

2 - kategooriad

Kategooriate loendi saamiseks kutsume seda URL-i:

https://opentdb.com/api_category.php

Väljavõte vastusest:

{"trivia_categories": [{"id": 9, "name": "General Knowledge"}, {"id": 10, "name": "Entertainment: Books"}]

Niisiis, pärast JSON-i dekodeerimist, kasutades viskamise funktsiooni jsonDecode: teisendage teek:

lõplik jsonResponse = convert.jsonDecode (response.body);

meil on see struktuur:

  • jsonResponse ['trivia_categories']: kategooriate loend
  • jsonResponse ['trivia_categories'] [INDEX] ['id']: kategooria id
  • jsonResponse ['trivia_categories'] [INDEX] ['name']: kategooria nimi

Nii et mudel on järgmine:

klassi kategooria {
  Kategooria ({see.id, see.nimi});
  tehas Category.fromJson (Kaart  json) {
    return kategooria (id: json ['id'], nimi: json ['nimi']);
  }
  int id;
  Stringi nimi;
}

3 - küsimused

Kui nimetame seda URL-i:

https://opentdb.com/api.php?amount=2&difficulty=medium&type=multiple

see on vastus:

{"vastuse_kood": 0, "tulemused": [{"kategooria": "Meelelahutus: Muusika", "tüüp": "mitu", "raskus": "keskmine", "küsimus": "Milline prantsuse artist / ansambel" on teada, et mängitakse midi-instrumendil "Launchpad"? "," pareizu_answer ":" Madeon "," korrektne vastus ": [" Daft Punk "," Avalikustamine "," David Guetta "]}, {" kategooria ":" Sport "," tüüp ":" mitu "," raskus ":" keskmine "," küsimus ":" Kes võitis 2015. aasta kolledži jalgpalli Playoff (CFP) riikliku meistrivõistluse? "," Pareizu_answer ":" Ohio osariigi Buckeyes "," unknown_answers ": [" Alabama karmiinpunane tõusulaine "," Clemsoni tiigrid "," Wisconsini mägerid "]}]}

Sel juhul on JSON-i dekodeerimine järgmine:

  • jsonResponse ['results']: küsimuste loetelu.
  • jsonResponse ['results'] [INDEX] ['category']: küsimuse kategooria.
  • jsonResponse ['results'] [INDEX] ['type']: küsimuse tüüp, mitu või tõeväärtus.
  • jsonResponse ['results'] [INDEX] ['question']: küsimus.
  • jsonResponse ['results'] [INDEX] ['right_answer']: õige vastus.
  • jsonResponse ['results'] [INDEX] ['wrong_answers']: valede vastuste loetelu.

Mudel:

klassi küsimusmodell {
  QuestionModel ({this.question, this.correctAnswer, this.incorrectAnswers});
  tehas QuestionModel.fromJson (Kaart  json) {
    tagasta küsimusModel (
      küsimus: json ['küsimus'],
      pareiz vastus: json ['korrektne vastus'],
      wrongAnswers: (json ['wrong_answers'] kui nimekiri)
        .map ((vastus) => answer.toString ())
        .loetlema());
  }
  Stringküsimus;
  String korrektne vastus;
  Loend  unknownAnswers;
}

4 - TriviaApi klass

Klass rakendab kaht küsimustiku liidese, getCategories ja getQuestions meetodeid:

  • Kategooriate saamine

Esimeses osas dekodeeritakse JSON ja seejärel mudeli abil sõelutakse, saades tüübiliigi loendi, lõpuks antakse tulemus kategooriate jaoks (tüübi kategooria StreamedList, mida kasutatakse põhilehe kategooriate loendi täitmiseks) ).

lõplik jsonResponse = convert.jsonDecode (response.body);
lõpptulemus = (jsonResponse ['trivia_categories'] kui List)
.map ((kategooria) => Category.fromJson (kategooria));
kategooriad.väärtus = [];
kategooriad
..addAll (tulemus)
..addElement (Kategooria (id: 0, nimi: 'Mis tahes kategooria'));
  • Küsimuste saamine

Midagi sarnast juhtub küsimustega, kuid sel juhul kasutame JSON-i algse struktuuri (QuestionModel) JSON-i algse struktuuri (QuestionModel) teisendamiseks mudelis (küsimus) rakenduses kasutatavaks mugavamaks struktuuriks.

lõplik jsonResponse = convert.jsonDecode (response.body);
lõpptulemus = (jsonResponse ['results'] as List)
.map ((küsimus) => QuestionModel.fromJson (küsimus));
küsimused.väärtus = tulemus
.map ((küsimus) => Question.fromQuestionModel (question))
.loetlema();

5 - küsimuste klass

Nagu eelmises lõigus öeldud, kasutab rakendus küsimuste jaoks erinevat ülesehitust. Selles klassis on meil neli omadust ja kaks meetodit:

klassi küsimus {
  Küsimus ({see.küsimus, see vastus, see.korrektne vastusIndex});
  tehas Question.fromQuestionModel (QuestionModel mudel) {
    lõplik loend  vastused = []
      ..add (mudel.korrektne vastus)
      ..addAll (mudel.incorrectAnswers)
      ..vajuta ();
    lõplik indeks = vastused.indexOf (mudel.korrektne vastus);
    tagastamisküsimus (küsimus: mudel.küsimus, vastused: vastused, korrektne vastusIndex: register);
  }
  Stringküsimus;
  Loetle  vastused;
  int õigeAnswerIndex;
  int valitudAnswerIndex;
  bool on õige (stringi vastus) {
    tagastage vastused.indexOf (vastus) == korrektne vastusIndex;
  }
  bool isChosen (stringi vastus) {
    tagastage vastused.indexOf (vastus) == valitudAnswerIndex;
  }
}

Tehases asustatakse vastuste loend kõigepealt koos kõigi vastustega ja segatakse seejärel nii, et järjekord on alati erinev. Siit saame isegi õige vastuse indeksi, et saaksime selle küsimuste koostaja kaudu korrigeeridaAnswerIndexile. Neid kahte meetodit kasutatakse määramaks, kas parameetrina edastatud vastus on õige või valitud (neid selgitatakse paremini järgmises lõigus).

4. osa - koduleht ja muud ekraanid

1 - avalehe vidin

AppState-is näete atribuuti nimega tabControllerthat, mis on StreamedValue tüüpi AppTab (enum), mida kasutatakse lehe voogesitamiseks, et kuvada vidin HomePage (kodakondsuseta). See töötab sel viisil: iga kord, kui erinev AppTabise komplekt luuakse, loob vidin ValueBuilder uue lehe kuvamise ekraani uuesti.

  • HomePage klass:
Vidina loomine (BuildContext kontekst) {
  final appState = AppStateProvider.of  (kontekst);
  
  tagasta ValueBuilder (
    voogesitus: appState.tabController,
    ehitaja: (kontekst, hetktõmmis) => Tellingud (
      appBar: snapshot.data! = AppTab.main? null: AppBar (),
      sahtel: DrawerWidget (),
      keha: _switchTab (snapshot.data, appState),
      ),
  );
}

N.B. Sel juhul kuvatakse rakenduste riba ainult avalehel.

  • _switchTab meetod:
Vidin _switchTab (vahekaart AppTab, AppState appState) {
  lüliti (sakk) {
    juhtum AppTab.main:
      naasta MainPage ();
      vaheaeg;
    juhtum AppTab.trivia:
      tagastama TriviaPage ();
      vaheaeg;
    juhtum AppTab.summary:
      return SummaryPage (statistika: appState.triviaBloc.stats);
      vaheaeg;
    vaikimisi:
    naasta MainPage ();
  }
}

2 - SeadedPage

Seadete lehel saate valida kuvatavate küsimuste arvu, raskuse, loendamise aja ja selle, millist tüüpi andmebaasi kasutada. Seejärel saate avalehel valida kategooria ja lõpuks mängu alustada. Kõigi nende sätete jaoks kasutan ma StreamedValue'i, nii et vidina ValueBuilder abil saab lehte värskendada iga kord, kui uus väärtus on seatud.

5. osa - TriviaBloc

Rakenduse äriloogika on ainsas BLoC-is, mille nimi on TriviaBloc. Uurime seda klassi.

Ehitajas on meil:

TriviaBloc ({this.countdownStream, this.questions, this.tabController}) {
// Küsimuste hankimine API-st
  questions.onChange ((andmed) {
    if (data.isNotEmpty) {
      lõplikud küsimused = andmed..jagage ();
     _startTrivia (küsimused);
    }
  });
  countdownStream.outTransformed.listen ((andmed) {
     tagasiarvestus = sisemine (andmed) * 1000;
  });
}

Siin kuulab küsimuste atribuut (tüüpi küsimuste StreamedList) muudatusi, kui küsimuste loend voogu saadetakse, alustades _startTrivia meetodit, alustades mängu.

Selle asemel kuulab countdownStream lihtsalt seadete lehel loenduse väärtuse muutusi, et see saaks värskendada TriviaBloci klassis kasutatavat loenduse atribuuti.

  • _startTrivia (loend andmed)

See meetod alustab mängu. Põhimõtteliselt lähtestab see atribuutide oleku, seab esimese kuvatava küsimuse ja kutsub ühe sekundi pärast esile playTrivia meetodi.

tühine _startTrivia (loendi  andmed) {
  indeks = 0;
  triviaState.value.questionIndex = 1;
  // Pealehe ja kokkuvõtte nuppude kuvamiseks
  triviaState.value.isTriviaEnd = vale;
  // lähtestage statistika
  stats.reset ();
  // Algküsimuse (antud juhul tagasiarvestuse) seadmine
  // riba animatsioon ei käivitu).
  currentQuestion.value = data.first;
  Taimer (kestus (millisekundites: 1000), () {
    // Selle lipu õigeks seadmine küsimuse muutmisel
    // algab loenduriba animatsioon.
    triviaState.value.isTriviaPlaying = true;
  
    // Voogestage esimene küsimus uuesti loenduriba abil
    // animatsioon.
    currentQuestion.value = andmed [register];
  
    playTrivia ();
  });
}

triviaState on StreamedValue tüüpi TriviaState, klass, mida kasutatakse trivia oleku haldamiseks.

klass TriviaState {
  bool isTriviaPlaying = false;
  loll isTriviaEnd = vale;
  bool isAnswerChosen = vale;
  int küsimusIndex = 1;
}
  • playTrivia ()

Kui seda meetodit kutsutakse, värskendab taimer perioodiliselt taimerit ja kontrollib, kas möödunud aeg on suurem kui loenduse säte, sel juhul tühistab ta taimeri, märgistab praeguse küsimuse vastuseta ja kutsub _nextQuestionmeetodi üles uue küsimuse kuvamiseks .

tühine playTrivia () {
  taimer = taimer.perioodiline (kestus (millisekundites: refreshTime), (taimer t) {
    currentTime.value = refreshTime * t.tick;
    if (currentTime.value> tagasiarvestus) {
      currentTime.value = 0;
      taimer.sulg ();
      notAwewered (currentQuestion.value);
     _järgmine küsimus();
    }
  });
}
  • ei vastatud (küsimus küsimus)

See meetod kutsub statistika värskendamiseks iga küsimuse jaoks, millele pole vastust, TriviaStats-i klassi statistika eksemplari meetodit addNoAnswer.

tühine ei vastatud (küsimus küsimus) {
  stats.addNoAnswer (küsimus);
}
  • _järgmine küsimus()

Selle meetodi korral suurendatakse küsimuste indeksit ja kui loendis on ka muid küsimusi, saadetakse voog currentQuestion uus küsimus, nii et ValueBuilder värskendab lehte uue küsimusega. Vastasel juhul nimetatakse _endTriva meetodit, mis lõpetab mängu.

tühine _nextQuestion () {
  indeks ++;
   if (indeks 
  • endTrivia ()

Taimer tühistatakse ja lipuTriviaEnd väärtus on tõene. Pärast 1,5 sekundit pärast mängu lõppu kuvatakse kokkuvõtte leht.

tühine _endTrivia () {
  // RESET
  taimer.sulg ();
  currentTime.value = 0;
  triviaState.value.isTriviaEnd = true;
  triviaState.refresh ();
  stopTimer ();
  Taimer (kestus (millisekundites: 1500), () {
     // see lähtestatakse siin, et mitte käivitada
     // loenduse animatsioon kokkuvõtte lehte oodates.
     triviaState.value.isAnswerChosen = vale;
     // Kuva kokkuvõtte leht pärast 1,5 sekundit
     tabController.value = AppTab.summary;
     // Kustutage viimane küsimus nii, et seda ei ilmu
     // järgmises mängus
     currentQuestion.value = null;
  });
}
  • checkAnswer (küsimusküsimus, stringivastus)

Kui kasutaja klõpsab vastusel, kontrollib see meetod, kas see on õige, ja nimetab meetodiks statistikale positiivse või negatiivse punktisumma lisamiseks. Siis lähtestatakse taimer ja laaditakse uus küsimus.

void checkAnswer (küsimusküsimus, vastus stringile) {
  if (! triviaState.value.isTriviaEnd) {
     küsimus.chosenAnswerIndex = küsimus.answers.indexOf (vastus);
     if (küsimus.korrektne (vastus)) {
       stats.addCorrect (küsimus);
     } veel {
       stats.addWrong (küsimus);
     }
     taimer.sulg ();
     currentTime.value = 0;
    _järgmine küsimus();
  }
}
  • stopTimer ()

Kui seda meetodit kutsutakse, siis aeg tühistatakse ja lipp isAnswerChosen seatakse väärtusele True, et käsk CountdownWidget animatsiooni peatada.

tühine stopTimer () {
  // Taimeri peatamine
  taimer.sulg ();
  // Kui seate selle lipu tõeseks, peatub loenduri animatsioon
  triviaState.value.isAnswerChosen = true;
  triviaState.refresh ();
}
  • onChosenAnswer (stringi vastus)

Kui vastus on valitud, siis taimer tühistatakse ja vastuse indeks salvestatakse klassi AnswerAnimation eksemplaride AnsAnswerIndex valitud omadusesAnswerIndex. Seda indeksit kasutatakse selle vastuse lisamiseks vidinate virna viimaseks, et vältida kõigi teiste vastuste katmist.

kehtetu saidilChosenAnswer (stringivastus) {
  selectedAnswer = vastus;
  stopTimer ();
  // Seadke valitud vastus nii, et vastuse vidin saaks selle viimasele panna
  // virn.
  
  answerAnimation.value.chosenAnswerIndex =
  currentQuestion.value.answers.indexOf (vastus);
  atbildesAnimation.refresh ();
}

VastusAnimatsiooniklass:

klass AnswerAnimation {
  AnswerAnimation ({this.chosenAnswerIndex, this.startPlaying});
  int valitudAnswerIndex;
  bool startPlaying = false;
}
  • onChosenAnswerAnimationEnd ()

Kui vastuste animatsioon lõpeb, seatakse lipp isAnswerChosen väärtusele vale, et loenduse animatsioon saaks uuesti käivituda, ja seejärel kutsuti meetod checkAnswer, et kontrollida, kas vastus on õige.

tühine saidilChosenAnwserAnimationEnd () {
  // Lähtestage lipp, et loenduse animatsioon saaks alata
  triviaState.value.isAnswerChosen = vale;
  triviaState.refresh ();
  checkAnswer (praeguneQuestion.value, valitudAnswer);
}
  • TriviaStats klass

Hinde määramisel kasutatakse selle klassi meetodeid. Kui kasutaja valib õige vastuse, suurendatakse tulemust kümne punkti võrra ja praegused küsimused lisatakse paranduste loendisse, nii et neid saaks kokkuvõtte lehel näidata, kui vastus pole õige, vähendatakse tulemust nelja võrra, lõpuks kui vastuse puudumisel vähendatakse tulemust kahe punkti võrra.

klass TriviaStats {
  TriviaStats () {
    parandab = [];
    valed = [];
    ei vastatud = [];
    tulemus = 0;
  }
Loend  parandab;
  Loendi  valed;
  Loend  ei vastatud;
  int skoor;
void addCorrect (küsimus küsimus) {
    parandab.add (küsimus);
    skoor + = 10;
  }
void addWrong (küsimus küsimus) {
    valed.add (küsimus);
    tulemus - = 4;
  }
void addNoAnswer (küsimus küsimus) {
    noAnswered.add (küsimus);
    tulemus - = 2;
  }
tühista lähtestamine () {
    parandab = [];
    valed = [];
    ei vastatud = [];
    tulemus = 0;
  }
}
6. osa - animatsioonid

Selles rakenduses on meil kahte tüüpi animatsioone: vastuste all olev animeeritud riba näitab vastamiseks kuluvat aega ja animatsiooni, mida mängitakse vastuse valimisel.

1 - loenduriba animatsioon

See on üsna lihtne animatsioon. Vidin võtab parameetrina riba riba laiuse, kestuse ja mängu oleku. Animatsioon algab iga kord, kui vidin uuesti üles ehitatakse, ja peatub, kui vastus on valitud.

Algne värv on roheline ja järk-järgult muutub see punaseks, andes märku, et aeg hakkab lõppema.

2 - vastab animatsioonile

Animatsioon käivitatakse iga kord, kui vastus valitakse. Lihtsalt arvutades vastuste positsiooni, viiakse kõik vastused järk-järgult valitud vastuse asukohta. Et valitud vastus jääks virna tippu, vahetatakse see vidinate loendi viimase elemendiga.

// Vaheta viimane üksus valitud angerjaga nii, et see saaks võimalik
// näidatakse virna viimasena.
viimane viimane = vidinad.last;
lõplik valitud = vidinad [widget.answerAnimation.chosenAnswerIndex]; lõplik valitudIndex = vidinad.indexOf (valitud);
vidinad.last = valitud;
vidinad [selectedIndex] = viimane;
tagastatav konteiner (
   laps: korstnat (
      lapsed: vidinad,
   ),
);

Kastide värv muutub roheliseks, kui vastus on õige, ja punaseks, kui see on vale.

var newColor;
if (isCorrect) {
  newColor = värvid.green;
} veel {
  newColor = Colors.red;
}
colorAnimation = ColorTween (
  alusta: answerBoxColor,
  lõpp: newColor,
) .animaalne (kontroller);
oota kontrollerit.forward ();
7. osa - kokkuvõtlik leht

1 - kokkuvõteleht

Sellel lehel võetakse parameetrina klassi TriviaStats eksemplar, mis sisaldab parandatud küsimuste, eksimuste ja vastusteta küsimuste loetelu ning loob nimekirjavaate, mis näitab iga küsimust õiges kohas. Seejärel edastatakse praegune küsimus vidinale SummaryAnswers, mis loob vastuste loendi.

2 - kokkuvõte vastused

See vidin võtab parameetrina küsimuse ja küsimuse enda indeksi ning koostab vastuste loendi. Õige vastuse värvus on roheline, kui kasutaja valis vale vastuse, siis see on punasega esile tõstetud, näidates nii õigeid kui ka valesid vastuseid.

Järeldus

See näide on kaugeltki täiuslik või lõplik, kuid see võib olla hea lähtepunkt koostööks. Näiteks saab seda paremaks muuta, luues statistikalehe, kus on toodud kõigi mängitud mängude punktisumma, või jaotise, kus kasutaja saab luua kohandatud küsimusi ja kategooriaid (need võivad olla suurepäraseks harjutamiseks andmebaasidega). Loodetavasti on see kasulik, tehke julgelt parandusi, ettepanekuid või muud.

Lähtekoodi leiate sellest GitHubi hoidlast.