كيفية تصميم واجهة تطبيق دردشة باستخدام Flutter وDart

دقائق القراءة: 9

مقدمة: لماذا تُعد واجهة تطبيقات الدردشة مهمة؟

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

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

واجهة تطبيق دردشة حديثة باستخدام Flutter وDart على الهاتف المحمول

إنشاء مشروع جديد باستخدام Flutter

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

flutter create ChatApp

بعد إنشاء المشروع، انتقل إلى مجلد المشروع وشغّل التطبيق باستخدام الأمر التالي:

flutter run

عند نجاح التشغيل، سيظهر التطبيق الافتراضي على المحاكي أو على الجهاز الحقيقي.

تشغيل مشروع Flutter الجديد على المحاكي

إعداد الملف الرئيسي للتطبيق

سنبدأ بتعديل الملف main.dart لإزالة الشيفرة الافتراضية واستبدالها بهيكل بسيط يعتمد على MaterialApp:

import 'package:flutter/material.dart' ;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo' ,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      debugShowCheckedModeBanner: false ,
      home: Container(),
    );
  }
}

في هذه المرحلة، نستخدم Container مؤقتاً كواجهة رئيسية إلى أن ننشئ شاشة الصفحة الرئيسية الخاصة بالتطبيق.

بناء الشاشة الرئيسية للتطبيق

داخل المجلد ./lib، أنشئ مجلداً جديداً باسم ./screens. هذا المجلد سيحتوي على ملفات الشاشات المختلفة.

ثم أنشئ ملفاً باسم homePage.dart داخل ./lib/screens، وأضف الشيفرة التالية:

import 'package:flutter/material.dart' ;

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Center(child: Text("Chat")),
      ),
    );
  }
}

بعد ذلك، عد إلى ملف main.dart واجعل الصفحة الرئيسية هي HomePage() بدلاً من Container():

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo' ,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      debugShowCheckedModeBanner: false ,
      home: HomePage(),
    );
  }
}

الشاشة الرئيسية الأولية لتطبيق الدردشة في Flutter

إضافة شريط التنقل السفلي

لإنشاء تجربة استخدام قريبة من تطبيقات الدردشة الحديثة، سنضيف شريط تنقل سفلي باستخدام العنصر BottomNavigationBar داخل الخاصية bottomNavigationBar في Scaffold:

return Scaffold(
  body: Container(
    child: Center(child: Text("Chat")),
  ),
  bottomNavigationBar: BottomNavigationBar(
    selectedItemColor: Colors.red,
    unselectedItemColor: Colors.grey.shade600,
    selectedLabelStyle: TextStyle(fontWeight: FontWeight.w600),
    unselectedLabelStyle: TextStyle(fontWeight: FontWeight.w600),
    type: BottomNavigationBarType.fixed,
    items: [
      BottomNavigationBarItem(
        icon: Icon(Icons.message),
        title: Text("Chats"),
      ),
      BottomNavigationBarItem(
        icon: Icon(Icons.group_work),
        title: Text("Channels"),
      ),
      BottomNavigationBarItem(
        icon: Icon(Icons.account_box),
        title: Text("Profile"),
      ),
    ],
  ),
);

بهذا أصبح لدينا شريط تنقل يضم الأقسام الأساسية:

  • المحادثات
  • القنوات
  • الملف الشخصي

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

إنشاء شاشة قائمة المحادثات

الخطوة التالية هي بناء القسم الرئيسي الذي يعرض المحادثات. سننشئ ملفاً جديداً باسم chatPage.dart داخل مجلد ./lib/screens، ثم نضيف هيكل شاشة قابل للتطوير:

import 'package:flutter/material.dart' ;

class ChatPage extends StatefulWidget {
  @override
  _ChatPageState createState() => _ChatPageState();
}

class _ChatPageState extends State<ChatPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        child: Center(child: Text("Chat")),
      ),
    );
  }
}

ثم استبدل محتوى body في homePage.dart من Container إلى ChatPage():

