React Native / Expo Camera

Expo Camera

Утасны камер ашиглах нь React Native-н хамгийн сонирхолтой функцүүдийн нэг. expo-camera package ашиглан зураг авах, видео бичих, QR код уншихаас эхлэн бүх боломжтой. Хамгийн сайн нь — JavaScript-аар л хийнэ, Swift эсвэл Kotlin огт мэдэх шаардлагагүй!

expo-camera суулгах

bash
npx expo install expo-camera

expo install ашиглах нь чухал — npm install биш. Учир нь expo install таны Expo SDK-н хувилбарт тохирсон зөв хувилбарыг суулгадаг.

Камерын зөвшөөрөл авах

iOS болон Android хоёулан камер ашиглахын өмнө хэрэглэгчийн зөвшөөрөл шаардана. useCameraPermissions hook ашиглан зөвшөөрлийг хялбархан удирдана:

jsx
import { CameraView, useCameraPermissions } from "expo-camera";
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";

export default function CameraScreen() {
  const [permission, requestPermission] = useCameraPermissions();

  // Зөвшөөрлийн байдлыг шалгаж байна
  if (!permission) {
    return <View style={styles.container} />;
  }

  // Зөвшөөрөл олгогдоогүй
  if (!permission.granted) {
    return (
      <View style={styles.center}>
        <Text style={styles.message}>
          Камер ашиглахын тулд зөвшөөрөл шаардлагатай
        </Text>
        <TouchableOpacity style={styles.btn} onPress={requestPermission}>
          <Text style={styles.btnText}>Зөвшөөрөл олгох</Text>
        </TouchableOpacity>
      </View>
    );
  }

  // Зөвшөөрөл байна — камер харуулна
  return (
    <View style={styles.container}>
      <CameraView style={styles.camera} facing="back" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#0b1120",
  },
  center: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#0b1120",
    padding: 24,
    gap: 16,
  },
  message: {
    color: "#94a3b8",
    textAlign: "center",
    fontSize: 15,
    lineHeight: 22,
  },
  camera: {
    flex: 1,
  },
  btn: {
    backgroundColor: "#22d3ee",
    paddingHorizontal: 24,
    paddingVertical: 12,
    borderRadius: 10,
  },
  btnText: {
    color: "#0b1120",
    fontWeight: "700",
    fontSize: 15,
  },
});

Зураг авах ба камер сэлгэх

useRef ашиглан камерт хандаж takePictureAsync() дуудна. facing state-р урд/арын камер сэлгэнэ:

jsx
import { useRef, useState } from "react";
import { CameraView, useCameraPermissions } from "expo-camera";
import {
  View,
  Text,
  Image,
  TouchableOpacity,
  StyleSheet,
  SafeAreaView,
} from "react-native";

