欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android自定義照相機詳解

 更新時間:2016年04月08日 15:22:34   作者:一口仨饃的博客  
幾乎每個APP都會用的相機功能,下面小編把內(nèi)容整理分享到腳本之家平臺,供大家參考

幾乎每個APP都會用的相機功能,下面小編把內(nèi)容整理分享到腳本之家平臺,供大家參考,感興趣的朋友一起學習吧!

啟動相機的兩種方式

1.直接啟動系統(tǒng)相機

<code class="hljs avrasm"> Intent intent = new Intent(); 
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); 
startActivity(intent);</code>

或者指定返回圖片的名稱mCurrentPhotoFile

<code class="hljs avrasm"> 
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(mCurrentPhotoFile));
startActivityForResult(intent, CAMERA_WITH_DATA);</code>

2.自定義啟動相機

今天以第二種為例。效果圖如下

demo

自定義相機的一般步驟

創(chuàng)建顯示相機畫面的布局,Android已經(jīng)為我們選定好SurfaceView 通過SurfaceView#getHolder()獲得鏈接Camera和SurfaceView的SurfaceHolder Camame.open()打開相機 通過SurfaceHolder鏈接Camera和SurfaceView

一般步驟的代碼演示

<code class="hljs java">public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.AutoFocusCallback {
private static final String TAG = "CameraSurfaceView";
private Context mContext;
private SurfaceHolder holder;
private Camera mCamera;
private int mScreenWidth;
private int mScreenHeight;
public CameraSurfaceView(Context context) {
this(context, null);
}
public CameraSurfaceView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CameraSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
getScreenMetrix(context);
initView();
}
private void getScreenMetrix(Context context) {
WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
WM.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
mScreenHeight = outMetrics.heightPixels;
}
private void initView() {
holder = getHolder();//獲得surfaceHolder引用
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//設置類型
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i(TAG, "surfaceCreated");
if (mCamera == null) {
mCamera = Camera.open();//開啟相機
try {
mCamera.setPreviewDisplay(holder);//攝像頭畫面顯示在Surface上
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i(TAG, "surfaceChanged");
mCamera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i(TAG, "surfaceDestroyed");
mCamera.stopPreview();//停止預覽
mCamera.release();//釋放相機資源
mCamera = null;
holder = null;
}
@Override
public void onAutoFocus(boolean success, Camera Camera) {
if (success) {
Log.i(TAG, "onAutoFocus success="+success);
}
}
}</code>

添加相機和自動聚焦限權

<code class="hljs xml"><uses-permission android:name="android.permission.CAMERA">
<uses-feature android:name="android.hardware.camera.autofocus"></uses-feature></uses-permission></code>

將CameraSurfaceView放在布局文件中,這里建議最外層為FrameLayout,后面會用到。如此,我們便有了一個沒有照相功能的相機。初次之外,仔細觀察相機顯示畫面,圖片是不是變形嚴重?那是因為我們還沒有為相機設置各種參數(shù)。在預覽前要設置攝像頭的分辨率、預覽分辨率和圖片分辨率的寬高比保持一致。這樣圖片才不會變形。這是個比較難以理解的部分,想深刻理解還需讀者自己動手去實踐。

<code class="hljs java"> private void setCameraParams(Camera camera, int width, int height) {
Log.i(TAG,"setCameraParams width="+width+" height="+height);
Camera.Parameters parameters = mCamera.getParameters();
// 獲取攝像頭支持的PictureSize列表
List<camera.size> pictureSizeList = parameters.getSupportedPictureSizes();
for (Camera.Size size : pictureSizeList) {
Log.i(TAG, "pictureSizeList size.width=" + size.width + " size.height=" + size.height);
}
/**從列表中選取合適的分辨率*/
Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width));
if (null == picSize) {
Log.i(TAG, "null == picSize");
picSize = parameters.getPictureSize();
}
Log.i(TAG, "picSize.width=" + picSize.width + " picSize.height=" + picSize.height);
// 根據(jù)選出的PictureSize重新設置SurfaceView大小
float w = picSize.width;
float h = picSize.height;
parameters.setPictureSize(picSize.width,picSize.height);
this.setLayoutParams(new FrameLayout.LayoutParams((int) (height*(h/w)), height));
// 獲取攝像頭支持的PreviewSize列表
List<camera.size> previewSizeList = parameters.getSupportedPreviewSizes();
for (Camera.Size size : previewSizeList) {
Log.i(TAG, "previewSizeList size.width=" + size.width + " size.height=" + size.height);
}
Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width);
if (null != preSize) {
Log.i(TAG, "preSize.width=" + preSize.width + " preSize.height=" + preSize.height);
parameters.setPreviewSize(preSize.width, preSize.height);
}
parameters.setJpegQuality(100); // 設置照片質(zhì)量
if (parameters.getSupportedFocusModes().contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 連續(xù)對焦模式
}
mCamera.cancelAutoFocus();//自動對焦。
mCamera.setDisplayOrientation(90);// 設置PreviewDisplay的方向,效果就是將捕獲的畫面旋轉(zhuǎn)多少度顯示
mCamera.setParameters(parameters);
}
/**
* 從列表中選取合適的分辨率
* 默認w:h = 4:3
*<p>注意:這里的w對應屏幕的height
* h對應屏幕的width</p></camera.size></camera.size></code>
*/ private Camera.Size getProperSize(List pictureSizeList, float screenRatio) { Log.i(TAG, "screenRatio=" + screenRatio); Camera.Size result = null; for (Camera.Size size : pictureSizeList) { float currentRatio = ((float) size.width) / size.height; if (currentRatio - screenRatio == 0) { result = size; break; } } if (null == result) { for (Camera.Size size : pictureSizeList) { float curRatio = ((float) size.width) / size.height; if (curRatio == 4f / 3) {// 默認w:h = 4:3 result = size; break; } } } return result; }

進去的是屏幕寬高,出來的是調(diào)整好了的參數(shù)。在surfaceChanged方法中執(zhí)行mCamera.startPreview(); 前調(diào)用setCameraParams(mCamera, mScreenWidth, mScreenHeight); 就可以了。最后要在AndroidManifest.xml里設置activity的方向android:screenOrientation="portrait"代碼里有很多注釋,其中也有我自己調(diào)試時候的Log,大家可以自己調(diào)試下,看看不同參數(shù)的效果。昨天調(diào)參數(shù)搞到一點多,都在折騰這個函數(shù)。唉,一把辛酸淚。

身為一個相機,居然不能照相?真是太丟臉了!下面給我們的相機添加上照相的功能。照相核心代碼就一句:mCamera.takePicture(null, null, jpeg);

可以看到takePicture方法有三個參數(shù),分別是ShutterCallback、PictureCallback和PictureCallback。這里我們只用了PictureCallback

<code class="hljs java"> // 拍照瞬間調(diào)用
private Camera.ShutterCallback shutter = new Camera.ShutterCallback() {
@Override
public void onShutter() {
Log.i(TAG,"shutter");
}
};
// 獲得沒有壓縮過的圖片數(shù)據(jù)
private Camera.PictureCallback raw = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera Camera) {
Log.i(TAG, "raw");
}
};
//創(chuàng)建jpeg圖片回調(diào)數(shù)據(jù)對象
private Camera.PictureCallback jpeg = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera Camera) {
BufferedOutputStream bos = null;
Bitmap bm = null;
try {
// 獲得圖片
bm = BitmapFactory.decodeByteArray(data, 0, data.length);
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Log.i(TAG, "Environment.getExternalStorageDirectory()="+Environment.getExternalStorageDirectory());
String filePath = "/sdcard/dyk"+System.currentTimeMillis()+".jpg";//照片保存路徑
File file = new File(filePath);
if (!file.exists()){
file.createNewFile();
}
bos = new BufferedOutputStream(new FileOutputStream(file));
bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);//將圖片壓縮到流中
}else{
Toast.makeText(mContext,"沒有檢測到內(nèi)存卡", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.flush();//輸出
bos.close();//關閉
bm.recycle();// 回收bitmap空間
mCamera.stopPreview();// 關閉預覽
mCamera.startPreview();// 開啟預覽
} catch (IOException e) {
e.printStackTrace();
}
}
}
};</code>