return Scaffold(
  body: ChatPage(),
  bottomNavigationBar: BottomNavigationBar(

ربط شاشة قائمة المحادثات بالصفحة الرئيسية في Flutter

إضافة ترويسة جذابة لقائمة المحادثات

من المهم أن تبدأ شاشة المحادثات بعنوان واضح وزر للإجراءات السريعة. أضف القسم التالي داخل Column في شاشة chatPage.dart:

return Scaffold(
  body: SingleChildScrollView(
    physics: BouncingScrollPhysics(),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        SafeArea(
          child: Padding(
            padding: EdgeInsets.only(left: 16 ,right: 16 ,top: 10 ),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Text(
                  "Conversations" ,
                  style: TextStyle(fontSize: 32 ,fontWeight: FontWeight.bold),
                ),
                Container(
                  padding: EdgeInsets.only(left: 8 ,right: 8 ,top: 2 ,bottom: 2 ),
                  height: 30 ,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(30),
                    color: Colors.pink[50],
                  ),
                  child: Row(
                    children: <Widget>[
                      Icon(Icons.add,color: Colors.pink,size: 20),
                      SizedBox(width: 2),
                      Text(
                        "Add New" ,
                        style: TextStyle(fontSize: 14 ,fontWeight: FontWeight.bold),
                      ),
                    ],
                  ),
                )
              ],
            ),
          ),
        ),
      ],
    ),
  ),
);

استخدام SingleChildScrollView مع BouncingScrollPhysics() يمنح الشاشة سلاسة أكبر أثناء التمرير، خصوصاً على الأجهزة التي تدعم تأثير الارتداد.

ترويسة شاشة المحادثات في Flutter مع زر إضافة محادثة جديدة

إضافة شريط بحث داخل واجهة الدردشة

وجود شريط بحث في الأعلى يجعل الوصول إلى المحادثات أسرع، خاصة مع ازدياد عدد المستخدمين. أضف العنصر التالي أسفل الترويسة مباشرة:

Padding(
  padding: EdgeInsets.only(top: 16 ,left: 16 ,right: 16 ),
  child: TextField(
    decoration: InputDecoration(
      hintText: "Search..." ,
      hintStyle: TextStyle(color: Colors.grey.shade600),
      prefixIcon: Icon(Icons.search,color: Colors.grey.shade600, size: 20),
      filled: true,
      fillColor: Colors.grey.shade100,
      contentPadding: EdgeInsets.all(8),
      enabledBorder: OutlineInputBorder(
        borderRadius: BorderRadius.circular(20),
        borderSide: BorderSide(color: Colors.grey.shade100),
      ),
    ),
  ),
),

شريط بحث أنيق داخل شاشة قائمة المحادثات في Flutter

بناء نموذج بيانات المحادثات

حتى نعرض قائمة محادثات منظمة، من الأفضل إنشاء نموذج بيانات مستقل. أنشئ مجلداً جديداً باسم ./models ثم أضف ملفاً باسم chatUsersModel.dart:

import 'package:flutter/cupertino.dart' ;

class ChatUsers {
  String name;
  String messageText;
  String imageURL;
  String time;

  ChatUsers({
    @required this.name,
    @required this.messageText,
    @required this.imageURL,
    @required this.time
  });
}

هذا النموذج يحفظ المعلومات الأساسية لكل محادثة:

  • اسم المستخدم
  • آخر رسالة
  • رابط الصورة الشخصية
  • وقت الرسالة

إعداد بيانات تجريبية لقائمة المحادثات

داخل ملف chatPage.dart، أضف قائمة تجريبية من المستخدمين:

class _ChatPageState extends State<ChatPage> {
  List<ChatUsers> chatUsers = [
    ChatUsers(name: "Jane Russel", messageText: "Awesome Setup", imageURL: "images/userImage1.jpeg", time: "Now"),
    ChatUsers(name: "Glady's Murphy", messageText: "That's Great", imageURL: "images/userImage2.jpeg", time: "Yesterday"),
    ChatUsers(name: "Jorge Henry", messageText: "Hey where are you?", imageURL: "images/userImage3.jpeg", time: "31 Mar"),
    ChatUsers(name: "Philip Fox", messageText: "Busy! Call me in 20 mins", imageURL: "images/userImage4.jpeg", time: "28 Mar"),
    ChatUsers(name: "Debra Hawkins", messageText: "Thankyou, It's awesome", imageURL: "images/userImage5.jpeg", time: "23 Mar"),
    ChatUsers(name: "Jacob Pena", messageText: "will update you in evening", imageURL: "images/userImage6.jpeg", time: "17 Mar"),
    ChatUsers(name: "Andrey Jones", messageText: "Can you please share the file?", imageURL: "images/userImage7.jpeg", time: "24 Feb"),
    ChatUsers(name: "John Wick", messageText: "How are you?", imageURL: "images/userImage8.jpeg", time: "18 Feb"),
  ];

هذه البيانات التجريبية مفيدة لتصميم الواجهة قبل ربطها لاحقاً بواجهة خلفية أو قاعدة بيانات.

إنشاء مكوّن مستقل لكل عنصر محادثة

لفصل الواجهة بطريقة احترافية، من الأفضل إنشاء عنصر مستقل يمثل كل محادثة. أنشئ مجلداً باسم ./widgets ثم أضف ملفاً باسم conversationList.dart:

import 'package:flutter/material.dart' ;

class ConversationList extends StatefulWidget {
  String name;
  String messageText;
  String imageUrl;
  String time;
  bool isMessageRead;

