تطبيق اساله واجوابه باستخدام فلاتر بشكل بسيط | Simple question and answer application using Flutter

تطبيق اساله واجوابه باستخدام فلاتر بشكل بسيط

تطبيق اساله واجوابه باستخدام فلاتر بشكل بسيط

عندما تتعلم في تطوير تطبيقات الجوال تحتاج دائما الى تنفيذ عدد كبير من التطبيقات لكي تتاكد من انك قادر على تنفيذ مشاريع للعملاء ومن ضمن المشاريع التي تطلب بشكل كبير وهيا انشاء تطبيق quiz app حيث يقوم التطبيق بوضع مجموعة من الاسئله والاختيارات حيث يتمكن المستخدم من قراءة السؤال واختيار الاجابة الصحيحه من بين مجموعة الاسئلة , هذا التطبيق بسيط جدا ومع ذلك يوجد به افكار جديده قد تحسن من مستواك البرمجي بشكل كبير وتمكنك من ان تصبح قادر على بناء تطبيقات قوية بشكل رائع وبسرعه مع الدقه في تفنيذ التصميم .


توجد اطارات عمل مشتركة بين الأنظمة الأساسية مثل Xamarin و React Native بالفعل في السوق لتطوير تطبيقات iOS و Android بقاعدة رمز واحدة. بينما يشارك Flutter المفاهيم مع React Native و Xamarin ، تختلف البنية الفنية لجميع الاطارات الثلاثة اختلافًا كبيرًا. دعنا نرى كيف تتراكم Flutter مقابل أطر العمل المشتركة بين الأنظمة الأساسية باستخدام المعايير التالية. دون إجراء أي مقارنات مع الأنظمة الأساسية الأخرى ، إليك بعض الميزات والسمات التي يمكن أن تغريك بتجربة Flutter: في ديسمبر 2018 ، أصبح Flutter مستقرًا. ثم بدأ في إنشاء تطبيقات فيه ، ووصل إلى درجة غير مسبوقة من النشوة. هذا رائع؛ إنه أمر رائع بالنسبة لنا ، ولكن ماذا يعني ذلك لمطور البرامج الرائد لديك؟


model class for questions


في هذا الclass عباره عن نموذج يمكنك من وضع مجموعة اسالة واجابات كما هو موضح بالشكل التالي تستطيع نسخه ولصقه لديك في المشروع الذي تعمل عليه .


model class for questions

Model.dart


class QuestionModel {
  final String question; // questions
  final List<Option> option; // answers
  bool isLocked;
  Option? selectedOption;

   QuestionModel({
    required this.question,
    required this.option,
    this.selectedOption,
    this.isLocked = false,
  });

}

class Option {
  final String text; // string answer
  final bool isCorrect; // is true or false  .

  const Option({
    required this.text,
    required this.isCorrect,
  });
}

final questions = [
  QuestionModel(question: 'what is the best website to learn development ?',
    option: [
    const Option(text: 'geecoders', isCorrect: true),
    const Option(text: 'geekscoders', isCorrect: false),
    const Option(text: 'gecocoder', isCorrect: false),
    const Option(text: 'geekcoder', isCorrect: false),
  ],
),
  QuestionModel(question: 'hat is your favorite color? ?',
    option: [
      const Option(text: 'black', isCorrect: true),
      const Option(text: 'blue', isCorrect: false),
      const Option(text: 'yellow', isCorrect: false),
      const Option(text: 'red', isCorrect: false),
    ],
  ),
  QuestionModel(question: 'what the best website to learn development ?',
    option: [
      const Option(text: 'geecoders', isCorrect: true),
      const Option(text: 'geekscoders', isCorrect: false),
      const Option(text: 'gecocoder', isCorrect: false),
      const Option(text: 'geekcoder', isCorrect: false),
    ],
  ),
  QuestionModel(question: 'what is your favorite city ?',
    option: [
      const Option(text: 'ciro', isCorrect: false),
      const Option(text: 'zagazig', isCorrect: false),
      const Option(text: '10Th Ramadan', isCorrect: true),
      const Option(text: 'another', isCorrect: false),
    ],
  ),
  QuestionModel(question: 'what is your favorite car ?',
    option: [
      const Option(text: 'Ferrari', isCorrect: false),
      const Option(text: 'bugatti', isCorrect: false),
      const Option(text: 'Mercedes', isCorrect: false),
      const Option(text: 'Dodge', isCorrect: true),
    ],
  ),
  QuestionModel(question: 'what is your favorite language ?',
    option: [
      const Option(text: 'dart', isCorrect: false),
      const Option(text: 'python', isCorrect: false),
      const Option(text: 'java', isCorrect: true),
      const Option(text: 'another', isCorrect: false),
    ],
  ),
];


