編輯: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); } }
源碼下載
對話框 對話框是提示用戶作出決定或輸入額外信息的小窗口。 對話框不會填充屏幕,通常用於需要用戶采取行動才能繼續執行的模式事件。 對話框設計 Dialog 類是對
當在某個網站注冊賬號的時候,網站會讓我們提供性別,生日,城市等信息,為了方便,就提供了一個下拉列表供我們選擇,在Android也同樣有這樣的功能,這就是Spinn
以下是開始Android編程的好方法: 1、找一些與你想開發的功能類似的代碼; 2、調整它,嘗試讓它變成你想要的; 3、回顧開發中遇到的問題 4、使用StackO
作者:Ian Lake,Google Android 推廣工程師;翻譯:韓國恺。 當你發布一個應用之後,(取決於具體的發布時間)可能沒過幾個月 Android 系