
كيفية برمجة تطبيق بطاقات تعليمية Flashcards على Android Studio Java
تعتبر تطبيقات البطاقات التعليمية أداة فعالة للتعلم والمراجعة.
سنقوم ببرمجة تطبيق بسيط يعرض بطاقات تحتوي على سؤال في الأمام وإجابة في الخلف،
مع إمكانية التنقل بين البطاقات وحساب النقاط. سنستخدم أندرويد ستوديو ولغة جافا،
مع التركيز على تنظيم الكود وتسهيل الفهم.
- برمجة تطبيق Flashcards على أندرويد ستوديو باستخدام جافا تبدأ بتصميم الواجهة في ملفات
XML ثم إضافة المنطق البرمجي في MainActivity.java.
- حفظ النقاط في تطبيق البطاقات التعليمية يتم بسهولة باستخدام SharedPreferences،
وهي طريقة مثالية لتخزين البيانات البسيطة بشكل دائم على الجهاز.
- حل مشكلة التنقل بين البطاقات يعتمد على استخدام قائمة (List) من نوع Flashcard،
وتغيير محتوى الواجهة عند كل نقرة على زر "البطاقة التالية".
خطوات برمجة برمجة تطبيق Flashcards على Android Studio
الخطوة 1: إعداد المشروع
في أندرويد ستوديو، قم بإنشاء مشروع جديد :
- اختر File > New > New Project.
- اختر Empty Views Activity.
- أعطِ المشروع اسماً (مثلاً: MyFlashcardsApp)، واختر لغة Java.
- انقر على Finish.
الخطوة 2: تصميم واجهة البطاقة (Flashcard Layout)
- سنقوم بإنشاء ملف تصميم XML خاص بشكل البطاقة نفسها، لكي نتمكن من إعادة استخدامه.
- افتح ملف res/layout/activity_main.xml. بدلاً من تصميمه كاملاً الآن، سنضيف فقط حاوية للبطاقة.
- الآن، أنشئ ملف res/layout/flashcard_layout.xml عن طريق النقر
بزر الماوس الأيمن على مجلد layout واختيار New > Layout Resource File.
هذا الملف سيمثل البطاقة الواحدة :
XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_margin="16dp"
app:cardCornerRadius="12dp"
app:cardElevation="8dp">
<TextView
android:id="@+id/card_text_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:padding="16dp"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="@android:color/black"
android:background="#f5f5f5"
android:text="Question goes here" />
</androidx.cardview.widget.CardView>
--
الخطوة 3: تصميم الواجهة الرئيسية (Main Activity Layout)
الآن سنقوم بتصميم الواجهة الرئيسية في ملف res/layout/activity_main.xml.
ستحتوي على البطاقة، وزرين للتنقل، ونص لعرض النقاط :
XML
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center_horizontal" android:padding="16dp" tools:context=".MainActivity">
<TextView android:id="@+id/score_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Score: 0" android:textSize="20sp" android:layout_marginBottom="16dp"/>
<include android:id="@+id/flashcard_container" layout="@layout/flashcard_layout" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" />
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center_horizontal" android:layout_marginTop="16dp">
<Button android:id="@+id/next_card_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Next Card"/>
</LinearLayout>
</LinearLayout>
--
* ملاحظة : سنستخدم النقر على البطاقة نفسها لقلبها، بدلاً من زر منفصل.
الخطوة 4: كلاس نموذج البيانات (Flashcard Data Model)
أنشئ كلاس جافا جديد باسم Flashcard.java في نفس حزمة MainActivity.
ستحتوي هذه الكلاس على السؤال والإجابة :
Java
// res/layout/flashcard_layout.xml
package com.example.myflashcardsapp;
public class Flashcard {
private String question;
private String answer;
public Flashcard(String question, String answer) {
this.question = question;
this.answer = answer;
}
public String getQuestion() {
return question;
}
public String getAnswer() {
return answer;
}
}
--
الخطوة 5 : المنطق البرمجي (MainActivity.java)
هذا هو قلب التطبيق، سنضيف المنطق للتعامل مع البطاقات والنقاط :
Java
// res/layout/activity_main.xml
package com.example.myflashcardsapp;
import androidx.appcompat.app.AppCompatActivity;import androidx.cardview.widget.CardView;import android.content.Context;import android.content.SharedPreferences;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.TextView;import java.util.ArrayList;import java.util.List;
public class MainActivity extends AppCompatActivity {
private CardView flashcardContainer; private TextView cardTextView; private Button nextCardButton; private TextView scoreTextView;
private List<Flashcard> flashcards; private int currentCardIndex = 0; private int score = 0; private boolean isShowingQuestion = true;
// اسم ملف SharedPreferences private static final String PREF_NAME = "MyFlashcardPrefs"; private static final String PREF_SCORE_KEY = "score";
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
// ربط العناصر من ملف XML flashcardContainer = findViewById(R.id.flashcard_container); cardTextView = flashcardContainer.findViewById(R.id.card_text_view); nextCardButton = findViewById(R.id.next_card_button); scoreTextView = findViewById(R.id.score_text_view);
// تحميل النقاط المحفوظة loadScore();
// إعداد قائمة البطاقات setupFlashcards();
// عرض أول بطاقة displayCurrentCard();
// التعامل مع النقر على البطاقة (للقلب) flashcardContainer.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { flipCard(); } });
// التعامل مع النقر على زر البطاقة التالية nextCardButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { goToNextCard(); } }); }
private void setupFlashcards() { flashcards = new ArrayList<>(); flashcards.add(new Flashcard("What is the capital of France?", "Paris")); flashcards.add(new Flashcard("What is the largest planet in our solar system?", "Jupiter")); flashcards.add(new Flashcard("Who wrote 'Hamlet'?", "William Shakespeare")); // يمكنك إضافة المزيد من البطاقات هنا }
private void displayCurrentCard() { if (flashcards.isEmpty()) { cardTextView.setText("No more cards!"); return; } cardTextView.setText(flashcards.get(currentCardIndex).getQuestion()); isShowingQuestion = true; }
private void flipCard() { if (isShowingQuestion) { cardTextView.setText(flashcards.get(currentCardIndex).getAnswer()); score++; // زيادة النقاط عند قلب البطاقة (هذا مثال يمكنك تعديله) updateScoreText(); } else { cardTextView.setText(flashcards.get(currentCardIndex).getQuestion()); } isShowingQuestion = !isShowingQuestion; }
private void goToNextCard() { currentCardIndex = (currentCardIndex + 1) % flashcards.size(); displayCurrentCard(); }
private void updateScoreText() { scoreTextView.setText("Score: " + score); saveScore(); // حفظ النقاط فوراً }
// حفظ النقاط باستخدام SharedPreferences private void saveScore() { SharedPreferences sharedPref = getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPref.edit(); editor.putInt(PREF_SCORE_KEY, score); editor.apply(); // تطبيق التغييرات بشكل غير متزامن }
// تحميل النقاط المحفوظة private void loadScore() { SharedPreferences sharedPref = getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); score = sharedPref.getInt(PREF_SCORE_KEY, 0); // القيمة الافتراضية هي 0 updateScoreText(); }}
--
مميزات اضافية لبرمجة تطبيق بطاقات تعليمية Flashcards
بعد إضافة هذه الميزات ستجعل تطبيقك أكثر احترافية وفائدة.
سأقدم لك خطوات مفصلة لكل ميزة على حدة، لتبدأ مباشرة في تطوير تطبيقك.
1. إضافة شاشة لإضافة بطاقات جديدة
للسماح للمستخدم بإضافة بطاقات جديدة، تحتاج إلى إنشاء نشاط (Activity)
جديد بواجهة خاصة، ثم حفظ البيانات.
الخطوة الأولى: إنشاء النشاط الجديد (Activity)
في أندرويد ستوديو، انقر بزر الماوس الأيمن على حزمة مشروعك
(مثلاً: com.example.myflashcardsapp).
- اختر New > Activity > Empty Views Activity.
- أعطِ النشاط اسماً، وليكن AddCardActivity.
- انقر Finish. سيتم إنشاء ملفين : AddCardActivity.java و activity_add_card.xml.
الخطوة الثانية : تصميم الواجهة (activity_add_card.xml)
سنضع حقلين لإدخال السؤال والإجابة، وزر لحفظ البطاقة :
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="24dp"
android:gravity="center_horizontal">
<EditText
android:id="@+id/question_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="أدخل السؤال هنا"
android:padding="12dp"
android:layout_marginBottom="16dp"/>
<EditText
android:id="@+id/answer_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="أدخل الإجابة هنا"
android:padding="12dp"
android:layout_marginBottom="24dp"/>
<Button
android:id="@+id/save_card_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="حفظ البطاقة"/>
</LinearLayout>
--
الخطوة الثالثة: برمجة المنطق (AddCardActivity.java)
هنا، سنحصل على البيانات من الحقول ونحفظها باستخدام SharedPreferences
على شكل ملف JSON لتخزين قائمة كاملة من البطاقات :
Java
import androidx.appcompat.app.AppCompatActivity;import android.content.Context;import android.content.SharedPreferences;import android.os.Bundle;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;import com.google.gson.Gson;import com.google.gson.reflect.TypeToken;import java.lang.reflect.Type;import java.util.ArrayList;import java.util.List;
public class AddCardActivity extends AppCompatActivity {
private EditText questionEditText; private EditText answerEditText; private Button saveButton;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_card);
questionEditText = findViewById(R.id.question_edit_text); answerEditText = findViewById(R.id.answer_edit_text); saveButton = findViewById(R.id.save_card_button);
saveButton.setOnClickListener(v -> saveNewCard()); }
private void saveNewCard() { String question = questionEditText.getText().toString(); String answer = answerEditText.getText().toString();
if (question.isEmpty() || answer.isEmpty()) { Toast.makeText(this, "يرجى ملء كل الحقول", Toast.LENGTH_SHORT).show(); return; }
SharedPreferences sharedPref = getSharedPreferences("MyFlashcardPrefs", Context.MODE_PRIVATE); String jsonCards = sharedPref.getString("flashcards_list", null); Gson gson = new Gson(); Type type = new TypeToken<ArrayList<Flashcard>>() {}.getType(); List<Flashcard> flashcards = jsonCards == null ? new ArrayList<>() : gson.fromJson(jsonCards, type); // إضافة بطاقة جديدة flashcards.add(new Flashcard(question, answer)); // تحويل القائمة إلى JSON وحفظها SharedPreferences.Editor editor = sharedPref.edit(); String updatedJson = gson.toJson(flashcards); editor.putString("flashcards_list", updatedJson); editor.apply();
Toast.makeText(this, "تم حفظ البطاقة بنجاح!", Toast.LENGTH_SHORT).show(); finish(); // العودة إلى الشاشة الرئيسية }}
--
* ملاحظة : ستحتاج إلى إضافة مكتبة Gson لتحويل كائنات جافا إلى JSON.
أضف هذا السطر إلى ملف build.gradle (Module:app) الخاص بك :
implementation 'com.google.code.gson:gson:2.8.9'
الخطوة الرابعة: ربط النشاطين
في ملف MainActivity.java، أضف زرًا للانتقال إلى AddCardActivity (ثم اربطه في الكود) في ملف activity_main.xml .
Java
// في MainActivity.java داخل onCreate
Button addCardButton = findViewById(R.id.add_card_button);
addCardButton.setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, AddCardActivity.class);
startActivity(intent);
});
--
2. تطبيق خوارزمية ذكية لعرض البطاقات
بدلاً من عرض البطاقات بشكل تسلسلي، سنستخدم خوارزمية تكرار متباعد بسيطة.
سنضيف مستوى صعوبة لكل بطاقة، ونعرض البطاقات الأصعب بشكل متكرر.
الخطوة الأولى: تعديل كلاس Flashcard.java
أضف خاصية difficultyLevel إلى كلاس Flashcard :
Java
// في Flashcard.java
public class Flashcard {
private String question;
private String answer;
private int difficultyLevel = 0; // 0 = easy, higher = hard
public Flashcard(String question, String answer) {
this.question = question;
this.answer = answer;
}
// أضف هذه الدوال
public int getDifficultyLevel() {
return difficultyLevel;
}
public void setDifficultyLevel(int difficultyLevel) {
this.difficultyLevel = difficultyLevel;
}
// ... باقي الدوال
}
--
* ملاحظة : ستحتاج إلى تعديل كود AddCardActivity و MainActivity
ليتعامل مع هذه الخاصية الجديدة عند حفظ وتحميل البيانات.
الخطوة الثانية : تعديل المنطق في MainActivity.java
سنبدل طريقة عرض البطاقة التالية باستخدام خوارزمية تعتمد على الصعوبة :
Java
// في MainActivity.java
// قم بتحديث دالة goToNextCard()
private void goToNextCard() {
// خوارزمية بسيطة: اختر بطاقة عشوائية، لكن مع تفضيل البطاقات الصعبة
List<Flashcard> difficultCards = new ArrayList<>();
for (Flashcard card : flashcards) {
if (card.getDifficultyLevel() > 0) {
difficultCards.add(card);
}
}
Flashcard nextCard;
if (!difficultCards.isEmpty() && Math.random() < 0.7) { // 70% chance to pick a difficult card
nextCard = difficultCards.get((int) (Math.random() * difficultCards.size()));
} else {
nextCard = flashcards.get((int) (Math.random() * flashcards.size()));
}
// ابحث عن فهرس البطاقة المختارة
currentCardIndex = flashcards.indexOf(nextCard);
// تحديث الواجهة
displayCurrentCard();
}
// أضف دوال لتحديث صعوبة البطاقة (مثلاً عند إجابة خاطئة)
private void markCardAsDifficult() {
Flashcard currentCard = flashcards.get(currentCardIndex);
currentCard.setDifficultyLevel(currentCard.getDifficultyLevel() + 1);
// قم بحفظ القائمة المحدثة في SharedPreferences
}
--
3. إضافة مؤثرات صوتية ومرئية
الخطوة الأولى: المؤثرات الصوتية
- أنشئ مجلدًا جديدًا باسم raw داخل مجلد res
(انقر بزر الماوس الأيمن على res ثم New > Directory).
- ضع ملفات الصوت (بصيغة mp3 أو wav) في هذا المجلد. مثلاً، flip_sound.mp3.
الخطوة الثانية : برمجة الصوت في MainActivity.java :
Java
// في MainActivity.java
import android.media.MediaPlayer;
public class MainActivity extends AppCompatActivity {
// ...
private MediaPlayer mediaPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
mediaPlayer = MediaPlayer.create(this, R.raw.flip_sound); // يجب أن يكون لديك ملف flip_sound.mp3 في مجلد raw
}
private void flipCard() {
if (isShowingQuestion) {
// ...
if (mediaPlayer != null) {
mediaPlayer.start(); // تشغيل الصوت عند قلب البطاقة
}
}
// ...
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.release(); // تحرير الموارد عند إغلاق التطبيق
mediaPlayer = null;
}
}
}
--
الخطوة الثالثة : المؤثرات المرئية
سنستخدم مؤثر تحول بسيط (Crossfade) عند قلب البطاقة ليعطي شعورًا بصريًا أفضل.
- افتح ملف res/layout/flashcard_layout.xml.
- قم بتغيير TextView إلى ViewSwitcher أو FrameLayout وادخل
TextView بداخله. هذا مثال بسيط لتحقيق مؤثر بصري :
// في MainActivity.java
// في دالة flipCard()
private void flipCard() {
// ...
// تطبيق مؤثر بصري (تلاشي)
cardTextView.animate().alpha(0f).setDuration(200).withEndAction(() -> {
// تغيير النص
if (isShowingQuestion) {
cardTextView.setText(flashcards.get(currentCardIndex).getAnswer());
} else {
cardTextView.setText(flashcards.get(currentCardIndex).getQuestion());
}
cardTextView.animate().alpha(1f).setDuration(200).start();
}).start();
isShowingQuestion = !isShowingQuestion;
// ...
}
--
الخاتمة :
في الختام، يظهر أن رحلة برمجة تطبيقات أندرويد باستخدام جافا هي عملية
متكاملة تبدأ من تصميم واجهة المستخدم (XML) وتمر بإنشاء نموذج البيانات
وصولاً إلى تطبيق المنطق البرمجي الفعلي. لقد تعلمنا كيف نقوم بإنشاء تطبيق
بسيط للبطاقات التعليمية، وكيفية إضافة ميزات متقدمة مثل حفظ النقاط
(SharedPreferences)، وتطوير خوارزميات ذكية، ودمج مؤثرات صوتية ومرئية.
إن هذا المشروع يمثل حجر الأساس الذي يمكنك البناء عليه لتصبح مبرمج أندرويد محترفاً.
استمر في التجربة والتعلم، وستكتشف أن إمكانيات تطوير التطبيقات لا حدود لها.