كيفية تنفيذ القوائم المنسدلة في Flutter

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

أداة DropdownButton في Flutter
الطريقة الأسهل لتنفيذ القوائم المنسدلة في Flutter هي استخدام الأداة المضمنة DropdownButton.

import ‘package:flutter/material.dart’;

void main() => runApp(const MyApp());

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

@override
State createState() => _MyAppState();
}

class _MyAppState extends State {
final List _languages = [‘English’, ‘German’, ‘French’];
String _language = ‘English’;

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: DropdownButton(
items: _languages
.map>(
(String language) => DropdownMenuItem(
value: language,
child: Text(language),
),
)
.toList(),
onChanged: (String? language) => setState(
() => _language = language ?? _language,
),
value: _language,
),
),
),
);
}
}
في مقتطف التعليمات البرمجية أعلاه، قمنا بإنشاء MyAppعنصر واجهة مستخدم بحالة. داخل فئة الحالة لهذه العنصر، نقوم بإرجاع الخاصية MaterialAppالخاصة بالتطبيق. داخل MaterialAppالعنصر، نقوم بعرض Scaffoldعنصر واجهة مستخدم يحتوي على . في المنتصف DropdownButton. لقد أضفنا ثلاث سمات إلى DropdownButton: itemsو onChanged، و value.

تأخذ السمة itemsقائمة من DropdownMenuItemالحالات. لإنشاء هذه القائمة، نقوم بربطها بالمتغير _languagesالذي يحتوي على قائمة اللغات. باستخدام mapالدالة، نقوم بإرجاع قيمة a DropdownMenuItemلكل لغة في القائمة. بعد ذلك، نقوم بتحويل العناصر المتطابقة مرة أخرى إلى قائمة باستخدام toListالدالة.

تتلقى الخاصية onChangedاستدعاءً نستخدمه لتحديث المتغير _languageإلى اللغة المحددة حديثًا. نظرًا لأن المتغير _languageمُخصص للخاصية value، فسيتم تحديث اللغة المحددة في كل مرة يتم فيها اختيار لغة مختلفة.

إخفاء التسطير
كما لاحظت في ملف GIF الأخير ، يعرض زر القائمة المنسدلة دائمًا خطًا سفليًا. والسؤال الشائع هو كيفية إخفاء هذا الخط السفلي في DropdownButtonالأداة. هناك طريقتان لتحقيق ذلك.

تغليف الزر المنسدل باستخدام أداة DropdownButtonHideUnderline
الطريقة الأولى هي استخدام DropdownButtonHideUnderlineالأداة المخصصة.
import ‘package:flutter/material.dart’;

void main() => runApp(const MyApp());

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

@override
State createState() => _MyAppState();
}

class _MyAppState extends State {
final List _languages = [‘English’, ‘German’, ‘French’];
String _language = ‘English’;

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: DropdownButtonHideUnderline(
child: DropdownButton(
items: _languages
.map>(
(String language) => DropdownMenuItem(
value: language,
child: Text(language),
),
)
.toList(),
onChanged: (String? language) => setState(
() => _language = language ?? _language,
),
value: _language,
),
),
),
),
);
}
}

في مقتطف التعليمات البرمجية أعلاه، قمنا بتغليف DropdownButtonمع DropdownButtonHideUnderlineالأداة. عند تشغيل التطبيق مرة أخرى، ستلاحظ أن DropdownButtonلم يعد يعرض خطًا سفليًا.

تعيين سمة التسطير إلى SizedBox.Shrink()
الطريقة الثانية هي استخدام underlineسمة الأداة DropdownButton.
import ‘package:flutter/material.dart’;

void main() => runApp(const MyApp());

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

@override
State createState() => _MyAppState();
}

class _MyAppState extends State {
final List _languages = [‘English’, ‘German’, ‘French’];
String _language = ‘English’;

@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: DropdownButton(
items: _languages
.map>(
(String language) => DropdownMenuItem(
value: language,
child: Text(language),
),
)
.toList(),
onChanged: (String? language) => setState(
() => _language = language ?? _language,
),
underline: const SizedBox.shrink(),
value: _language,
),
),
),
);
}
}