  ConversationList({
    @required this.name,
    @required this.messageText,
    @required this.imageUrl,
    @required this.time,
    @required this.isMessageRead
  });

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

class _ConversationListState extends State<ConversationList> {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: (){},
      child: Container(
        padding: EdgeInsets.only(left: 16 ,right: 16 ,top: 10 ,bottom: 10 ),
        child: Row(
          children: <Widget>[
            Expanded(
              child: Row(
                children: <Widget>[
                  CircleAvatar(
                    backgroundImage: NetworkImage(widget.imageUrl),
                    maxRadius: 30,
                  ),
                  SizedBox(width: 16),
                  Expanded(
                    child: Container(
                      color: Colors.transparent,
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          Text(widget.name, style: TextStyle(fontSize: 16)),
                          SizedBox(height: 6),
                          Text(
                            widget.messageText,
                            style: TextStyle(
                              fontSize: 13,
                              color: Colors.grey.shade600,
                              fontWeight: widget.isMessageRead ? FontWeight.bold : FontWeight.normal
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
            ),
            Text(
              widget.time,
              style: TextStyle(
                fontSize: 12,
                fontWeight: widget.isMessageRead ? FontWeight.bold : FontWeight.normal
              ),
            ),
          ],
        ),
      ),
    );
  }
}

هذا المكوّن يستقبل القيم التالية:

  • اسم المستخدم
  • نص الرسالة الأخيرة
  • رابط الصورة
  • وقت الرسالة
  • حالة قراءة الرسالة

عرض قائمة المحادثات باستخدام ListView

الآن يمكننا استخدام ListView.builder لعرض العناصر داخل chatPage.dart:

ListView.builder(
  itemCount: chatUsers.length,
  shrinkWrap: true,
  padding: EdgeInsets.only(top: 16),
  physics: NeverScrollableScrollPhysics(),
  itemBuilder: (context, index) {
    return ConversationList(
      name: chatUsers[index].name,
      messageText: chatUsers[index].messageText,
      imageUrl: chatUsers[index].imageURL,
      time: chatUsers[index].time,
      isMessageRead: (index == 0 || index == 3) ? true : false,
    );
  },
),

احرص على وضع هذا المكوّن داخل Column ضمن شاشة chatPage حتى تظهر القائمة أسفل شريط البحث مباشرة.

قائمة محادثات كاملة في تطبيق Flutter مع صور وأوقات وآخر الرسائل

إنشاء شاشة تفاصيل المحادثة

بعد الانتهاء من شاشة القائمة، ننتقل إلى شاشة تفاصيل الرسائل. أنشئ ملفاً جديداً باسم chatDetailPage.dart داخل ./lib/screens:

import 'package:flutter/material.dart' ;

class ChatDetailPage extends StatefulWidget {
  @override
  _ChatDetailPageState createState() => _ChatDetailPageState();
}

class _ChatDetailPageState extends State<ChatDetailPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Chat Detail"),
      ),
      body: Container()
    );
  }
}

هذه الشاشة ستكون الأساس الذي سنبني عليه واجهة الرسائل لاحقاً.

إضافة التنقل إلى شاشة تفاصيل المحادثة

في ملف conversationList.dart، أضف عملية التنقل داخل الحدث onTap في GestureDetector:

GestureDetector(
  onTap: () {
    Navigator.push(context, MaterialPageRoute(builder: (context) {
      return ChatDetailPage();
    }));
  },

بهذا، عند الضغط على أي محادثة، سينتقل المستخدم إلى شاشة التفاصيل.

التنقل من قائمة المحادثات إلى شاشة تفاصيل المحادثة في Flutter

تصميم شريط علوي مخصص لشاشة المحادثة

بدلاً من استخدام شريط افتراضي بسيط، يمكننا إنشاء AppBar مخصص يعرض صورة المستخدم وحالته:

return Scaffold(
  appBar: AppBar(
    elevation: 0,
    automaticallyImplyLeading: false,
    backgroundColor: Colors.white,
    flexibleSpace: SafeArea(
      child: Container(
        padding: EdgeInsets.only(right: 16),
        child: Row(
          children: <Widget>[
            IconButton(
              onPressed: () {
                Navigator.pop(context);
              },
              icon: Icon(Icons.arrow_back, color: Colors.black),
            ),
            SizedBox(width: 2),
            CircleAvatar(
              backgroundImage: NetworkImage("https://randomuser.me/api/portraits/men/5.jpg"),
              maxRadius: 20,
            ),
            SizedBox(width: 12),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    "Kriss Benwat",
                    style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
                  ),
                  SizedBox(height: 6),
                  Text(
                    "Online",
                    style: TextStyle(color: Colors.grey.shade600, fontSize: 13),
                  ),
                ],
              ),
            ),
            Icon(Icons.settings, color: Colors.black54),
          ],
        ),
      ),
    ),
  ),
  body: Container()
);