在jpeg的onPictureTaken里。我們將存儲照片信息的byte[] data解析成bitmap,然后轉(zhuǎn)換成JPG格式的圖片保存在SD卡中。注意finally中最后兩句mCamera.stopPreview();// 關閉預覽 mCamera.startPreview();// 開啟預覽 上文也提到:當調(diào)用camera.takePiture方法后,camera關閉了預覽,這時需要調(diào)用startPreview()來重新開啟預覽。如果不再次開啟預覽,則會一直停留在拍攝照片畫面。為了方便外部調(diào)用拍照。這里我暴露了一個方法供外部拍照。

<code class="hljs cs"> public void takePicture(){
//設置參數(shù),并拍照
setCameraParams(mCamera, mScreenWidth, mScreenHeight);
// 當調(diào)用camera.takePiture方法后,camera關閉了預覽,這時需要調(diào)用startPreview()來重新開啟預覽
mCamera.takePicture(null, null, jpeg);
}</code>

在布局文件中添加一個Button,點擊Button執(zhí)行takePicture()方法。不要忘了添加寫SD卡限權

<code class="hljs xml"><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission></code>

至此,一個具有照相并保存拍攝圖片功能的相機就做出來了。But,我們就此滿足了嗎?要是為了這些簡單的功能我也不會寫這篇博客。這只是個開始

真正的開始

昨天看見別的APP在照相的時候,屏幕上居然可以顯示像效果圖那樣的框框啦、輔助點啦、圖片bulabulabula~。在網(wǎng)上搜索一番實現(xiàn)方式,再加上一些自己的理解,構成了這篇博客。

上文布局文件一直沒有貼,現(xiàn)在貼出來大家先掃一眼,有些控件會在接下來展示

<code class="hljs xml"><!--?xml version="1.0" encoding="utf-8"?-->
<framelayout android:layout_height="match_parent" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android">
<com.dyk.cameratest.view.camerasurfaceview android:id="@+id/cameraSurfaceView" android:layout_height="match_parent" android:layout_width="match_parent">
<com.dyk.cameratest.view.rectoncamera android:layout_height="match_parent" android:layout_width="match_parent">
<relativelayout android:layout_height="match_parent" android:layout_width="match_parent">
</relativelayout></com.dyk.cameratest.view.rectoncamera></com.dyk.cameratest.view.camerasurfaceview></framelayout></code><button android:background="#88427ac7" android:id="@+id/takePic" android:layout_alignparentbottom="true" android:layout_centerhorizontal="true" android:layout_height="50dp" android:layout_marginbottom="20dp" android:layout_width="80dp" android:text="拍照" android:textcolor="#aaa"><code class="hljs xml">
</code></button>

布局文件的最外層是個FrameLayout,我們知道FrameLayout是自帶覆蓋效果的。由來這個思路接下來就很簡單了。編程重要的是思想,思想有了,其余的就剩具體的實現(xiàn)細節(jié)。

自定義邊邊框框

為了和CameraSurfaceView區(qū)分開,再自定義一個RectOnCamera專門用來畫邊邊框框這些東西。這樣做還一個好處是方便維護,不至于將所有東西都放在一個View中。

RectOnCamera