في مقتطف التعليمات البرمجية أعلاه، بدلاً من تغليف العنصر DropdownButtonبالأداة DropdownButtonHideUnderline، قمنا بتعيين underlineالسمة إلى SizedBox.shrink(). يؤدي هذا إلى إخفاء الخط السفلي، ولكن يمكن أيضًا استخدام هذه السمة لتخصيص مظهر الخط السفلي إذا لزم الأمر.

تنشئ الأداة SizedBox.shrinkمربعًا فارغًا بدون حجم. ويمكن استخدامها كعلامة نائبة غير مرئية عندما تحتاج إلى توفير أداة أو استبدال أداة.

تصميم عنصر واجهة المستخدم DropdownButton

يقدم DropdownButtonسمات إضافية يمكن استخدامها لتصميم القائمة المنسدلة.

import ‘package:flutter/material.dart’;

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {

const MyApp({super.key});

@override

State createState() => _MyAppState();

}

class _MyAppState extends State {

final List _languages = [‘English’, ‘German’, ‘French’];

String _language = ‘English’;

@override

Widget build(BuildContext context) {

return MaterialApp(

  home: Scaffold(

    body: Center(

      child: Ink(

        decoration: BoxDecoration(

          borderRadius: BorderRadius.circular(10),

          color: Colors.blueAccent,

        ),

        child: DropdownButtonHideUnderline(

          child: DropdownButton(

            borderRadius: BorderRadius.circular(10),

            dropdownColor: Colors.blueAccent,

            icon: const Icon(Icons.language),

            iconEnabledColor: Colors.white,

            iconSize: 30,

            items: _languages

                .map<DropdownMenuItem<String>>(

                  (String language) => DropdownMenuItem<String>(

                    value: language,

                    child: Text(language),

                  ),

                )

                .toList(),

            onChanged: (String? language) => setState(

              () => _language = language ?? _language,

            ),

            padding: const EdgeInsets.symmetric(horizontal: 30),

            style: const TextStyle(fontSize: 20, color: Colors.white),

            value: _language,

          ),

        ),

      ),

    ),

  ),

);

}

}

في مقتطف التعليمات البرمجية أعلاه، قمنا بتغيير ألوان كل من الزر والقائمة المنسدلة. لتغيير لون DropdownButton، قمنا بتغليفه بعنصر Inkواجهة مستخدم. يضمن هذا بقاء تأثير التموج مرئيًا، حيث سيؤدي استخدام عنصر واجهة مستخدم ColoredBoxأو Containerإلى إزالة هذا التأثير. يتم تعيين لون القائمة المنسدلة باستخدام dropdownColorالسمة.

داخل DropdownButtonعنصر واجهة المستخدم، قمنا بتغيير نصف قطر الحدود عن طريق تعيين borderRadiusالسمة إلى BorderRadius.circular(10). نفس القيمة التي استخدمناها داخل decorationسمة عنصر Inkواجهة المستخدم.

لقد أضفنا أيضًا أيقونة باستخدام السمات iconو iconEnabledColorو و iconSize. وأخيرًا، أضفنا حشوًا أفقيًا إلى الزر وقمنا بتغيير لون النص إلى الأبيض.

إذا كنت تريد معرفة طرق مختلفة للحفاظ على تأثير التموج، فراجع المقالة التالية: Flutter InkWell لا يظهر تأثير التموج

أداة DropdownButtonFormField

بدلاً من استخدام DropdownButtonالأداة، يمكننا أيضًا استخدام DropdownButtonFormFieldالأداة. على الرغم من أن هذه الأداة مخصصة للاستخدام داخل Formأداة، إلا أنه يمكن استخدامها أيضًا خارجها Form.

import ‘package:flutter/material.dart’;

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {

const MyApp({super.key});

@override

State createState() => _MyAppState();

}

class _MyAppState extends State {

final List _languages = [‘English’, ‘German’, ‘French’];

String _language = ‘English’;

@override

Widget build(BuildContext context) {

return MaterialApp(

  home: Scaffold(

    body: Center(

      child: SizedBox(

        width: 200,

        child: DropdownButtonFormField(

          decoration: InputDecoration(

            border: OutlineInputBorder(

              borderRadius: BorderRadius.circular(10),

            ),

            contentPadding: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),

            enabledBorder: OutlineInputBorder(

              borderRadius: BorderRadius.circular(10),

              borderSide: const BorderSide(color: Colors.blueAccent, width: 1.5),

            ),

            focusedBorder: OutlineInputBorder(

              borderRadius: BorderRadius.circular(10),

              borderSide: const BorderSide(color: Colors.blueAccent, width: 2.5),

            ),

            labelText: 'Language',

            labelStyle: Theme.of(context).textTheme.titleMedium?.copyWith(fontSize: 18),

          ),

          items: _languages

              .map<DropdownMenuItem<String>>(

                (String language) => DropdownMenuItem<String>(

                  value: language,

                  child: Text(language),

                ),

              )

              .toList(),

          onChanged: (String? language) => setState(

            () => _language = language ?? _language,

          ),

          value: _language,

        ),

      ),

    ),

  ),

);

}

}

في مقتطف الكود أعلاه، استبدلنا DropdownButtonالأداة بالأداة DropdownButtonFormField. أحد الاختلافات الرئيسية هو أنها DropdownButtonFormFieldتتضمن decorationسمة توفر العديد من خيارات التصميم.

على سبيل المثال، أضفنا حدًا أزرق حول زر القائمة المنسدلة وأضفنا تسمية تعرض “اللغة”. بشكل افتراضي، DropdownButtonFormFieldتشغل الأداة العرض الكامل، لذا قمنا بتغليفها داخل SizedBoxأداة لتعيين عرض ثابت يبلغ 200. وبخلاف ذلك، ما زلنا نستخدم نفس السمات كما في السابق لعرض العناصر وتحديث العنصر المحدد.

أداة PopupMenuButton في Flutter

بالإضافة إلى استخدام عناصر واجهة المستخدم DropdownButtonالرسومية DropdownButtonFormField، يمكننا أيضًا استخدام PopupMenuButtonعناصر واجهة المستخدم الرسومية. ورغم أنه من المفترض استخدامها مع الأيقونات وليس النصوص، إلا أنه لا يزال بإمكاننا استخدامها لعرض قوائم منسدلة مماثلة لما فعلناه في الأقسام السابقة.

import ‘package:flutter/material.dart’;

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {

const MyApp({super.key});

@override

State createState() => _MyAppState();

}

class _MyAppState extends State {

final List _languages = [‘English’, ‘German’, ‘French’];

String _language = ‘English’;

@override

Widget build(BuildContext context) {

return MaterialApp(

  home: Scaffold(

    body: Center(

      child: PopupMenuButton(

        iconSize: 30,

        icon: Text(_language),

        initialValue: _language,

        itemBuilder: (BuildContext context) => _languages

            .map<PopupMenuItem<String>>(

              (String language) => PopupMenuItem<String>(

                value: language,

                child: Text(language),

              ),

            )

            .toList(),

        onSelected: (String? language) => setState(

          () => _language = language ?? _language,

        ),

      ),

    ),

  ),

);

}

}

في مقتطف التعليمات البرمجية أعلاه، استبدلنا DropdownButtonبـ PopupMenuButtonwidget لعرض القوائم المنسدلة. PopupMenuButtonتحتوي على سمات مختلفة مقارنة بـ DropdownButton. لإضافة عناصر القائمة المنسدلة، نستخدم itemBuilderالسمة. تأخذ هذه السمة قائمة من PopupMenuEntryالحالات. نستخدم نفس نهج التعيين كما في السابق لإرجاع قائمة من PopupMenuItemعناصر widget، والتي يتم قبولها لأنها تمتد إلى PopupMenuEntryالفئة.

نستخدم iconالسمة لعرض اللغة المحددة حاليًا داخل الزر. وهذا ممكن لأن السمة iconتقبل أي عنصر واجهة مستخدم. ولتحديث اللغة إلى اللغة المحددة حديثًا، نستخدم السمتين initialValueو onSelected. وعلى الرغم من اختلاف الأسماء، فإن هذه السمات تعمل بشكل مشابه لسمات valueو onChangedللعنصر DropdownButtonواجهة المستخدم.

حزمة الزر المنسدل2

