الخطوة 2 في تطبيق الجوال: واجهة الدردشة

ابنِ واجهة الدردشة — فقاعات الرسائل وحقل الإدخال وزر الإرسال.

ما ستتعلمه

  • مكوّنات React Native الأساسية (View، Text، TextInput، TouchableOpacity)
  • التنسيق باستخدام StyleSheet
  • استخدام FlatList لعرض قائمة رسائل قابلة للتمرير
  • التخطيط باستخدام flexbox

الخطوة 1: فهم بنية المكوّنات

سيكون لتطبيق الدردشة الخاص بنا هذا التخطيط:

┌─────────────────────┐
│   Header            │
├─────────────────────┤
│                     │
│   Message List      │
│   ┌─────────┐       │
│   │ User    │       │
│   └─────────┘       │
│   ┌──────────┐      │
│   │  AI      │      │
│   └──────────┘      │
│                     │
├─────────────────────┤
│ Typing indicator    │
├─────────────────────┤
│ [Input...]  [Send]  │
└─────────────────────┘

الخطوة 2: المكوّنات الأساسية

import { View, Text, TextInput, TouchableOpacity, FlatList, StyleSheet } from 'react-native';

<View>              // مثل <div> في الويب — حاوية
<Text>              // عرض النص
<TextInput />       // حقل إدخال نصي
<TouchableOpacity>  // زر قابل للضغط
<FlatList />        // قائمة قابلة للتمرير ومحسّنة
<StyleSheet>        // تعريف الأنماط

الخطوة 3: تعريف واجهة الرسالة

interface Message {
  id: number;
  content: string;
  sender: "user" | "ai";
  timestamp?: string;
}

الخطوة 4: حالة الرسائل ونص الإدخال

import { useState } from "react";

const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState("");
  • messages — مصفوفة رسائل الدردشة
  • input — النص الحالي في حقل الإدخال

الخطوة 5: عرض الرسائل باستخدام FlatList

<FlatList
  data={messages}
  keyExtractor={(item) => item.id.toString()}
  renderItem={({ item }) => {
    const isUser = item.sender === "user";
    return (
      <View style={[
        styles.bubble,
        isUser ? styles.userBubble : styles.aiBubble
      ]}>
        <Text style={isUser ? styles.userText : styles.aiText}>
          {item.content}
        </Text>
      </View>
    );
  }}
/>
  • data — المصفوفة التي سنعرضها
  • keyExtractor — مفتاح فريد لكل عنصر
  • renderItem — دالة تعيد المكوّن الخاص بكل عنصر

الخطوة 6: صف الإدخال

<View style={styles.inputRow}>
  <TextInput
    style={styles.input}
    value={input}
    onChangeText={setInput}
    placeholder="Type a message..."
  />
  <TouchableOpacity style={styles.sendButton}>
    <Text style={styles.sendButtonText}>Send</Text>
  </TouchableOpacity>
</View>

الخطوة 7: التنسيق باستخدام StyleSheet

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#F5F5F5",
  },
  bubble: {
    maxWidth: "80%",
    padding: 12,
    borderRadius: 16,
    marginBottom: 8,
  },
  userBubble: {
    backgroundColor: "#007AFF",
    alignSelf: "flex-end",
  },
  aiBubble: {
    backgroundColor: "#E8E8E8",
    alignSelf: "flex-start",
  },
  inputRow: {
    flexDirection: "row",
    padding: 12,
    borderTopWidth: 1,
    borderTopColor: "#DDD",
    backgroundColor: "#FFF",
  },
  input: {
    flex: 1,
    borderWidth: 1,
    borderColor: "#DDD",
    borderRadius: 20,
    paddingHorizontal: 16,
    paddingVertical: 10,
    fontSize: 16,
  },
  sendButton: {
    backgroundColor: "#007AFF",
    borderRadius: 20,
    paddingHorizontal: 20,
    paddingVertical: 10,
    marginLeft: 8,
  },
  sendButtonText: {
    color: "#FFF",
    fontSize: 16,
    fontWeight: "600",
  },
});

الخطوة 8: بناء الواجهة الكاملة

استبدل محتوى App.tsx بالكود الموجود في ملف App.tsx النهائي (الجزء الخاص بالواجهة فقط — بلا استدعاءات API بعد، واستخدم رسائل مؤقتة):

import React, { useState } from "react";
import { View, Text, TextInput, TouchableOpacity, FlatList, StyleSheet } from "react-native";

interface Message {
  id: number;
  content: string;
  sender: "user" | "ai";
}

export default function App() {
  const [messages, setMessages] = useState<Message[]>([]);
  const [input, setInput] = useState("");

  const handleSend = () => {
    if (!input.trim()) return;
    const newMsg: Message = { id: Date.now(), content: input, sender: "user" };
    setMessages([...messages, newMsg]);
    setInput("");
  };

  return (
    <View style={styles.container}>
      <FlatList
        data={messages}
        keyExtractor={(item) => item.id.toString()}
        renderItem={({ item }) => (
          <View style={[styles.bubble, item.sender === "user" ? styles.userBubble : styles.aiBubble]}>
            <Text>{item.content}</Text>
          </View>
        )}
      />
      <View style={styles.inputRow}>
        <TextInput
          style={styles.input}
          value={input}
          onChangeText={setInput}
          placeholder="Type a message..."
        />
        <TouchableOpacity style={styles.sendButton} onPress={handleSend}>
          <Text style={styles.sendButtonText}>Send</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: "#F5F5F5", paddingTop: 50 },
  bubble: { maxWidth: "80%", padding: 12, borderRadius: 16, marginBottom: 8 },
  userBubble: { backgroundColor: "#007AFF", alignSelf: "flex-end" },
  aiBubble: { backgroundColor: "#E8E8E8", alignSelf: "flex-start" },
  inputRow: { flexDirection: "row", padding: 12, borderTopWidth: 1, borderTopColor: "#DDD" },
  input: { flex: 1, borderWidth: 1, borderColor: "#DDD", borderRadius: 20, paddingHorizontal: 16, paddingVertical: 10 },
  sendButton: { backgroundColor: "#007AFF", borderRadius: 20, paddingHorizontal: 20, paddingVertical: 10, marginLeft: 8 },
  sendButtonText: { color: "#FFF", fontSize: 16, fontWeight: "600" },
});

التحقق

  • اكتب رسالة في حقل الإدخال
  • اضغط على زر الإرسال
  • تظهر الرسالة كفقاعة زرقاء على اليمين
  • لا يوجد رد من الذكاء الاصطناعي بعد (فهذا في الخطوة 3)