<code class="hljs java">package com.dyk.cameratest.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
/**
* Created by dyk on 2016/4/7.
*/
public class RectOnCamera extends View {
private static final String TAG = "CameraSurfaceView";
private int mScreenWidth;
private int mScreenHeight;
private Paint mPaint;
private RectF mRectF;
// 圓
private Point centerPoint;
private int radio;
public RectOnCamera(Context context) {
this(context, null);
}
public RectOnCamera(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RectOnCamera(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getScreenMetrix(context);
initView(context);
}
private void getScreenMetrix(Context context) {
WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
WM.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
mScreenHeight = outMetrics.heightPixels;
}
private void initView(Context context) {
mPaint = new Paint();
mPaint.setAntiAlias(true);// 抗鋸齒
mPaint.setDither(true);// 防抖動
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(5);
mPaint.setStyle(Paint.Style.STROKE);// 空心
int marginLeft = (int) (mScreenWidth*0.15);
int marginTop = (int) (mScreenHeight * 0.25);
mRectF = new RectF(marginLeft, marginTop, mScreenWidth - marginLeft, mScreenHeight - marginTop);
centerPoint = new Point(mScreenWidth/2, mScreenHeight/2);
radio = (int) (mScreenWidth*0.1);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
canvas.drawRect(mRectF, mPaint);
mPaint.setColor(Color.WHITE);
Log.i(TAG, "onDraw");
canvas.drawCircle(centerPoint.x,centerPoint.y, radio,mPaint);// 外圓
canvas.drawCircle(centerPoint.x,centerPoint.y, radio - 20,mPaint); // 內(nèi)圓
}
}
</code>

這里簡單的畫了一個類似二維碼掃描的框框,還有一個類似聚焦的內(nèi)外圓。那么問題來了,聚焦的內(nèi)外圓要隨著手指滑而改變位置,而且要有聚焦的效果??捎趾途哂芯劢构δ艿腃ameraSurfaceView不是同一個類,不僅如此聚焦內(nèi)外圓還完全覆蓋了CameraSurfaceView。要處理這種問題,需要接口回調(diào)。這就是思想下面的細節(jié)?,F(xiàn)在雖然確定接口回調(diào),但還有一個問題,CameraSurfaceView類和RectOnCamera類中都沒有對方的對象或者引用。沒錯,通過共同持有RectOnCamera和CameraSurfaceView的Activity可以實現(xiàn)此功能。下面是具體的實現(xiàn)方法。

動起來

首先,想要隨著手指的滑動而改變RectOnCamera的位置肯定是要復寫onTouchEvent()方法

<code class="hljs cs"> @Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
int x = (int) event.getX();
int y = (int) event.getY();
centerPoint = new Point(x, y);
invalidate();
return true;
}
return true;
}</code>

其次,定義回調(diào)接口

<code class="hljs java"> private IAutoFocus mIAutoFocus;
/** 聚焦的回調(diào)接口 */
public interface IAutoFocus{
void autoFocus();
}
public void setIAutoFocus(IAutoFocus mIAutoFocus) {
this.mIAutoFocus = mIAutoFocus;
}</code>

在onTouchEvent()中return前加入

<code class="hljs cs"> if (mIAutoFocus != null){
mIAutoFocus.autoFocus();
}</code>

至此我們的回調(diào)接口已經(jīng)定義好了,此時還需要CameraSurfaceView暴露一個聚焦方法,以便Activity調(diào)用

<code class="hljs cs"> public void setAutoFocus(){
mCamera.autoFocus(this);
}</code>

準備工作已經(jīng)全部完成,下面請看Activity的具體實現(xiàn):

