Android?Camera開發(fā)實現(xiàn)可復(fù)用的相機(jī)組件
本文實例為大家分享了Android Camera實現(xiàn)可復(fù)用相機(jī)組件的具體代碼,供大家參考,具體內(nèi)容如下
若自己的應(yīng)用需要使用camera,有兩種解決方案。
1. 使用Intent調(diào)用自帶的Camera程序
2. 使用Camera API在程序中構(gòu)造自己的Camera。
本文主要講解第二種。
構(gòu)造一個相機(jī)APP,通常需要六個步驟
1. 聲明Manifest的相機(jī)權(quán)限
2. 創(chuàng)建一個相機(jī)預(yù)覽類(繼承SurfaceView)
3. 創(chuàng)建一個類實現(xiàn)相機(jī)拍照之后的回調(diào)函數(shù)
本文將一步步帶你實現(xiàn)上述三個步驟。
1. 聲明Manifest的相機(jī)權(quán)限。
應(yīng)為我們需要寫文件與調(diào)用相機(jī),所以在你的manifest文件中加上。
<uses-permission android:name="android.permission.CAMERA" /> ?<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2. 創(chuàng)建一個相機(jī)預(yù)覽類
由于相機(jī)的預(yù)覽是使用的SurfaceView,所以這里我們創(chuàng)建一個SurfaceView的子類。
為了讓這個View所見即所得,我們將其設(shè)置為4/3的比例。重寫它的onMeasure方法
代碼如下:
package com.example.cameratutorial; ? import android.content.Context; ? import android.util.Log; import android.view.SurfaceView; ? /** ?* @author CTGU小龍同學(xué) 2014-6-21 ?*/ public class CameraSurfaceView extends SurfaceView { ?? ?private static final String TAG = "CameraSurfaceView"; ?? ?// 用四比三的比例 ?? ?public static double RATIO = 3.0 / 4.0; ? ?? ?/** ?? ? * @param context ?? ? */ ?? ?public CameraSurfaceView(Context context) { ?? ??? ?super(context); ? ?? ?} ? ?? ?@Override ?? ?protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ?? ??? ? ?? ??? ?int height = MeasureSpec.getSize(heightMeasureSpec); ?? ??? ?int width = MeasureSpec.getSize(widthMeasureSpec); ?? ??? ?Log.d("Measured", "before width" + width + "height" + height); ? ?? ??? ?boolean isWidthLonger; ?? ??? ?int longSide; ?? ??? ?int shortSide; ?? ??? ?// 以短邊為準(zhǔn)確定一下長邊 ?? ??? ?if (width < height) { ?? ??? ??? ?height = (int) (width / RATIO); ?? ??? ??? ?isWidthLonger = false; ? ?? ??? ?} else { ?? ??? ??? ?width = (int) (height / RATIO); ?? ??? ??? ?isWidthLonger = true; ?? ??? ?} ? ?? ??? ?Log.d("Measured", "after width" + width + "height" + height); ?? ??? ?setMeasuredDimension(width, height); ? ?? ?} ? }
3. 現(xiàn)在我們使用一個實現(xiàn)了SurfaceHolder.Callback, Camera.PictureCallback 的Fragment來把我們需要的組件都封裝起來。
代碼如下:
package com.example.cameratutorial; ? import java.io.*; import java.util.*; import android.app.Activity; import android.app.Fragment; import android.graphics.*; ? import android.graphics.Bitmap.CompressFormat; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.Size; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.*; ? ? import android.widget.RelativeLayout; import android.widget.Toast; ? /** ?* @author CTGU小龍同學(xué) 2014-6-21 ?*/ public class CameraFragment extends Fragment implements SurfaceHolder.Callback, Camera.PictureCallback { ?? ?private Camera mCamera; ?? ?// CameraPreview的holder ?? ?private SurfaceHolder mSurfaceHolder; ?? ?private CameraSurfaceView preview; ?? ?private int mFrontCameraId = -1; ?? ?private int mBackCameraId = -1; ? ?? ?@Override ?? ?public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ? ?? ??? ?preview = new CameraSurfaceView(getActivity()); ?? ??? ?preview.getHolder().addCallback(this); ? ?? ??? ?RelativeLayout layout = new RelativeLayout(getActivity()); ?? ??? ?layout.addView(preview); ? ?? ??? ?return layout; ? ?? ?} ? ?? ?@Override ?? ?public void onAttach(Activity activity) { ?? ??? ?super.onAttach(activity); ?? ??? ?findAvailableCameras(); ? ?? ?} ? ?? ?@Override ?? ?public void onResume() { ? ?? ??? ?super.onResume(); ?? ??? ?Log.d("camera", "mFrontCameraId" + mFrontCameraId); ?? ??? ?Log.d("camera", "mbackCameraId" + mBackCameraId); ?? ??? ?if (mBackCameraId != -1) { ? ?? ??? ??? ?mCamera = Camera.open(mBackCameraId); ? ?? ??? ?} else { ?? ??? ??? ?Toast.makeText(getActivity(), "fialed to open camera", Toast.LENGTH_SHORT).show(); ?? ??? ?} ? ?? ?} ? ?? ?@Override ?? ?public void onPause() { ?? ??? ?super.onPause(); ? ?? ??? ?mCamera.stopPreview(); ?? ??? ?mCamera.release(); ?? ?} ? ?? ?/** ?? ? * 獲得可用的相機(jī),并設(shè)置前后攝像機(jī)的ID ?? ? */ ?? ?private void findAvailableCameras() { ? ?? ??? ?Camera.CameraInfo info = new CameraInfo(); ?? ??? ?int numCamera = Camera.getNumberOfCameras(); ?? ??? ?for (int i = 0; i < numCamera; i++) { ?? ??? ??? ?Camera.getCameraInfo(i, info); ?? ??? ??? ?// 找到了前置攝像頭 ?? ??? ??? ?if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { ?? ??? ??? ??? ?mFrontCameraId = info.facing; ?? ??? ??? ?} ?? ??? ??? ?// 招到了后置攝像頭 ?? ??? ??? ?if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { ?? ??? ??? ??? ?mBackCameraId = info.facing; ?? ??? ??? ?} ? ?? ??? ?} ? ?? ?} ? ?? ?/** ?? ? * 當(dāng)相機(jī)拍照時會回調(diào)該方法 ?? ? */ ?? ?@Override ?? ?public void onPictureTaken(byte[] data, Camera camera) { ?? ??? ?final Bitmap bitmap; ? ?? ??? ?final String path; ?? ??? ?try { ?? ??? ??? ?// /storage/emulated/0/Pictures/XXX.jpg ? ?? ??? ??? ?path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath() + "/" + new Date().toLocaleString() + ".jpg"; ?? ??? ??? ?Log.d("Path", path); ?? ??? ??? ?bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); ?? ??? ??? ?camera.stopPreview(); ? ?? ??? ??? ?final int displayOrientation = getCorrectOrientation(); ?? ??? ??? ?new Thread(new Runnable() { ? ?? ??? ??? ??? ?@Override ?? ??? ??? ??? ?public void run() { ?? ??? ??? ??? ??? ?FileOutputStream fos; ?? ??? ??? ??? ??? ?Matrix matrix = new Matrix(); ?? ??? ??? ??? ??? ?matrix.postRotate(displayOrientation); ?? ??? ??? ??? ??? ?Bitmap rotaBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); ? ?? ??? ??? ??? ??? ?try { ?? ??? ??? ??? ??? ??? ?fos = new FileOutputStream(path); ?? ??? ??? ??? ??? ??? ?rotaBitmap.compress(CompressFormat.JPEG, 100, fos); ?? ??? ??? ??? ??? ??? ?fos.close(); ?? ??? ??? ??? ??? ?} catch (Exception e) { ?? ??? ??? ??? ??? ??? ?// TODO Auto-generated catch block ?? ??? ??? ??? ??? ??? ?e.printStackTrace(); ?? ??? ??? ??? ??? ?} ? ?? ??? ??? ??? ?} ?? ??? ??? ?}).start(); ? ?? ??? ?} catch (Exception e) { ? ?? ??? ?} ?? ??? ?camera.startPreview(); ?? ?} ? ?? ?/** ?? ? * 讓預(yù)覽跟照片符合正確的方向。<br/> ?? ? * 因為預(yù)覽默認(rèn)是橫向的。如果是一個豎向的應(yīng)用,就需要把預(yù)覽轉(zhuǎn)90度<br/> ?? ? * 比如橫著時1280*960的尺寸時,1280是寬.<br/> ?? ? * 豎著的時候1280就是高了<br/> ?? ? * 這段代碼來自官方API。意思就是讓拍出照片的方向和預(yù)覽方向正確的符合設(shè)備當(dāng)前的方向(有可能是豎向的也可能使橫向的) ?? ? *? ?? ? */ ?? ?private int getCorrectOrientation() { ?? ??? ?android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); ?? ??? ?android.hardware.Camera.getCameraInfo(mBackCameraId, info); ?? ??? ?int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation(); ?? ??? ?int degrees = 0; ?? ??? ?switch (rotation) { ?? ??? ?case Surface.ROTATION_0: ?? ??? ??? ?degrees = 0; ?? ??? ??? ?break; ?? ??? ?case Surface.ROTATION_90: ?? ??? ??? ?degrees = 90; ?? ??? ??? ?break; ?? ??? ?case Surface.ROTATION_180: ?? ??? ??? ?degrees = 180; ?? ??? ??? ?break; ?? ??? ?case Surface.ROTATION_270: ?? ??? ??? ?degrees = 270; ?? ??? ??? ?break; ?? ??? ?} ? ?? ??? ?int result; ?? ??? ?if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { ?? ??? ??? ?result = (info.orientation + degrees) % 360; ?? ??? ??? ?result = (360 - result) % 360; // compensate the mirror ?? ??? ?} else { // back-facing ?? ??? ??? ?result = (info.orientation - degrees + 360) % 360; ?? ??? ?} ?? ??? ?Log.d("orientationResult", result + ""); ?? ??? ?return result; ?? ?} ? ?? ?public void takePicture() { ?? ??? ?mCamera.takePicture(null, null, this); ?? ?} ? ?? ?@Override ?? ?public void surfaceCreated(SurfaceHolder holder) { ?? ??? ?mSurfaceHolder = holder; ? ?? ??? ?startPreView(); ? ?? ?} ? ?? ?private void startPreView() { ?? ??? ?try { ?? ??? ??? ?mCamera.setPreviewDisplay(mSurfaceHolder); ?? ??? ??? ?setPreviewSize(); ?? ??? ??? ?setDisplayOrientation(); ?? ??? ??? ?mCamera.startPreview(); ?? ??? ?} catch (IOException e) { ?? ??? ??? ?// TODO Auto-generated catch block ?? ??? ??? ?e.printStackTrace(); ?? ??? ?} ? ?? ?} ? ?? ?private void setDisplayOrientation() { ?? ??? ?int displayOrientation = getCorrectOrientation(); ? ?? ??? ?mCamera.setDisplayOrientation(displayOrientation); ?? ?} ? ?? ?/** ?? ? * 我們用4比3的比例設(shè)置預(yù)覽圖片 ?? ? */ ?? ?private void setPreviewSize() { ?? ??? ?Camera.Parameters params = mCamera.getParameters(); ?? ??? ?List<Size> sizes = params.getSupportedPreviewSizes(); ?? ??? ?for (Size size : sizes) { ?? ??? ??? ?Log.d("previewSize", "width:" + size.width + " height " + size.height); ?? ??? ?} ?? ??? ?for (Size size : sizes) { ?? ??? ??? ?if (size.width / 4 == size.height / 3) { ?? ??? ??? ??? ?params.setPreviewSize(size.width, size.height); ?? ??? ??? ??? ?Log.d("previewSize", "SET width:" + size.width + " height " + size.height); ?? ??? ??? ??? ?break; ?? ??? ??? ?} ?? ??? ?} ? ?? ??? ?// params一定要記得寫回Camera ?? ??? ?mCamera.setParameters(params); ? ?? ?} ? ?? ?private void setPictureSize() { ?? ??? ?Camera.Parameters params = mCamera.getParameters(); ?? ??? ?List<Size> sizes = params.getSupportedPictureSizes(); ?? ??? ?for (Size size : sizes) { ?? ??? ??? ?Log.d("picSize", "width:" + size.width + " height " + size.height); ?? ??? ?} ?? ??? ?for (Size size : sizes) { ?? ??? ??? ?if (size.width / 4 == size.height / 3) { ?? ??? ??? ??? ?params.setPictureSize(size.width, size.height); ?? ??? ??? ??? ?break; ?? ??? ??? ?} ?? ??? ?} ? ?? ?} ? ?? ?@Override ?? ?public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { ? ?? ?} ? ?? ?@Override ?? ?public void surfaceDestroyed(SurfaceHolder holder) { ?? ??? ?mCamera.release(); ?? ?} ? }
4. 程序的Mainactivity以及相應(yīng)的布局文件
package com.example.cameratutorial; ? import android.os.Bundle; import android.app.Activity; import android.app.FragmentManager; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; ? public class MainActivity extends Activity { ?? ? ?? ?@Override ?? ?protected void onCreate(Bundle savedInstanceState) { ?? ??? ?super.onCreate(savedInstanceState); ?? ??? ?setContentView(R.layout.activity_main); ?? ??? ?final CameraFragment fragment=(CameraFragment) getFragmentManager().findFragmentById(R.id.camera_fragment); ?? ??? ?Button button=(Button) findViewById(R.id.TakePic); ?? ??? ?button.setOnClickListener(new OnClickListener() { ?? ??? ??? ? ?? ??? ??? ?@Override ?? ??? ??? ?public void onClick(View v) { ?? ??? ??? ??? ?fragment.takePicture(); ?? ??? ??? ??? ? ?? ??? ??? ?} ?? ??? ?}); ?? ??? ? ?? ?} ? }
布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" ? ? xmlns:tools="http://schemas.android.com/tools" ? ? android:layout_width="match_parent" ? ? android:layout_height="match_parent"? ? ? android:orientation="vertical" ? ? > ? ? ? <fragment ? ? ? ? android:id="@+id/camera_fragment" ? ? ? ? android:name="com.example.cameratutorial.CameraFragment" ? ? ?? ? ? ? ? android:layout_width="match_parent" ? ? ? ? android:layout_height="match_parent" ? ? ? ? /> ? ? ? <Button ? ? ? ? android:id="@+id/TakePic" ? ? ? ? android:layout_width="match_parent" ? ? ? ? android:layout_height="wrap_content" ? ? ? ? android:layout_alignParentBottom="true" ? ? ? ? android:text="capture" /> ? </RelativeLayout>
這樣,我們一個可以復(fù)用的相機(jī)組件就完成了。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android如何動態(tài)改變App桌面圖標(biāo)
這篇文章主要介紹了 Android動態(tài)改變App桌面圖標(biāo)的方法,非常不錯,具有參考借鑒價值,需要的朋友參考下2017-01-01源碼解析Android Jetpack組件之ViewModel的使用
Jetpack 是一個豐富的組件庫,它的組件庫按類別分為 4 類,分別是架構(gòu)(Architecture)、界面(UI)、 行為(behavior)和基礎(chǔ)(foundation)。本文將從源碼和大家講講Jetpack組件中ViewModel的使用2023-04-04Android開發(fā)RecyclerView單獨(dú)刷新使用技巧
本篇文章主要是分享下RecyclerView中子item如何單獨(dú)刷新以及子item的某一部分內(nèi)容如何實現(xiàn)單獨(dú)刷新,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09