شريط علوي مخصص في شاشة تفاصيل المحادثة مع صورة المستخدم وحالته

إضافة صندوق كتابة الرسائل في الأسفل

أي تطبيق دردشة يحتاج إلى منطقة كتابة واضحة وثابتة أسفل الشاشة. يمكن تنفيذ ذلك باستخدام Stack مع Align:

body: Stack(
  children: <Widget>[
    Align(
      alignment: Alignment.bottomLeft,
      child: Container(
        padding: EdgeInsets.only(left: 10 ,bottom: 10 ,top: 10 ),
        height: 60,
        width: double.infinity,
        color: Colors.white,
        child: Row(
          children: <Widget>[
            GestureDetector(
              onTap: () {},
              child: Container(
                height: 30,
                width: 30,
                decoration: BoxDecoration(
                  color: Colors.lightBlue,
                  borderRadius: BorderRadius.circular(30),
                ),
                child: Icon(Icons.add, color: Colors.white, size: 20),
              ),
            ),
            SizedBox(width: 15),
            Expanded(
              child: TextField(
                decoration: InputDecoration(
                  hintText: "Write message...",
                  hintStyle: TextStyle(color: Colors.black54),
                  border: InputBorder.none
                ),
              ),
            ),
            SizedBox(width: 15),
            FloatingActionButton(
              onPressed: () {},
              child: Icon(Icons.send, color: Colors.white, size: 18),
              backgroundColor: Colors.blue,
              elevation: 0,
            ),
          ],
        ),
      ),
    ),
  ],
),

صندوق كتابة وإرسال الرسائل في أسفل شاشة دردشة Flutter

إنشاء نموذج بيانات الرسائل

لعرض الرسائل بشكل صحيح، نحتاج إلى نموذج مستقل يمثل الرسالة. أنشئ ملفاً باسم chatMessageModel.dart داخل ./models:

import 'package:flutter/cupertino.dart' ;

class ChatMessage {
  String messageContent;
  String messageType;

  ChatMessage({
    @required this.messageContent,
    @required this.messageType
  });
}

هذا النموذج يحدد:

  • محتوى الرسالة
  • نوعها: sender أو receiver

إعداد قائمة الرسائل داخل شاشة التفاصيل

داخل ملف chatDetailPage.dart، أضف قائمة تجريبية للرسائل:

List<ChatMessage> messages = [
  ChatMessage(messageContent: "Hello, Will", messageType: "receiver"),
  ChatMessage(messageContent: "How have you been?", messageType: "receiver"),
  ChatMessage(messageContent: "Hey Kriss, I am doing fine dude. wbu?", messageType: "sender"),
  ChatMessage(messageContent: "ehhhh, doing OK.", messageType: "receiver"),
  ChatMessage(messageContent: "Is there any thing wrong?", messageType: "sender"),
];