<code class="hljs java">public class MainActivity extends Activity implements View.OnClickListener,RectOnCamera.IAutoFocus{
private CameraSurfaceView mCameraSurfaceView;
private RectOnCamera mRectOnCamera;
private Button takePicBtn;
private boolean isClicked;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
// 全屏顯示
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
mCameraSurfaceView = (CameraSurfaceView) findViewById(R.id.cameraSurfaceView);
mRectOnCamera = (RectOnCamera) findViewById(R.id.rectOnCamera);
takePicBtn= (Button) findViewById(R.id.takePic);
mRectOnCamera.setIAutoFocus(this);
takePicBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.takePic:
mCameraSurfaceView.takePicture();
break;
default:
break;
}
}
@Override
public void autoFocus() {
mCameraSurfaceView.setAutoFocus();
}
}
</code>

可以看到,MainActivity實現(xiàn)了IAutoFocus接口,并且在復寫的IAutoFocus#autoFocus()方法中,調(diào)用了CameraSurfaceView暴露出來的方法setAutoFocus()。至此,在RectOnCamera每次的滑動過程中都會改變聚焦內(nèi)外圓的位置,還會增加聚焦功能。一心二用甚至一心多用豈不是更好。

好了,Android自定義照相機教程到此結束,希望對大家有所幫助!

腳本之家推薦閱讀:

Android開發(fā)從相機或相冊獲取圖片裁剪

Android自定義照相機倒計時拍照

相關文章

  • Android自定義ViewGroup之實現(xiàn)FlowLayout流式布局

    Android自定義ViewGroup之實現(xiàn)FlowLayout流式布局

    這篇文章主要為大家詳細介紹了Android自定義ViewGroup之實現(xiàn)FlowLayout流式布局的相關代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Android實現(xiàn)傳感器功能

    Android實現(xiàn)傳感器功能

    這篇文章主要為大家詳細介紹了Android實現(xiàn)傳感器功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • Android開發(fā)實現(xiàn)廣告無限循環(huán)功能示例

    Android開發(fā)實現(xiàn)廣告無限循環(huán)功能示例

    這篇文章主要介紹了Android開發(fā)實現(xiàn)廣告無限循環(huán)功能,結合完整實例形式分析了Android廣告圖片輪播功能的具體實現(xiàn)步驟與相關功能、布局等操作技巧,需要的朋友可以參考下
    2017-11-11
  • Android集成zxing掃碼框架功能

    Android集成zxing掃碼框架功能

    這篇文章主要介紹了Android集成zxing掃碼框架功能,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-04-04
  • Android實現(xiàn)仿慕課網(wǎng)下拉加載動畫

    Android實現(xiàn)仿慕課網(wǎng)下拉加載動畫

    這篇文章是我在做動畫的項目中整理出來的,在eoe看了篇帖子,然后仿慕課網(wǎng)做了一個下拉加載動畫。此功能實現(xiàn)方法是AnimationDrawable類進行 Animation-list中item的循環(huán)遍歷圖片,類似于flash里的幀幀動畫,需要的朋友可以參考下
    2015-07-07
  • Android 安全退出應用程序的方法總結

    Android 安全退出應用程序的方法總結

    這篇文章主要介紹了Android 安全退出應用程序的方法總結的相關資料,需要的朋友可以參考下
    2017-03-03
  • Android簡單實用的可拖拽GridView組件分享

    Android簡單實用的可拖拽GridView組件分享

    在我們?nèi)粘i_發(fā)中,使用?GridView?這種網(wǎng)格視圖的場合還是不少的,本篇我們來介紹一個支持拖拽的?GridView?組件,可以輕松搞定網(wǎng)格視圖的拖拽排序,需要的可以參考一下
    2023-06-06
  • Android Studio實現(xiàn)補間動畫

    Android Studio實現(xiàn)補間動畫

    這篇文章主要為大家詳細介紹了Android Studio實現(xiàn)補間動畫,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • android LinearLayout 布局實例代碼

    android LinearLayout 布局實例代碼

    android LinearLayout 布局實例代碼,需要的朋友可以參考一下
    2013-04-04
  • Android實現(xiàn)串口通信

    Android實現(xiàn)串口通信

    這篇文章主要為大家詳細介紹了Android實現(xiàn)串口通信,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08

最新評論