編輯:關於Android編程
最近,在修改Android4.4的原生相機Camera2,很習慣的去尋找SurfaceView,結果任憑我使用grep還是ack,都無法搜索到SurfaceView,最後還是通過代碼CameraActivity-->CameraModule-->PhotoUI-->R.layout.photo_module找到,原來是使用了TextureView。不是很了解此控件,百度之,在官方API文檔中找到此控件:
官方文檔大概的意思是:
TextureView可以用來顯示內容流。這樣一個內容流例如可以視頻或者OpenGL的場景。內容流可以來自本應用程序以及其他進程。
Textureview必須在硬件加速開啟的窗口中。
與SurfaceView相比,TextureView不會創建一個單獨的窗口,這使得它可以像一般的View一樣執行一些變換操作,比如移動、動畫等等,例如,你可以通過調用myView.setAlpha(0.5f)將TextureView設置成半透明。
使用TextureView很簡單:你需要使用的就是SurfaceTexture,SurfaceTexture可以用於呈現內容。
下面是我寫一個小例子來演示如何渲染相機預覽到TextureView,在官方文檔例子的基礎上稍微改動了一下:
main.xml:
<framelayout android:id="@+id/camera_preview" android:layout_height="fill_parent" android:layout_weight="1" android:layout_width="fill_parent"></framelayout>
CameraPreview.java:
import java.io.IOException; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.view.TextureView; @SuppressLint(NewApi) public class CameraPreview extends TextureView implements TextureView.SurfaceTextureListener { private Camera mCamera; private TextureView mTextureView; public CameraPreview(Context context , Camera camera) { super(context); mCamera = camera; // TODO Auto-generated constructor stub } public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { // mCamera = Camera.open(); try { mCamera.setPreviewTexture(surface); mCamera.startPreview(); } catch (IOException ioe) { // Something bad happened } } public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { // Ignored, Camera does all the work for us } public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { mCamera.stopPreview(); mCamera.release(); return true; } public void onSurfaceTextureUpdated(SurfaceTexture surface) { // Invoked every time there's a new Camera preview frame } }
import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.FrameLayout; import android.widget.Toast; import com.example.mycamera.R.id; @SuppressLint(NewApi) public class CameraTest extends Activity { public static final int MEDIA_TYPE_IMAGE = 1; public static final int MEDIA_TYPE_VIDEO = 2; private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100; private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200; private Camera mCamera; private CameraPreview mPreview; private static final String TAG = ERROR; private PictureCallback mPicture = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE); if (pictureFile == null) { Log.d(TAG, Error creating media file, check storage permissions: + e.getMessage()); return; } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { Log.d(TAG, File not found: + e.getMessage()); } catch (IOException e) { Log.d(TAG, Error accessing file: + e.getMessage()); } } }; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.main); // 創建Camera實例 mCamera = getCameraInstance(); // 創建Preview view並將其設為activity中的內容 mPreview = new CameraPreview(this, mCamera); mPreview.setSurfaceTextureListener(mPreview); //設置渾濁 mPreview.setAlpha(0.5f); FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview); // preview.setAlpha(0.0f); preview.addView(mPreview); // 在Capture按鈕中加入listener Button captureButton = (Button) findViewById(id.button_capture); captureButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 從攝像頭獲取圖片 mCamera.takePicture(null, null, mPicture); } }); } /** 安全獲取Camera對象實例的方法 */ public static Camera getCameraInstance() { Camera c = null; try { c = Camera.open(); // 試圖獲取Camera實例 } catch (Exception e) { // 攝像頭不可用(正被占用或不存在) } return c; // 不可用則返回null } /** 為保存圖片或視頻創建File */ private static File getOutputMediaFile(int type) { // 安全起見,在使用前應該 // 用Environment.getExternalStorageState()檢查SD卡是否已裝入 File mediaStorageDir = new File( Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), MyCameraApp); // 如果期望圖片在應用程序卸載後還存在、且能被其它應用程序共享, // 則此保存位置最合適 // 如果不存在的話,則創建存儲目錄 if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { Log.d(MyCameraApp, failed to create directory); return null; } Log.d(MyCameraApp, failed to create directory); } // 創建媒體文件名 String timeStamp = new SimpleDateFormat(yyyyMMdd_HHmmss) .format(new Date()); File mediaFile; if (type == MEDIA_TYPE_IMAGE) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + IMG_ + timeStamp + .jpg); } else if (type == MEDIA_TYPE_VIDEO) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + VID_ + timeStamp + .mp4); } else { return null; } return mediaFile; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) { if (resultCode == RESULT_OK) { // 捕獲的圖像保存到Intent指定的fileUri Toast.makeText(this, Image saved to: + data.getData(), Toast.LENGTH_LONG).show(); } else if (resultCode == RESULT_CANCELED) { // 用戶取消了圖像捕獲 } else { // 圖像捕獲失敗,提示用戶 } } if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) { if (resultCode == RESULT_OK) { // 捕獲的視頻保存到Intent指定的fileUri Toast.makeText(this, Video saved to: + data.getData(), Toast.LENGTH_LONG).show(); } else if (resultCode == RESULT_CANCELED) { // 用戶取消了視頻捕獲 } else { // 視頻捕獲失敗,提示用戶 } } } @Override protected void onPause() { super.onPause(); releaseCamera(); // 在暫停事件中立即釋放攝像頭 } private void releaseCamera() { if (mCamera != null) { mCamera.release(); // 為其它應用釋放攝像頭 mCamera = null; } } }
前言:監於5.0之後Google用的是Camera2相關API取代之前的Camera,過時的Camera雖然精典,但不再進行介紹,可自行查閱相關資料。今天本文是在正式深入
很多時候Android常用的控件不能滿足我們的需求,那麼我們就需要自定義一個控件了。今天做了一個自定義控件的實例,來分享下。首先定義一個layout實現按鈕內部布局:&n
Drawable天天用,可你是否對Drawable家族有一個完整的認知?今天我們就來系統的學習一下Drawable的使用。1.概述用過Drawable的筒子都知道Draw
RecyclerView出現已經有一段時間了,相信大家肯定不陌生了,大家可以通過導入support-v7對其進行使用。 據官方的介紹,該控件用於在有限的窗口中展示大量數據