لمزيد من خيارات التخصيص، يمكننا استخدام DropdownButton2الحزمة. إحدى الفوائد الرئيسية لهذه الحزمة هي أنها تعرض القائمة المنسدلة مباشرةً أسفل الزر افتراضيًا. وهذا مفيد لأن الأدوات المضمنة غالبًا ما تعرض القائمة المنسدلة في مواضع مختلفة حسب العنصر المحدد، وهو ما قد لا يناسب احتياجاتك دائمًا.

تثبيت حزمة Dropdown Button2

لتثبيت حزمة Dropdow Button2 https://pub.dev/packages/dropdown_button2 ، قم بتنفيذ الأمر التالي داخل جذر مشروعك:

flutter pub add dropdown_button2

بمجرد تنفيذ الأمر، تأكد من فحص ملفك pubspec.yaml بحثًا عن التبعيات المضافة. يجب أن ترى حزمة Dropdown Button2 مضمنة في قسم التبعيات، مثل هذا:

dependencies:

dropdown_button2: ^2.3.9

تنفيذ حزمة Dropdown Button2

توفر حزمة Dropdown Button2 DropdownButton2أداة. ويتم تنفيذ الأداة بنفس طريقة تنفيذ الأداة المضمنة DropdownButton.

import ‘package:dropdown_button2/dropdown_button2.dart’;

import ‘package:flutter/material.dart’;

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {

const MyApp({super.key});

@override

State createState() => _MyAppState();

}

class _MyAppState extends State {

final List _languages = [‘English’, ‘German’, ‘French’];

String _language = ‘English’;

@override

Widget build(BuildContext context) {

return MaterialApp(

  home: Scaffold(

    body: Center(

      child: DropdownButton2(

        items: _languages

            .map<DropdownMenuItem<String>>(

              (String language) => DropdownMenuItem<String>(

                value: language,

                child: Text(language),

              ),

            )

            .toList(),

        onChanged: (String? language) => setState(

          () => _language = language ?? _language,

        ),

        value: _language,

      ),

    ),

  ),

);

}

}

في مقتطف التعليمات البرمجية أعلاه، نستخدم الآن DropdownButton2الأداة لعرض قائمة منسدلة. وكما ترى، لا يزال بإمكاننا استخدام نفس السمات كما في السابق. ومع ذلك، كما هو موضح في ملف GIF ، سترى أن القائمة المنسدلة تظهر دائمًا أسفل الزر.

تصميم عنصر واجهة المستخدم DropdownButton2

على غرار DropdownButtonالأداة، DropdownButton2تسمح الأداة بالتصميم من خلال سماتها. ومع ذلك، DropdownButton2توفر الأداة المزيد من خيارات التصميم وعادةً لا تتطلب أدوات تغليف إضافية لتحقيق التصميم المطلوب.

import ‘package:dropdown_button2/dropdown_button2.dart’;

import ‘package:flutter/material.dart’;

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {

const MyApp({super.key});

@override

State createState() => _MyAppState();

}

class _MyAppState extends State {

final List _languages = [‘English’, ‘German’, ‘French’];

String _language = ‘English’;

@override

Widget build(BuildContext context) {

return MaterialApp(

  home: Scaffold(

    body: Center(

      child: DropdownButton2(

        buttonStyleData: ButtonStyleData(

          decoration: BoxDecoration(

            borderRadius: BorderRadius.circular(10),

            color: Colors.blueAccent,

          ),

          padding: const EdgeInsets.symmetric(horizontal: 10)

        ),

        dropdownStyleData: DropdownStyleData(

          decoration: BoxDecoration(

            borderRadius: BorderRadius.circular(10),

            color: Colors.blueAccent,

          ),

        ),

        iconStyleData: const IconStyleData(

          icon: Icon(Icons.language),

          iconSize: 30,

          iconEnabledColor: Colors.white,

        ),

        items: _languages

            .map<DropdownMenuItem<String>>(

              (String language) => DropdownMenuItem<String>(

            value: language,

            child: Text(language),

          ),

        )

            .toList(),

        onChanged: (String? language) => setState(

              () => _language = language ?? _language,

        ),

        underline: const SizedBox.shrink(),

        style: const TextStyle(

            color: Colors.white,

            fontSize: 20

        ),

        value: _language,

      ),

    ),

  ),

);

}

}

