Android Camera開發 給攝像頭預覽介面加個ZoomBar(附完整程式碼下載)
廢話不說了,就是加個seekbar,拖動的話能夠調節焦距,讓畫面變大或縮小。下面是核心程式:
一,camera的佈局檔案
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/BestWish" tools:context=".StandardCamera" /> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" > <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" > <SurfaceView android:id="@+id/previewSV" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </FrameLayout> <LinearLayout android:id="@+id/zoomLayout" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_centerInParent="true" android:layout_centerHorizontal="true" android:orientation="horizontal" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="-" android:textColor="#ffffff" android:textSize="30dip"/> <SeekBar android:id="@+id/seekbar_zoom" android:layout_width="300dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:progressDrawable="@drawable/seekbar_style" android:thumb="@drawable/ic_launcher" android:thumbOffset="0dp" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="+" android:textColor="#ffffff" android:textSize="30dip" /> </LinearLayout> </RelativeLayout> <ImageButton android:id="@+id/photoImgBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:background="@drawable/photo_img_btn" /></LinearLayout>
其中裡面巢狀的LinearLayout就是那個ZoomBar,最外面我用了相對佈局,發現相對佈局用起來還是很好用的。為了方便以後擴充套件,Camera的SurfaceView用的幀佈局。注意SeekBar的幾個引數,其中的progressDrawable是指那個橫條的形狀,可以直接用個圖片,也可以寫個xml檔案。這裡用的是xml,當然用圖片很簡單。seekbar_style.xml檔案如下:
<?xml version="1.0" encoding="UTF-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@android:id/background"> <shape> <corners android:radius="5dip" /> <gradient android:startColor="#ff9d9e9d" android:centerColor="#ff5a5d5a" android:centerY="0.75" android:endColor="#ff747674" android:angle="270" /> </shape> </item> </layer-list>
下面的android:thumb是滑動的那個手柄,本來我是寫了一個xml檔案,名字為thumb.xml如下:
<?xml version="1.0" encoding="UTF-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 按下狀態 --> <item android:state_focused="true" android:state_pressed="true"><shape android:shape="oval"> <gradient android:angle="0" android:centerColor="#FF00FF00" android:endColor="#000000" android:gradientRadius="8" android:startColor="#FFFF0000" android:type="radial" /> <size android:height="20dip" android:width="20dip"></size> </shape></item></selector>
無奈啥也顯示不出來,索性直接找了個粗糙的圖片,見諒哈!
二,整個程式的主程式碼:
package yan.guoqi.camera;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.util.List;import yan.guoqi.rectphoto.R;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.ColorMatrixColorFilter;import android.graphics.Matrix;import android.graphics.PixelFormat;import android.hardware.Camera;import android.hardware.Camera.AutoFocusCallback;import android.hardware.Camera.Parameters;import android.hardware.Camera.PictureCallback;import android.hardware.Camera.PreviewCallback;import android.hardware.Camera.ShutterCallback;import android.os.Bundle;import android.util.Log;import android.view.Display;import android.view.MotionEvent;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnTouchListener;import android.view.ViewGroup.LayoutParams;import android.view.Window;import android.view.WindowManager;import android.widget.ImageButton;import android.widget.SeekBar;import android.widget.SeekBar.OnSeekBarChangeListener;public class StandardCamera extends Activity implements SurfaceHolder.Callback, PreviewCallback{ private static final String tag="StandardCamera"; private boolean isPreview = false; private SurfaceView mPreviewSV = null; //棰勮SurfaceView private SurfaceHolder mySurfaceHolder = null; private ImageButton mPhotoImgBtn = null; private Camera myCamera = null; private Bitmap mBitmap = null; private AutoFocusCallback myAutoFocusCallback = null; boolean flag = true; private SeekBar mZoomBar = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN; Window myWindow = this.getWindow(); myWindow.setFlags(flag, flag); setContentView(R.layout.activity_rect_photo); initView(); mySurfaceHolder = mPreviewSV.getHolder(); mySurfaceHolder.setFormat(PixelFormat.TRANSLUCENT); mySurfaceHolder.addCallback(this); mySurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); myAutoFocusCallback = new AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { // TODO Auto-generated method stub if(success) { Log.i(tag, "myAutoFocusCallback: success..."); } else { Log.i(tag, "myAutoFocusCallback: 澶辮觸浜�?."); } } }; //新增ZoomBar mZoomBar = (SeekBar)findViewById(R.id.seekbar_zoom); mZoomBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { public void onStopTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } public void onStartTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // TODO Auto-generated method stub Parameters p = myCamera.getParameters(); p.setZoom(progress); myCamera.setParameters(p); } }); } public void initView(){ mPreviewSV = (SurfaceView)findViewById(R.id.previewSV); WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); LayoutParams lpSV = mPreviewSV.getLayoutParams(); lpSV.width = display.getWidth(); lpSV.height = (int) ((float)display.getHeight()*0.75); mPreviewSV.setLayoutParams(lpSV); mPhotoImgBtn = (ImageButton)findViewById(R.id.photoImgBtn); LayoutParams lp = mPhotoImgBtn.getLayoutParams(); lp.width = 240; lp.height = 240; mPhotoImgBtn.setLayoutParams(lp); mPhotoImgBtn.setOnClickListener(new PhotoOnClickListener()); mPhotoImgBtn.setOnTouchListener(new MyOnTouchListener()); } public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) { // TODO Auto-generated method stub Log.i(tag, "SurfaceHolder.Callback:surfaceChanged!"); initCamera(); } public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub myCamera = Camera.open(); try { myCamera.setPreviewDisplay(mySurfaceHolder); Log.i(tag, "SurfaceHolder.Callback: surfaceCreated!"); } catch (IOException e) { // TODO Auto-generated catch block if(null != myCamera){ myCamera.release(); myCamera = null; } e.printStackTrace(); } } public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub Log.i(tag, "SurfaceHolder.Callback錛歋urface Destroyed"); if(null != myCamera) { myCamera.setPreviewCallback(null); myCamera.stopPreview(); isPreview = false; myCamera.release(); myCamera = null; } } public void initCamera(){ if(isPreview){ myCamera.stopPreview(); } if(null != myCamera){ Camera.Parameters myParam = myCamera.getParameters(); myParam.setPictureFormat(PixelFormat.JPEG);//璁劇疆鎷嶇収鍚庡瓨鍌ㄧ殑鍥劇墖鏍煎紡 //List<Size> pictureSizes = myParam.getSupportedPictureSizes(); //List<Size> previewSizes = myParam.getSupportedPreviewSizes(); // for(int i=0; i<pictureSizes.size(); i++){ // Size size = pictureSizes.get(i); // Log.i(tag, "initCamera:pictureSizes: width = "+size.width+"height = "+size.height); // } // for(int i=0; i<previewSizes.size(); i++){ // Size size = previewSizes.get(i); // Log.i(tag, "initCamera:鎽勫儚澶存敮鎸佺殑previewSizes: width = "+size.width+"height = "+size.height); // // } myParam.setPictureSize(1280, 960); // myParam.setPreviewSize(960, 720); // //myParam.set("rotation", 90); myCamera.setDisplayOrientation(90); List<String> focuseMode = (myParam.getSupportedFocusModes()); for(int i=0; i<focuseMode.size(); i++){ Log.i(tag, focuseMode.get(i)); if(focuseMode.get(i).contains("continuous")){ myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); } else{ myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); } } //設定mZoomBar的最大值 mZoomBar.setMax(myParam.getMaxZoom()); myCamera.setParameters(myParam); myCamera.startPreview(); myCamera.autoFocus(myAutoFocusCallback); isPreview = true; } } ShutterCallback myShutterCallback = new ShutterCallback() { public void onShutter() { // TODO Auto-generated method stub Log.i(tag, "myShutterCallback:onShutter..."); } }; PictureCallback myRawCallback = new PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { // TODO Auto-generated method stub Log.i(tag, "myRawCallback:onPictureTaken..."); } }; PictureCallback myJpegCallback = new PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { // TODO Auto-generated method stub Log.i(tag, "myJpegCallback:onPictureTaken..."); if(null != data){ mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);//data鏄瓧鑺傛暟鎹紝灝嗗叾瑙f瀽鎴愪綅鍥� myCamera.stopPreview(); isPreview = false; } Matrix matrix = new Matrix(); matrix.postRotate((float)90.0); Bitmap rotaBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), matrix, false); if(null != rotaBitmap) { saveJpeg(rotaBitmap); } myCamera.startPreview(); isPreview = true; } }; public class PhotoOnClickListener implements OnClickListener{ public void onClick(View v) { // TODO Auto-generated method stub if(isPreview && myCamera!=null){ myCamera.takePicture(myShutterCallback, null, myJpegCallback); } } } public void saveJpeg(Bitmap bm){ String savePath = "/mnt/sdcard/rectPhoto/"; File folder = new File(savePath); if(!folder.exists()) { folder.mkdir(); } long dataTake = System.currentTimeMillis(); String jpegName = savePath + dataTake +".jpg"; Log.i(tag, "saveJpeg:jpegName--" + jpegName); //File jpegFile = new File(jpegName); try { FileOutputStream fout = new FileOutputStream(jpegName); BufferedOutputStream bos = new BufferedOutputStream(fout); // Bitmap newBM = bm.createScaledBitmap(bm, 600, 800, false); bm.compress(Bitmap.CompressFormat.JPEG, 100, bos); bos.flush(); bos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public class MyOnTouchListener implements OnTouchListener{ public final float[] BT_SELECTED=new float[] { 2, 0, 0, 0, 2, 0, 2, 0, 0, 2, 0, 0, 2, 0, 2, 0, 0, 0, 1, 0 }; public final float[] BT_NOT_SELECTED=new float[] { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 }; public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub if(event.getAction() == MotionEvent.ACTION_DOWN){ v.getBackground().setColorFilter(new ColorMatrixColorFilter(BT_SELECTED)); v.setBackgroundDrawable(v.getBackground()); } else if(event.getAction() == MotionEvent.ACTION_UP){ v.getBackground().setColorFilter(new ColorMatrixColorFilter(BT_NOT_SELECTED)); v.setBackgroundDrawable(v.getBackground()); } return false; } } @Override public void onBackPressed() { // TODO Auto-generated method stub super.onBackPressed(); StandardCamera.this.finish(); } class UpdateThread implements Runnable{ public void run() { // TODO Auto-generated method stub while(flag){ if(myCamera!=null && isPreview) myCamera.autoFocus(myAutoFocusCallback); //鑷姩鑱氱劍 myCamera.setOneShotPreviewCallback(StandardCamera.this); //onPreviewFrame閲屼細鎺ュ彈鍒版暟鎹�? myCamera.stopPreview(); //鍋滄棰勮 flag = false; try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public void onPreviewFrame(byte[] data, Camera camera) { // TODO Auto-generated method stub }}
需要注意的有以下幾點:
1,為了讓程式適用不同的手機,onCreate函式裡用如下程式碼初始化SurfaceView的大小,避免以前寫死的方法:
public void initView(){
mPreviewSV = (SurfaceView)findViewById(R.id.previewSV);
WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
LayoutParams lpSV = mPreviewSV.getLayoutParams();
lpSV.width = display.getWidth();
lpSV.height = (int) ((float)display.getHeight()*0.75);
mPreviewSV.setLayoutParams(lpSV);
mPhotoImgBtn = (ImageButton)findViewById(R.id.photoImgBtn);
LayoutParams lp = mPhotoImgBtn.getLayoutParams();
lp.width = 240;
lp.height = 240;
mPhotoImgBtn.setLayoutParams(lp);
mPhotoImgBtn.setOnClickListener(new PhotoOnClickListener());
mPhotoImgBtn.setOnTouchListener(new MyOnTouchListener());
}
2,關於ZoomBar的程式碼片段很簡短,如下:
mPhotoImgBtn = (ImageButton)findViewById(R.id.photoImgBtn);
LayoutParams lp = mPhotoImgBtn.getLayoutParams();
lp.width = 240;
lp.height = 240;
mPhotoImgBtn.setLayoutParams(lp);
mPhotoImgBtn.setOnClickListener(new PhotoOnClickListener());
mPhotoImgBtn.setOnTouchListener(new MyOnTouchListener());
}
//新增ZoomBar
mZoomBar = (SeekBar)findViewById(R.id.seekbar_zoom);
mZoomBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
public void onStopTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
Parameters p = myCamera.getParameters();
p.setZoom(progress);
myCamera.setParameters(p);
}
});
3,在initCamera函式裡,查詢camera支援的聚焦模式,如果帶連續視訊聚焦則使用連續視訊聚焦,否則使用自動聚焦:
mPhotoImgBtn = (ImageButton)findViewById(R.id.photoImgBtn);
LayoutParams lp = mPhotoImgBtn.getLayoutParams();
lp.width = 240;
lp.height = 240;
mPhotoImgBtn.setLayoutParams(lp);
mPhotoImgBtn.setOnClickListener(new PhotoOnClickListener());
mPhotoImgBtn.setOnTouchListener(new MyOnTouchListener());
}
List<String> focuseMode = (myParam.getSupportedFocusModes());
for(int i=0; i<focuseMode.size(); i++){
Log.i(tag, focuseMode.get(i));
if(focuseMode.get(i).contains("continuous")){
myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}
else{
myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
}
4,同樣在initCamera函式裡,設定ZoomBar的最大值:
//設定mZoomBar的最大值
mZoomBar.setMax(myParam.getMaxZoom());
後續將寫專文分析Camera4.0的原始碼,並且模仿到自己的程式碼中!