android开发摄像头开发,在自己的SurfaceView里预览,并且解决摄像头预览变形问题--懒人笔记02
2016-11-03 09:52
543 查看
本来想只贴设置预览尺寸的部分了,后来想想就直接写个最简单的完整的demo吧
先在mainfeast中加入权限
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
然后是anctivity_main文件中的代码
先贴这两段代码的原因就是这两个文件是不用分步骤的写,而且一看就懂,不用做什么说明,当然你也可以用自己喜欢的布局,都一样的
接下来看MainActivity中的代码,
首先要做的事情就是把摄像里的东西显示到SurfaceView中去,不管显示成什么样子,先看到它有反应再说
第一个版本
package com.camerademo;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private SurfaceView surfaceView;//预览摄像头
private SurfaceHolder surfaceHolder;
private Button button;//拍照按钮
private Camera camera;//摄像头
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
initListener();
}
//初始化View的方法,其实少的话都放到
private void initView() {
surfaceView = (SurfaceView) findViewById(R.id.main_surface_view);
button = (Button) findViewById(R.id.main_button);
}
private void initData() {
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
}
private void initListener() {
surfaceView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "surfaceView", Toast.LENGTH_SHORT).show();
}
});
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "button", Toast.LENGTH_SHORT).show();
}
});
}
private void initCamera() {
camera.startPreview();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open();
camera.setPreviewDisplay(surfaceHolder);
} catch (Exception e) {
if (null != camera) {
camera.release();
camera = null;
}
e.printStackTrace();
Toast.makeText(MainActivity.this, "启动摄像头失败,请开启摄像头权限", Toast.LENGTH_SHORT).show();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
initCamera();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (null != camera) {
camera.stopPreview();
camera.release();
camera = null;
}
}
}
这个版本我们主要做的事情
1、为我们的程序添加摄像头相关权限
2、写一个简单的布局
3、找到layout中所有的View,并为View设置测试用的监听
4、实现一个SurfaceHolder.CallBack,赋给SurfaceHolder,并且在OnSurfaceCreated里获取Camera实例,将SurfaceHolder赋给camera实例,在onSurfaceChange里面显示预览,在onSurfaceDestroy里面停止预览并且释放掉camera实例(这里可能有点绕,多过几遍代码就好了)
程序写完以后当然是迫不及待的运行一下,果不其然,界面上是有反应的,但是跟我们想象中的好像还有些不一样,界面显示出来的东西好像被旋转了,旋转屏幕观察下(现象自己观察咯)
这个处理方法有很多,可以直接将这个activity在mainfeast中设置成横屏,为了尽量多的用到API,我选择让这个activity默认竖屏
默认竖屏的代码,在mainfeast中,下边代码红色的部分让activity竖屏
继续在MainActivity中的initCamera方法中加代码
getOptimalPreviewSize方法
就到这里吧,拍照的话与自动对焦的套路差不过,用到了camera.tackpicture方法,这篇就到这里吧
先在mainfeast中加入权限
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
然后是anctivity_main文件中的代码
<pre name="code" class="html"><?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <SurfaceView android:id="@+id/main_surface_view" android:layout_width="match_parent" android:layout_height="match_parent" /> <Button android:id="@+id/main_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_margin="10dp" android:text="拍照" /> </FrameLayout>
先贴这两段代码的原因就是这两个文件是不用分步骤的写,而且一看就懂,不用做什么说明,当然你也可以用自己喜欢的布局,都一样的
接下来看MainActivity中的代码,
首先要做的事情就是把摄像里的东西显示到SurfaceView中去,不管显示成什么样子,先看到它有反应再说
第一个版本
</pre><pre>
package com.camerademo;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private SurfaceView surfaceView;//预览摄像头
private SurfaceHolder surfaceHolder;
private Button button;//拍照按钮
private Camera camera;//摄像头
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
initListener();
}
//初始化View的方法,其实少的话都放到
private void initView() {
surfaceView = (SurfaceView) findViewById(R.id.main_surface_view);
button = (Button) findViewById(R.id.main_button);
}
private void initData() {
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
}
private void initListener() {
surfaceView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "surfaceView", Toast.LENGTH_SHORT).show();
}
});
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "button", Toast.LENGTH_SHORT).show();
}
});
}
private void initCamera() {
camera.startPreview();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open();
camera.setPreviewDisplay(surfaceHolder);
} catch (Exception e) {
if (null != camera) {
camera.release();
camera = null;
}
e.printStackTrace();
Toast.makeText(MainActivity.this, "启动摄像头失败,请开启摄像头权限", Toast.LENGTH_SHORT).show();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
initCamera();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (null != camera) {
camera.stopPreview();
camera.release();
camera = null;
}
}
}
这个版本我们主要做的事情
1、为我们的程序添加摄像头相关权限
2、写一个简单的布局
3、找到layout中所有的View,并为View设置测试用的监听
4、实现一个SurfaceHolder.CallBack,赋给SurfaceHolder,并且在OnSurfaceCreated里获取Camera实例,将SurfaceHolder赋给camera实例,在onSurfaceChange里面显示预览,在onSurfaceDestroy里面停止预览并且释放掉camera实例(这里可能有点绕,多过几遍代码就好了)
程序写完以后当然是迫不及待的运行一下,果不其然,界面上是有反应的,但是跟我们想象中的好像还有些不一样,界面显示出来的东西好像被旋转了,旋转屏幕观察下(现象自己观察咯)
这个处理方法有很多,可以直接将这个activity在mainfeast中设置成横屏,为了尽量多的用到API,我选择让这个activity默认竖屏
默认竖屏的代码,在mainfeast中,下边代码红色的部分让activity竖屏
<activity android:name=".MainActivity" <span style="color:#ff0000;">android:screenOrientation="portrait"</span> > <intent-filter> <action android:name= bc37 "android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>竖屏以后屏幕中的预览还是旋转了90度呢,我们在MainActivity中的initCamera方法中加一些代码,红色的部分为新加的代码
private void initCamera() { camera.startPreview();//开始预览 camera.setDisplayOrientation(90);//将预览旋转90度 }好,加了上边几行代码后我们再运行一下吧,发现图像是转过来了哈,不过貌似不是所有的手机看上去都正常,不出意外的话应该是有些手机的预览图像是会有变形的,android开发处处是坑哈,下边我们接着处理变形问题
继续在MainActivity中的initCamera方法中加代码
private void initCamera() { Camera.Parameters parameters = camera.getParameters();//获取camera的parameter实例 List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();//获取所有支持的camera尺寸 Camera.Size optionSize = getOptimalPreviewSize(sizeList, surfaceView.getWidth(), surfaceView.getHeight());//获取一个最为适配的camera.size parameters.setPreviewSize(optionSize.width,optionSize.height);//把camera.size赋值到parameters camera.setParameters(parameters);//把parameters设置给camera camera.startPreview();//开始预览 camera.setDisplayOrientation(90);//将预览旋转90度 }咦,楼主你是不是在坑我,根本就没有getOptimalPreviewSize这个方法啊,别着急嘛,下边我给你贴出来,这个放我我抄的别人的,不是我写的啊,不过好用
getOptimalPreviewSize方法
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.1; double targetRatio = (double) w / h; if (sizes == null) return null; Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } // Cannot find the one match the aspect ratio, ignore the requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; }运行一下程序,好啦,变形问题和旋转问题解决了,下边加点击屏幕自动对焦,直接上代码吧,也没什么好说的
package com.camerademo; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.PixelFormat; import android.hardware.Camera; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.Button; import android.widget.Toast; import java.util.List; public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback { private SurfaceView surfaceView;//预览摄像头 private SurfaceHolder surfaceHolder; private Button button;//拍照按钮 private Camera camera; <span style="color:#ff0000;">private Camera.AutoFocusCallback myAutoFocusCallback1 = null;//只对焦不拍照 public static final int only_auto_focus = 110; int issuccessfocus = 0;</span> <span style="color:#ff0000;">private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); switch (msg.what) { case only_auto_focus: if (camera != null) camera.autoFocus(myAutoFocusCallback1); break; } } };</span> @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); initListener(); } private void initView() { surfaceView = (SurfaceView) findViewById(R.id.main_surface_view); button = (Button) findViewById(R.id.main_button); } private void initData() { surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this); <span style="color:#ff0000;">myAutoFocusCallback1 = new Camera.AutoFocusCallback() { public void onAutoFocus(boolean success, Camera camera) { // TODO Auto-generated method stub if (success)//success表示对焦成功 { issuccessfocus++; if (issuccessfocus <= 1) mHandler.sendEmptyMessage(only_auto_focus); Log.i("qtt", "myAutoFocusCallback1: success..." + issuccessfocus); } else { //if (issuccessfocus == 0) { mHandler.sendEmptyMessage(only_auto_focus); //} Log.i("qtt", "myAutoFocusCallback1: 失败..."); } } };</span> } private void initListener() { surfaceView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (camera != null) { if (camera != null) camera.autoFocus(myAutoFocusCallback1); } } }); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "button", Toast.LENGTH_SHORT).show(); } }); } private void initCamera() { Camera.Parameters parameters = camera.getParameters();//获取camera的parameter实例 List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();//获取所有支持的camera尺寸 Camera.Size optionSize = getOptimalPreviewSize(sizeList, surfaceView.getWidth(), surfaceView.getHeight());//获取一个最为适配的屏幕尺寸 parameters.setPreviewSize(optionSize.width, optionSize.height);//把只存设置给parameters camera.setParameters(parameters);//把parameters设置给camera上 camera.startPreview();//开始预览 camera.setDisplayOrientation(90);//将预览旋转90度 } @Override public void surfaceCreated(SurfaceHolder holder) { try { camera = Camera.open(); camera.setPreviewDisplay(surfaceHolder); } catch (Exception e) { if (null != camera) { camera.release(); camera = null; } e.printStackTrace(); Toast.makeText(MainActivity.this, "启动摄像头失败,请开启摄像头权限", Toast.LENGTH_SHORT).show(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { initCamera(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (null != camera) { camera.setPreviewCallback(null); camera.stopPreview(); camera.release(); camera = null; } } private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.1; double targetRatio = (double) w / h; if (sizes == null) return null; Camera.Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (Camera.Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } // Cannot find the one match the aspect ratio, ignore the requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Camera.Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } }
就到这里吧,拍照的话与自动对焦的套路差不过,用到了camera.tackpicture方法,这篇就到这里吧
相关文章推荐
- Android开发笔记: 解决View宽高为0的问题
- Android开发 摄像头SurfaceView预览 背景带矩形框 实现(原理:双surfaceview,顶层画矩形框,底层预览视频)
- Android SurfaceView预览变形完美解决方法
- Android开发学习笔记(11):Android问题解决对策集(更新中...)
- android开发中webview保存cookie问题的解决
- android开发中webview保存cookie问题的解决
- (转)【Android游戏开发之六】在SurfaceView中添加组件!!!!并且相互交互数据!!!!
- 【Android游戏开发之六】在SurfaceView中添加组件!!!!并且相互交互数据!!!!
- 【Android 应用开发】Android中使用ViewPager制作广告栏效果 - 解决ViewPager占满全屏页面适配问题
- 【Android游戏开发之六】在SurfaceView中添加系统控件,并且相互交互数据!
- Android 解决SurfaceView切换导致界面闪烁,短暂黑屏问题。
- 【Android游戏开发之六】在SurfaceView中添加组件!!!!并且相互交互数据!!!!
- 【Android游戏开发之六】在SurfaceView中添加组件!!!!并且相互交互数据!!!!
- 开发笔记:解决安卓GestureOverlayView手势和ListView点击事件、文本框获取焦点冲突的问题
- 【Android游戏开发之六】在SurfaceView中添加组件!!!!并且相互交互数据!!!!
- v310 摄像头调试笔记---QQ视频对方发现颜色不对, 有红块, 并且本地预览闪烁的问题
- 自己在使用Android Maps API 开发地图应用程序时遇到的问题,以及解决的办法
- android开发中webview保存cookie问题的解决
- 【Android游戏开发之六】在SurfaceView中添加组件!!!!并且相互交互数据!!!!
- 【Android游戏开发之六】在SurfaceView中添加系统控件,并且相互交互数据!