مقدّمة
لقد ذكرنا في مقال سابق كيفيّة استخدام كاميرا الهاتف في نظام آندرويد من أجل التقاط صورة واستخدامها في تطبيقنا، في هذا المقال، سنغطّي كيفيّة تصوير مقطع فيديو وعرضه في تطبيقنا من خلال عنصر VideoView .
تصميم التطبيق
سنحتاج في واجهة تطبيقنا إلى عنصر VideoView، والذي سيتم استخدامه في عرض مقطع الفيديو الذي تمَّ تصويره بواسطة تطبيق الكاميرا الموجود في الجهاز. كما سنحتاج أيضاً إلى زرّ ينقل المُستخدم إلى تطبيق الكاميرا من أجل بدء تصوير الفيديو. بالنسبة لي، فقد قمت بترتيب الواجهة كالآتي:
- سيتم احتواء جميع عناصر الواجهة في RelativeLayout.
- سيتم وضع الزرّ في أسفل الواجهة.
- سيتم وضع عنصر VideoView أعلى الواجهة، فوق زرّ التصوير.
بحيث ستظهر الواجهة كالتالي:
ما يلي كود XML الخاصّ بالواجهة:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" tools:context=".MainActivity"> <VideoView android:id="@+id/VideoView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/button_recordvid" /> <Button android:id="@+id/button_recordvid" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:text="تصوير فيديو" /> </RelativeLayout> |
برمجة التطبيق
مختصر عمل التطبيق
إنَّ مختصر آليّة عمل التطبيق ستكون كالآتي:
- عند ضغط المستخدم على زرّ تصوير فيديو، فسيتم إنشاء Intent جديدة لاستدعاء تطبيق الكاميرا الموجود في الجهاز.
- بعد انتهاء المستخدم من التصوير والخروج من تطبيق الكاميرا، سيقوم هذا التطبيق (الكاميرا) بإرجاع نتيجة لتطبيقنا تحتوي مقطع الفيديو الذي تمَّ تصويره، فنقوم باستخدام دالّة ()onActivityResult للحصول على المقطع.
- نقوم بتشغيل مقطع الفيديو في عنصر VideoView.
التهيئة
قبل البدء ببرمجة ما هو أساسيٌّ من التطبيق، يجب علينا إضافة سطر معيَّن إلى ملفّ الmanifset لتفعيل خاصيّة استخدام كاميرا الهاتف، كما يجب تفعيل أذونات استخدام الكاميرا والميكروفون، فنقوم بإضافة الأسطر التالية في ترميز <manifest> من ملفّ AndroidManifest.xml:
1 2 3 |
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="true"/> <uses-permission android:name="android.permission.RECORD_AUDIO" /> |
في حال كنت تستخدم Android Emulator، فيجب عليك تفعيل الأذونات يدويّاً من الإعدادات (Settings) للتطبيق قبل البدء باستخدامه، إذ لن تكون الأذونات مُفعّلة في الوضع الطبيعي، ممّا يتسبَّب في انهيار التطبيق عند استدعاء تطبيق الكاميرا.
تصوير فيديو وتشغيله
سنقوم أوّلاً بوصل زرّ Record Video وعنصر VideoView الموجودان في الواجهة ببرنامجنا من خلال دالّة ()findViewById كالتالي:
1 2 3 4 5 6 7 8 9 10 11 |
public class MainActivity extends AppCompatActivity { Button recordVideo_ref; VideoView videoView_ref; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recordVideo_ref = findViewById(R.id.button_recordvid); videoView_ref = findViewById(R.id.VideoView); |
بعد ذلك سنقوم بالتحقُّق ممّا إن كان الهاتف يحتوي على كاميرا يمكننا استخدامها، وسنلجأ لدالّة ()hasSystemFeature الموجودة في كلاس PackageManager لنتمكَّن من ذلك، وفي حال عدم وجودها، فسنُظهر له رسالة Toast:
1 2 3 4 |
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) { Toast error = Toast.makeText(getApplicationContext(), "Device lacks a camera!", Toast.LENGTH_LONG); error.show(); } |
سنقوم بتعريف متغيِّر من نوع boolean لنخزِّن فيه حالة ما إن كان الجهاز يحتوي كاميرا أم لا، وذلك حتّى نمنعه من محاولة فتح تطبيق الكاميرا من الأساس، فسنقوم بتعريف المتغيِّر hasCamera لذلك واستخدامه كما يلي:
1 2 3 4 |
public class MainActivity extends AppCompatActivity { Button recordVideo_ref; VideoView videoView_ref; boolean hasCamera = true; |
1 2 3 4 5 |
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) { Toast error = Toast.makeText(getApplicationContext(), "Device lacks a camera!", Toast.LENGTH_LONG); error.show(); hasCamera = false; } |
الآن يمكننا البدء ببرمجة حالة الضغط على زرّ “تصوير فيديو”، وذلك من خلال ()setOnClickListener. بعد ضغط المستخدم على الزرّ، سنتأكَّد أوّلاً ممّا إن كان الهاتف يحتوي على كاميرا، وفي حال توافر فيه، فسنقوم بإنشاء Intent جديدة لاستدعاء تطبيق الكاميرا، بحيث سنقوم بتمرير القيمة ACTION_VIDEO_CAPTURE كمعامل لدالّة البناء (Constructor). بعد ذلك سنقوم باستدعاء دالّة ()resolveActivity لنرى ما إن تمَّ إنشاء الIntent بدون مشاكل (في حال إرجاع أي قيمة عدا null، فهذا يعني عدم وجود مشاكل):
1 2 3 4 5 6 |
recordVideo_ref.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(hasCamera) { Intent recordVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); if (recordVideoIntent.resolveActivity(getPackageManager()) != null) |
الآن سنقوم باستخدام دالّة ()startActivityForResult، وسنجعل رمز الطلب (requestCode) هو 1 (يمكن أن يكون أي رقم، ولكن المهم أن تحفظه لأنّنا سنستخدمه لاحقاً عند استلام نتيجة الIntent):
1 2 3 4 5 6 7 8 9 10 11 |
recordVideo_ref.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(hasCamera) { Intent recordVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); if (recordVideoIntent.resolveActivity(getPackageManager()) != null) { startActivityForResult(recordVideoIntent, 1); } } } }); |
الآن سنقوم بإعادة تعريف (أي Override) دالّة ()onActivityResult، والتي ستستلم النتيجة من تطبيق الكاميرا، بحيث سيتم إرجاع النتيجة باستخدام نفس رمز الطلب الذي أدخلناه في الكود أعلاه، ألا وهو 1، كما سيتم إرجاع ما إن كانت العمليّة قد تمّت بنجاح من خلال المتغيِّر resultCode. فسيكون الكود كالتالي:
1 2 3 |
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == 1 && resultCode == RESULT_OK) { |
سيحتوي المعامل “data” على بيانات المقطع المُصوَّر، ويمكننا استرجاعه من خلال دالّة ()getData، بحيث سيتم إرجاع وصلة من نوع URI تشير إلى مكان تخزين المقطع، وبالتالي يمكننا عرض المقطع في عنصر VideoView كالتالي:
1 |
videoView_ref.setVideoURI(data.getData()); |
أخيراً، نقوم بتشغيل المقطع باستخدام دالّة ()start الموجودة في VideoView:
1 |
videoView_ref.start(); |
الكود النهائي
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
public class MainActivity extends AppCompatActivity { Button recordVideo_ref; VideoView videoView_ref; boolean hasCamera = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recordVideo_ref = findViewById(R.id.button_recordvid); videoView_ref = findViewById(R.id.VideoView); if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) { Toast error = Toast.makeText(getApplicationContext(), "الهاتف لا يحتوي على كاميرا!", Toast.LENGTH_LONG); error.show(); hasCamera = false; } recordVideo_ref.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(hasCamera) { Intent recordVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); if (recordVideoIntent.resolveActivity(getPackageManager()) != null) { startActivityForResult(recordVideoIntent, 1); } } } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == 1 && resultCode == RESULT_OK) { videoView_ref.setVideoURI(data.getData()); videoView_ref.start(); } } } |
عند تجربة التطبيق في محاكي آندرويد، يمكنك تصوير مقطع تظهر فيه مُربّعات صغيرة ويتحرَّك أعلاها مُربَّع يتغيَّر لونه كلّ بضع ثوانٍ:
ويمكنك أيضاً تجربة التطبيق على هاتف حقيقي لتصوير مقطع والتأكُّد من أنّه يعمل بالشكل المطلوب.
فكرة حلوة شكرا على النشر