تصميم لصفحة عرض الاسئلة وعدد الاسئلة في فلاتر


تصميم لصفحة عرض الاسئلة وعدد الاسئلة في فلاتر

في هذا الجزء سوف يكون الصفحة الرئيسيه التي يعمل عليها التطبيق والتي تبدء بسؤال ومجموعة من الاجابات وسوف نقوم بتصميم شكل الاجابات في الجزء التالي سوف يكون عباره عن appbar تقوم بتصميمه يعبر عن السؤال الذي نقف عليه الان وعدد الاسئله الموجوده , واسفلها مجموعة من الاختيارات وعند اختيار اي عنصر يتم اظهار زر للانتقال الى السؤال التالي .


تصميم لصفحة عرض الاسئلة وعدد الاسئلة في فلاتر

Question_page.dart


class QuestionWidget extends StatefulWidget {
  const QuestionWidget({Key? key}) : super(key: key);

  @override
  State<QuestionWidget> createState() => _QuestionWidgetState();
}

class _QuestionWidgetState extends State<QuestionWidget> {
  int _questionNumber = 1;
  late PageController _controller;
  int _score = 0;
  bool isLocked = false;

  void initState() {
    super.initState();
    _controller = PageController(initialPage: 0);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(padding: const EdgeInsets.symmetric(horizontal: 16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            const SizedBox(height: 32,),
            Text('Question $_questionNumber/${questions.length}'),
            const Divider(thickness: 1, color: Colors.grey,),
            Expanded
              (child: PageView.builder(
                itemCount: questions.length,
                controller: _controller,
                physics: const NeverScrollableScrollPhysics(),
                itemBuilder: (context,index) {
                  return buildQuestion(questions[index]);
                })),
            isLocked ? buildElevatedButton() : const SizedBox.shrink(),
            const SizedBox(height: 20,),
          ],
        ),),
    );
  }

  // button show is isLocked true and if Question is final ? result page
  ElevatedButton buildElevatedButton() {
    return ElevatedButton(
        onPressed: (){
          if ( _questionNumber < questions.length) {
            _controller.nextPage(
              duration : const Duration(microseconds: 250),
              curve : Curves.easeInExpo,
            );
            setState((){
              _questionNumber++;
              isLocked = false;
              });
          }
          else {
            navToPush(context, ResulPage(score: _score));
          }
        },
        child: Text(
          _questionNumber < questions.length ? 'Next' : 'Result',
        )
    );
  }

  // design .
  Column buildQuestion(QuestionModel questionModel){
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        const SizedBox(height: 32,),
        // appbar
        Text(questionModel.question , style: const TextStyle(fontSize: 25),),
        const SizedBox(height: 32,),
        // list of Option (answers)
        Expanded(
          child: OptionWidget(
          // send question to show answers
          question : questionModel,
          // click any item from answers
          onClick: (Option value) {
            // if locked any item selectedOption = value is clicked .
            // and isLocked is true
            if (questionModel.isLocked) {
              return;
            } else {
              setState((){
                questionModel.isLocked = true;
                questionModel.selectedOption = value;
              });
              // if locked is true ? _score ++ .
              isLocked = questionModel.isLocked;
              if (questionModel.selectedOption!.isCorrect) {
                _score++;
              }
            }
          },
        ))
      ],
    );
  }

}


