طَبِّقْهاتعلّم المبدأ، وطبّقه بيدكمقرر 251 · برمجة الأجهزة الذكية
الدرس 18 · الوحدة 8: التفاعل مع الحساسات والأجهزة الذكية باستخدام APIs

الكاميرا: التقاط صورة وعرضها

التقاط الصور وعرضها باحترام الخصوصيّة. ⏱ نحو 40 دقيقة.

بعد هذا الدرس ستستطيع أن:
  • تلتقط إطارًا من الكاميرا وتعرضه.
  • تجمع اللقطات في معرضٍ بالتحديث الدالّيّ.
  • تراعي الإذن والخصوصيّة والطاقة.

١الكاميرا في التطبيقات

الكاميرا من أقوى المستشعرات: تصوير، مسح رموز QR، التعرّف على المستندات. تدفّقها «إطاراتٌ» متتالية، ونلتقط منها لقطة عند الطلب.

٢التقاط وعرض

نشترك في الكاميرا؛ كل «التقاط» يعطي إطارًا نعرضه. نحفظ آخر لقطةٍ في حالة:

import { useState, useEffect } from 'react';import { View, Text, StyleSheet } from 'react-native';import SmartDevice from 'smartdevice'; export default function App() {  const [shot, setShot] = useState(null);   useEffect(() => {    const stop = SmartDevice.on('camera', (c) => {      if (c.active) setShot(c.frame);           // التقطت لقطة    });    return stop;  }, []);   return (    <View style={styles.box}>      <View style={styles.viewfinder}>        <Text style={styles.frame}>{shot || 'اضغط «التقط»'}</Text>      </View>      <Text style={styles.cap}>{shot ? 'آخر لقطة: ' + shot : 'لا توجد صورة بعد'}</Text>    </View>  );} const styles = StyleSheet.create({  box: { padding: 16, alignItems: 'center' },  viewfinder: { width: 220, height: 150, backgroundColor: '#111', borderRadius: 14, alignItems: 'center', justifyContent: 'center' },  frame: { color: '#fff', fontSize: 30 },  cap: { marginTop: 12, color: '#555' },});

كل ضغطةٍ على «التقط» تبدّل الإطار. في الواقع يكون الإطار صورةً؛ هنا رمزٌ تمثيليّ.

٣معرض اللقطات

نجمع اللقطات في قائمةٍ (ألبوم). كل التقاطٍ يُضاف إلى المصفوفة:

import { useState, useEffect } from 'react';import { View, Text, FlatList, StyleSheet } from 'react-native';import SmartDevice from 'smartdevice'; export default function App() {  const [album, setAlbum] = useState([]);   useEffect(() => {    return SmartDevice.on('camera', (c) => {      if (c.active) setAlbum((prev) => [{ id: String(c.ts), frame: c.frame }, ...prev]);    });  }, []);   return (    <View style={{ padding: 12 }}>      <Text style={styles.h}>الألبوم ({album.length})</Text>      <FlatList        horizontal        data={album}        keyExtractor={(it) => it.id}        renderItem={({ item }) => <Text style={styles.thumb}>{item.frame}</Text>}        ListEmptyComponent={<Text style={styles.empty}>التقط صورًا لتظهر هنا</Text>}      />    </View>  );} const styles = StyleSheet.create({  h: { fontWeight: 'bold', fontSize: 16, marginBottom: 8 },  thumb: { fontSize: 34, padding: 8, backgroundColor: '#FFF3E0', borderRadius: 10, marginEnd: 8 },  empty: { color: '#888' },});

استخدمنا شكل التحديث الدالّيّ setAlbum(prev => …) لأن الجديد يعتمد على السابق.

توقّع وتحقّق

الكاميرا تُستخدم في:

قبل استخدام الكاميرا:

لإضافة عنصرٍ يعتمد على السابق نستخدم:

تدفّق الكاميرا عبارة عن:

الخلاصة

تحدٍّ برمجي: زرّ التقاط

متقدم

اعرض آخر لقطةٍ من الكاميرا.

المطلوب:
  • حالة shot تبدأ فارغة.
  • اشترك في «camera» بـ SmartDevice.on واحفظ c.frame عند c.active.
  • <Text testID="shot"> يعرض اللقطة أو «—».
👀 اعرض الناتج المطلوب (وجرّبه)
✓ التحقق الآلي من حلّك:
  • الكود يعمل بلا أخطاء في Console
  • يبدأ فارغًا «—»
  • اشترك في camera
  • حفظ الإطار frame

💡 تلميح 1
اشترك: SmartDevice.on('camera', c => …).
💡 تلميح 2
قبل أيّ التقاطٍ تكون اللقطة فارغة فيظهر «—».

حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.

import { useState, useEffect } from 'react';import { View, Text, StyleSheet } from 'react-native';import SmartDevice from 'smartdevice'; export default function App() {  const [shot, setShot] = useState(null);  useEffect(() => {    return SmartDevice.on('camera', (c) => {      if (c.active) setShot(c.frame);    });  }, []);  return (    <View style={{ padding: 20 }}>      <Text testID="shot" style={styles.s}>{shot || '—'}</Text>    </View>  );} const styles = StyleSheet.create({ s: { fontSize: 30 } });
انتقل إلى تقييم الدرساختيار من متعدد، وصح وخطأ، وأكمل الفراغ، وتتبّع الناتج.ابدأ التقييم ←

📝 معلم؟ أرسل ملاحظة للمؤلف عن هذا الدرس