編輯:Android資訊
對Activity強制橫屏,保證預覽方向正確。使用OrientationEventListener監聽設備方向,判斷豎拍時,旋轉照片後再保存,保證豎拍時預覽圖片和保存後的圖片方向一致。
運行效果:
代碼:
TestCameraActivity.java
package com.example.testcamera;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.OrientationEventListener;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class TestCameraActivity extends Activity implements OnClickListener,
SurfaceHolder.Callback {
private static final String TAG = "TestCameraActivity";
public static final String KEY_FILENAME = "filename";
private Button mTakePhoto;
private SurfaceView mSurfaceView;
private Camera mCamera;
private String mFileName;
private OrientationEventListener mOrEventListener; // 設備方向監聽器
private Boolean mCurrentOrientation; // 當前設備方向 橫屏false,豎屏true
/* 圖像數據處理還未完成時的回調函數 */
private Camera.ShutterCallback mShutter = new Camera.ShutterCallback() {
@Override
public void onShutter() {
// 一般顯示進度條
}
};
/* 圖像數據處理完成後的回調函數 */
private Camera.PictureCallback mJpeg = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// 保存圖片
mFileName = UUID.randomUUID().toString() + ".jpg";
Log.i(TAG, mFileName);
FileOutputStream out = null;
try {
out = openFileOutput(mFileName, Context.MODE_PRIVATE);
byte[] newData = null;
if (mCurrentOrientation) {
// 豎屏時,旋轉圖片再保存
Bitmap oldBitmap = BitmapFactory.decodeByteArray(data, 0,
data.length);
Matrix matrix = new Matrix();
matrix.setRotate(90);
Bitmap newBitmap = Bitmap.createBitmap(oldBitmap, 0, 0,
oldBitmap.getWidth(), oldBitmap.getHeight(),
matrix, true);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
newBitmap.compress(Bitmap.CompressFormat.JPEG, 85, baos);
newData = baos.toByteArray();
out.write(newData);
} else {
out.write(data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null)
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Intent i = new Intent(TestCameraActivity.this, ShowPicture.class);
i.putExtra(KEY_FILENAME, mFileName);
startActivity(i);
finish();
}
};
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_camera);
mTakePhoto = (Button) findViewById(R.id.take_photo);
mTakePhoto.setOnClickListener(this); // 拍照按鈕監聽器
startOrientationChangeListener(); // 啟動設備方向監聽器
mSurfaceView = (SurfaceView) findViewById(R.id.my_surfaceView);
SurfaceHolder holder = mSurfaceView.getHolder();
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(this); // 回調接口
}
private final void startOrientationChangeListener() {
mOrEventListener = new OrientationEventListener(this) {
@Override
public void onOrientationChanged(int rotation) {
if (((rotation >= 0) && (rotation <= 45)) || (rotation >= 315)
|| ((rotation >= 135) && (rotation <= 225))) {// portrait
mCurrentOrientation = true;
Log.i(TAG, "豎屏");
} else if (((rotation > 45) && (rotation < 135))
|| ((rotation > 225) && (rotation < 315))) {// landscape
mCurrentOrientation = false;
Log.i(TAG, "橫屏");
}
}
};
mOrEventListener.enable();
}
@Override
public void onClick(View v) {
// 點擊拍照
switch (v.getId()) {
case R.id.take_photo:
mCamera.takePicture(mShutter, null, mJpeg);
break;
default:
break;
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// SurfaceView尺寸發生改變時(首次在屏幕上顯示同樣會調用此方法),初始化mCamera參數,啟動Camera預覽
Parameters parameters = mCamera.getParameters();// 獲取mCamera的參數對象
Size largestSize = getBestSupportedSize(parameters
.getSupportedPreviewSizes());
parameters.setPreviewSize(largestSize.width, largestSize.height);// 設置預覽圖片尺寸
largestSize = getBestSupportedSize(parameters
.getSupportedPictureSizes());// 設置捕捉圖片尺寸
parameters.setPictureSize(largestSize.width, largestSize.height);
mCamera.setParameters(parameters);
try {
mCamera.startPreview();
} catch (Exception e) {
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// SurfaceView創建時,建立Camera和SurfaceView的聯系
if (mCamera != null) {
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// SurfaceView銷毀時,取消Camera預覽
if (mCamera != null) {
mCamera.stopPreview();
}
}
@SuppressLint("NewApi")
@Override
public void onResume() {
super.onResume();
// 開啟相機
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
mCamera = Camera.open(0);
// i=0 表示後置相機
} else
mCamera = Camera.open();
}
@Override
public void onPause() {
super.onPause();
// 釋放相機
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
private Size getBestSupportedSize(List<Size> sizes) {
// 取能適用的最大的SIZE
Size largestSize = sizes.get(0);
int largestArea = sizes.get(0).height * sizes.get(0).width;
for (Size s : sizes) {
int area = s.width * s.height;
if (area > largestArea) {
largestArea = area;
largestSize = s;
}
}
return largestSize;
}
}
ShowPicture.java
package com.example.testcamera;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.widget.ImageView;
public class ShowPicture extends Activity {
private static final String TAG = "ShowPicture";
private ImageView mPicture;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_picture);
mPicture = (ImageView) findViewById(R.id.picture);
String fileName = getIntent().getStringExtra(
TestCameraActivity.KEY_FILENAME);
// 圖片路徑
Log.i(TAG, fileName);
String path = getFileStreamPath(fileName).getAbsolutePath();
Display display = getWindowManager().getDefaultDisplay(); // 顯示屏尺寸
float destWidth = display.getWidth();
float destHeight = display.getHeight();
// 讀取本地圖片尺寸
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);// 設置為true,options依然對應此圖片,但解碼器不會為此圖片分配內存
float srcWidth = options.outWidth;
float srcHeight = options.outHeight;
int inSampleSize = 1;
if (srcHeight > destHeight || srcWidth > destWidth) { // 當圖片長寬大於屏幕長寬時
if (srcWidth > srcHeight) {
inSampleSize = Math.round(srcHeight / destHeight);
} else {
inSampleSize = Math.round(srcWidth / destWidth);
}
}
options = new BitmapFactory.Options();
options.inSampleSize = inSampleSize;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
BitmapDrawable bDrawable = new BitmapDrawable(getResources(), bitmap);
mPicture.setImageDrawable(bDrawable);
}
@Override
public void onDestroy() {
if (!(mPicture.getDrawable() instanceof BitmapDrawable))
return;
// 釋放bitmap占用的空間
BitmapDrawable b = (BitmapDrawable) mPicture.getDrawable();
b.getBitmap().recycle();
mPicture.setImageDrawable(null);
}
}
源碼下載
Android 對話框 Dialog 深度剖析
對話框 對話框是提示用戶作出決定或輸入額外信息的小窗口。 對話框不會填充屏幕,通常用於需要用戶采取行動才能繼續執行的模式事件。 對話框設計 Dialog 類是對
Android UI控件系列:Spinner(下拉列表)
當在某個網站注冊賬號的時候,網站會讓我們提供性別,生日,城市等信息,為了方便,就提供了一個下拉列表供我們選擇,在Android也同樣有這樣的功能,這就是Spinn
關於Android開發的40條優化建議
以下是開始Android編程的好方法: 1、找一些與你想開發的功能類似的代碼; 2、調整它,嘗試讓它變成你想要的; 3、回顧開發中遇到的問題 4、使用StackO
Android 中如何選擇 compileSdkVersion, minSdkVersion 和 targetSdkVersion
作者:Ian Lake,Google Android 推廣工程師;翻譯:韓國恺。 當你發布一個應用之後,(取決於具體的發布時間)可能沒過幾個月 Android 系