تصميم لصفحة عرض الاجابات الخاصه بالاسئله في فلاتر

هذا الجزء عباره عن تصميم للاجابات الخاصه بالسؤال كل ما سوف نقوم به هو اننا نحصل على الindex الخاص بالسؤال وبعدها نمر على جميع الاجابات التي توجد لهذا السؤال لكي نقوم بعدها بتنفيذها بشكل سليم كما هو موضح تم استخدام map لكي نمر على جميع العناصر الموجوده ونقوم بعمل تصميم مخصص لهم .


تصميم لصفحة عرض الاجابات الخاصه بالاسئله في فلاتر

answers.dart


class OptionWidget extends StatelessWidget {
  const OptionWidget({Key? key,required this.question , required this.onClick}) : super(key: key);
  final QuestionModel question;
  final ValueChanged<Option> onClick;

  @override
  Widget build(BuildContext context) {
    return Column(
      // loop all answers for Question and show .
      children: question.option.map((e) => buildOption(context,e)).toList(),
    );
  }

  // design Question
  Widget buildOption(BuildContext context , Option e) {
    // color answer after click .
    final color = getColorForOption(e,question);
    return GestureDetector(
      onTap: ()=> onClick(e),
      child: Container(
        height: 50,
        padding: EdgeInsets.all(12),
        margin: EdgeInsets.symmetric(vertical: 8),
        decoration: BoxDecoration(
          color: Colors.grey.shade200,
          borderRadius: BorderRadius.circular(16),
          // if color is true return green else red .
          border: Border.all(color: color),
        ),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              e.text,
              style: const TextStyle(fontSize: 20),
            ),
            // if Icon is true return green else red .
            getIconForOption(e,question),
          ],
        ),
      ),
    );
  }

Color getColorForOption(Option e,QuestionModel question) {
    final isSelected = e == question.selectedOption;
    if (question.isLocked) {
      if (isSelected) {
        return e.isCorrect ? Colors.green : Colors.red;
      } else if (e.isCorrect){
        return Colors.green;
      }
    }
    return Colors.grey.shade300;
}

Widget getIconForOption(Option e,QuestionModel question) {
    // isSelected value is e and e value is question.selectedOption
  final isSelected = e == question.selectedOption; // your choice
  print('is Seledted ------------ $isSelected');

  if (question.isLocked) {
    if (isSelected) {
      // if your choice is false .
      return e.isCorrect ? const Icon(Icons.check_circle , color: Colors.green,) :
      const Icon(Icons.cancel , color: Colors.red,);
    }else if (e.isCorrect){
      // if your choice is true .
      return const Icon(Icons.check_circle , color: Colors.green,);
    }
  }
  return const SizedBox.shrink();
}

}


تصميم صفحة عرض نتيجة الطالب بعد الانتهاء من الامتحان داخل فلاتر


تصميم صفحة عرض نتيجة الطالب بعد الانتهاء من الامتحان داخل فلاتر

الجزء الاخير وهو الجزء الذي يتم من خلاله عرض نتيجة الطالب وهي عباره عن مجموع الاجابات الصحيحه / مجموع عدد الاسئله يمكنك تنفيذ عملية حسابية لكي تظهر النسبة المئوية للطالب اذا اردت ذلك او تغيير شكل التصميم الذي تعرض بداخلها هذه العناصر .


تصميم صفحة عرض نتيجة الطالب بعد الانتهاء من الامتحان داخل فلاتر

result.dart


class ResulPage extends StatelessWidget {
  const ResulPage({Key? key,required this.score}) : super(key: key);
  final int score;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text('your Reslt is $score/${questions.length}'),
      ),
    );
  }
}


لمزيد من المقالات

تعليقات