export default function CameraApp() {
  const [permission, requestPermission] = useCameraPermissions();
  const [facing, setFacing] = useState("back");
  const [photo, setPhoto] = useState(null);
  const cameraRef = useRef(null);

  if (!permission?.granted) {
    return (
      <View style={styles.center}>
        <Text style={styles.message}>Камерын зөвшөөрөл шаардлагатай</Text>
        <TouchableOpacity style={styles.btn} onPress={requestPermission}>
          <Text style={styles.btnText}>Зөвшөөрөл олгох</Text>
        </TouchableOpacity>
      </View>
    );
  }

  const takePicture = async () => {
    if (!cameraRef.current) return;
    const result = await cameraRef.current.takePictureAsync({
      quality: 0.8, // 0–1 чанарын хэмжэ
      base64: false, // base64 хэлбэрт шаардлагатай бол true
      skipProcessing: false,
    });
    setPhoto(result.uri);
  };

  const toggleFacing = () => {
    setFacing((prev) => (prev === "back" ? "front" : "back"));
  };

  const retake = () => setPhoto(null);

  // Зураг авсан бол preview харуулна
  if (photo) {
    return (
      <SafeAreaView style={styles.container}>
        <Image source={{ uri: photo }} style={styles.preview} />
        <View style={styles.previewActions}>
          <TouchableOpacity style={styles.secondaryBtn} onPress={retake}>
            <Text style={styles.secondaryText}>Дахин авах</Text>
          </TouchableOpacity>
          <TouchableOpacity style={styles.btn}>
            <Text style={styles.btnText}>Хадгалах</Text>
          </TouchableOpacity>
        </View>
      </SafeAreaView>
    );
  }

  return (
    <SafeAreaView style={styles.container}>
      <CameraView ref={cameraRef} style={styles.camera} facing={facing}>
        {/* Камерын дотор харагдах товчнууд */}
        <View style={styles.controls}>
          {/* Камер сэлгэх */}
          <TouchableOpacity style={styles.iconBtn} onPress={toggleFacing}>
            <Text style={styles.iconText}>🔄</Text>
          </TouchableOpacity>

          {/* Зураг авах товч */}
          <TouchableOpacity style={styles.shutterBtn} onPress={takePicture}>
            <View style={styles.shutterInner} />
          </TouchableOpacity>

          {/* Нөөц зай */}
          <View style={styles.iconBtn} />
        </View>
      </CameraView>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#000",
  },
  center: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    backgroundColor: "#0b1120",
    padding: 24,
    gap: 16,
  },
  message: {
    color: "#94a3b8",
    textAlign: "center",
    fontSize: 15,
  },
  camera: {
    flex: 1,
    justifyContent: "flex-end",
  },
  controls: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "space-between",
    paddingHorizontal: 32,
    paddingBottom: 40,
  },
  iconBtn: {
    width: 50,
    height: 50,
    justifyContent: "center",
    alignItems: "center",
  },
  iconText: {
    fontSize: 28,
  },
  shutterBtn: {
    width: 72,
    height: 72,
    borderRadius: 36,
    backgroundColor: "rgba(255,255,255,0.3)",
    justifyContent: "center",
    alignItems: "center",
    borderWidth: 3,
    borderColor: "#fff",
  },
  shutterInner: {
    width: 56,
    height: 56,
    borderRadius: 28,
    backgroundColor: "#fff",
  },
  preview: {
    flex: 1,
  },
  previewActions: {
    flexDirection: "row",
    justifyContent: "center",
    gap: 16,
    padding: 24,
    backgroundColor: "#0b1120",
  },
  btn: {
    backgroundColor: "#22d3ee",
    paddingHorizontal: 24,
    paddingVertical: 12,
    borderRadius: 10,
    flex: 1,
    alignItems: "center",
  },
  btnText: {
    color: "#0b1120",
    fontWeight: "700",
    fontSize: 15,
  },
  secondaryBtn: {
    backgroundColor: "#1e293b",
    paddingHorizontal: 24,
    paddingVertical: 12,
    borderRadius: 10,
    flex: 1,
    alignItems: "center",
    borderWidth: 1,
    borderColor: "#475569",
  },
  secondaryText: {
    color: "#f1f5f9",
    fontWeight: "600",
    fontSize: 15,
  },
});

app.json дахь зөвшөөрлийн тохиргоо

Expo Go дээр ажиллахад автомат зөвшөөрдөг боловч EAS Build-р угсарч App Store/Play Store-д нийтлэхэд app.json-д зааж өгнэ:

json
{
  "expo": {
    "plugins": [
      [
        "expo-camera",
        {
          "cameraPermission": "Зураг авахад камер ашиглана",
          "microphonePermission": "Видео бичихэд микрофон ашиглана",
          "recordAudioAndroid": true
        }
      ]
    ]
  }
}

Хэрэглэгчид зөвшөөрлийн цонх нээгдэх үед энэ текст харагдана. Монгол хэлээр бичихийг мартуузай!

Утасны камерыг ердөө 50 мөр кодоор удирдаж чадна гэдэг гайхалтай биш гэж үү? Энэ нь React Native-н хамгийн том давуу талуудын нэг — native device API-уудыг JavaScript-ээр л ажиллуулна.

Дараагийн хичээлд:

Expo Image Picker — галерейгаас зураг сонгох, камераас зураг авах боломжийг нэг package-р хэрхэн хийх талаар сурна.