في مقتطف التعليمات البرمجية أعلاه، أضفنا خمس سمات لتطبيق التصميم على نحو مماثل لما فعلناه باستخدام DropdownButton. لقد استخدمنا السمتين buttonStyleDataو dropdownStyleDataلتعيين ألوان وحدود الزر والقائمة المنسدلة إلى اللون الأزرق والمستدير. iconStyleDataتضيف السمة أيقونة لغة بيضاء إلى الزر. وأخيرًا، underlineتزيل السمة الخط السفلي، وتُستخدم styleالسمة لزيادة حجم النص وتغيير لون النص إلى الأبيض.

إذا قمنا ببناء تطبيقنا مرة أخرى، فسترى أن الزر والقائمة المنسدلة لهما تصميم مشابه. ومع ذلك، على عكس الأدوات المدمجة، لم نكن بحاجة إلى تغليف DropdownButton2الأداة بأدوات إضافية لتحقيق هذا التصميم.

أداة DropdownButtonFormField2

أخيرًا، لدينا DropdownButtonFormField2الأداة التي تعمل بشكل مشابه للأداة المضمنة DropdownButtonFormField. والفرق الرئيسي هو أن القائمة المنسدلة تظهر مباشرة أسفل الزر، إلى جانب سمات التصميم الإضافية.

import ‘package:dropdown_button2/dropdown_button2.dart’;

import ‘package:flutter/material.dart’;

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {

const MyApp({super.key});

@override

State createState() => _MyAppState();

}

class _MyAppState extends State {

final List _languages = [‘English’, ‘German’, ‘French’];

String _language = ‘English’;

@override

Widget build(BuildContext context) {

return MaterialApp(

  home: Scaffold(

    body: Center(

      child: SizedBox(

        width: 200,

        child: DropdownButtonFormField2(

          buttonStyleData: const ButtonStyleData(

            width: 110,

          ),

          decoration: InputDecoration(

            border: OutlineInputBorder(

              borderRadius: BorderRadius.circular(10),

            ),

            contentPadding: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),

            enabledBorder: OutlineInputBorder(

              borderRadius: BorderRadius.circular(10),

              borderSide: const BorderSide(color: Colors.blueAccent, width: 1.5),

            ),

            focusedBorder: OutlineInputBorder(

              borderRadius: BorderRadius.circular(10),

              borderSide: const BorderSide(color: Colors.blueAccent, width: 2.5),

            ),

            labelText: 'Language',

            labelStyle: Theme.of(context).textTheme.titleMedium?.copyWith(fontSize: 18),

          ),

          dropdownStyleData: DropdownStyleData(

            decoration: BoxDecoration(

              borderRadius: BorderRadius.circular(10),

            ),

          ),

          items: _languages

              .map<DropdownMenuItem<String>>(

                (String language) => DropdownMenuItem<String>(

                  value: language,

                  child: Text(language),

                ),

              )

              .toList(),

          onChanged: (String? language) => setState(

            () => _language = language ?? _language,

          ),

          value: _language,

        ),

      ),

    ),

  ),

);

}

}

في مقتطف التعليمات البرمجية أعلاه، طبقنا نفس InputDecorationالمثيل على decorationالسمة كما فعلنا مع DropdownButtonFormFieldالمثال. وللحفاظ على المظهر مشابهًا، استخدمنا buttonStyleDataالسمة لمحاذاة اللغة المحددة إلى اليمين داخل الزر والسمة dropdownStyleDataلإضافة حدود مستديرة إلى القائمة المنسدلة.

خاتمة

في هذه المقالة، ناقشنا عدة طرق لتنفيذ القوائم المنسدلة في Flutter باستخدام الأدوات المدمجة: DropdownButton وPopupMenuButton وDropdownButtonFormField، بالإضافة إلى الأدوات المدمجة من حزمة Dropdown Button2. وبينما توفر الأدوات المدمجة العديد من الخيارات، توفر حزمة DropdownButton2 مرونة إضافية، مثل ضمان ظهور القائمة المنسدلة مباشرة أسفل الزر.

Leave a Comment

Your email address will not be published.