ثم استخدم ListView.builder لعرض الرسائل أعلى صندوق الكتابة:

body: Stack(
  children: <Widget>[
    ListView.builder(
      itemCount: messages.length,
      shrinkWrap: true,
      padding: EdgeInsets.only(top: 10 ,bottom: 10 ),
      physics: NeverScrollableScrollPhysics(),
      itemBuilder: (context, index) {
        return Container(
          padding: EdgeInsets.only(left: 16 ,right: 16 ,top: 10 ,bottom: 10 ),
          child: Text(messages[index].messageContent),
        );
      },
    ),
    Align(

عرض أولي لقائمة الرسائل داخل شاشة تفاصيل الدردشة في Flutter

تنسيق فقاعات الرسائل حسب المرسل والمستقبل

الآن نمنح الرسائل مظهراً احترافياً يشبه تطبيقات الدردشة الحقيقية، مع تغيير المحاذاة واللون حسب نوع الرسالة:

ListView.builder(
  itemCount: messages.length,
  shrinkWrap: true,
  padding: EdgeInsets.only(top: 10 ,bottom: 10 ),
  physics: NeverScrollableScrollPhysics(),
  itemBuilder: (context, index) {
    return Container(
      padding: EdgeInsets.only(left: 14 ,right: 14 ,top: 10 ,bottom: 10 ),
      child: Align(
        alignment: (messages[index].messageType == "receiver" ? Alignment.topLeft : Alignment.topRight),
        child: Container(
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(20),
            color: (messages[index].messageType == "receiver" ? Colors.grey.shade200 : Colors.blue[200]),
          ),
          padding: EdgeInsets.all(16),
          child: Text(
            messages[index].messageContent,
            style: TextStyle(fontSize: 15),
          ),
        ),
      ),
    );
  },
),

بهذا الشكل:

  • تظهر الرسائل المستلمة على اليسار
  • تظهر الرسائل المرسلة على اليمين
  • يتغير لون الفقاعة لتسهيل التمييز البصري

فقاعات رسائل منسقة حسب المرسل والمستقبل في تطبيق دردشة Flutter

النتيجة النهائية لواجهة التطبيق

بعد تنفيذ الخطوات السابقة، ستحصل على واجهة دردشة متكاملة من حيث التصميم، تشمل:

  • شاشة رئيسية مع شريط تنقل سفلي
  • قائمة محادثات تحتوي على صور ورسائل وأوقات
  • شريط بحث علوي
  • شاشة تفاصيل محادثة
  • فقاعات رسائل منسقة
  • صندوق كتابة وإرسال الرسائل

الواجهة الكاملة لتطبيق دردشة مبني باستخدام Flutter وDart

أفضل ممارسات لتحسين واجهة تطبيق الدردشة

1. افصل المكوّنات عن الشاشات

إنشاء ملفات مستقلة مثل conversationList.dart يساعدك على تنظيم المشروع وتسهيل الصيانة.

2. استخدم النماذج البرمجية

وجود نماذج مثل ChatUsers وChatMessage يجعل ربط البيانات لاحقاً مع API أو قاعدة البيانات أكثر وضوحاً.

3. راعِ الأداء في القوائم

استخدام ListView.builder أفضل من إنشاء العناصر يدوياً، لأنه يحمّل العناصر عند الحاجة فقط.

4. اجعل الواجهة قابلة للتطوير

هذه الواجهة تمثل أساساً ممتازاً لإضافة مزايا لاحقاً مثل الإشعارات، رفع الملفات، المكالمات الصوتية، أو الرسائل الصوتية.

الخلاصة التقنية

بناء واجهة تطبيق دردشة باستخدام Flutter وDart يمنحك مرونة كبيرة في تصميم تجربة استخدام حديثة تعمل بكفاءة على أكثر من منصة. هذا النوع من المشاريع مناسب جداً لفهم بنية الواجهات، وإدارة المكوّنات، وتنظيم الملفات، قبل الانتقال إلى المراحل الأعمق مثل إدارة الحالة وربط الخدمات الخلفية. تقنياً، يُظهر هذا المشروع قوة Flutter في إنتاج واجهات دقيقة وسلسة بزمن تطوير قصير نسبياً، وهو ما يجعله خياراً ممتازاً لتطبيقات التراسل الحديثة.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *