您的位置:首页 > 其它

相机开发(聚焦、横竖屏拍照、照片存储、连续拍照等)

2015-12-26 14:20 411 查看
最近项目用到了相机拍照的功能,于是想着封装好一些通用性较好的相机调用,从百度和谷歌上查找出来的资料真的印证了“天下文章一大抄”的道理,而且它们实现的拍照功能大都存在缺陷,如聚焦问题、重复拍照问题、照片存储问题、横竖屏转换问题。一大堆的问题,而且程序的扩展性和可重用性实在不敢恭维,排版级其混乱。

最后无奈,打开API文档camera相机类,从最基础的学起,然后自己进行改进,从这里也告诉我们一个道理,API文档才是学习起点,因为它会告诉你整个实现的原理和原因,能够对整个框架有一个整体的了解,看完API文档看其他的就有事半功倍的效果,吐槽完毕,下面来正式实现。

一.实现流程

这幅图是从API文档(最好是看英文版的)整理出来的,从这副图上面我们可以看出,主要是有6步,其中难点是创建相机预览类。



二.权限声明

这个不讲了,直接加入声明权限代码,不明白的可以网上查查看

view
sourceprint?

1.
<uses-permission
android:name=
"android.permission.CAMERA"
/>


2.
<uses-feature
android:name=
"android.hardware.camera"
/>


3.
<uses-permission
android:name=
"android.permission.WRITE_EXTERNAL_STORAGE"
/>


4.
<uses-permission
android:name=
"android.permission.ACCESS_FINE_LOCATION"
/>


5.
<uses-feature
android:name=
"android.hardware.camera.autofocus"
/>


6.
<uses-permission
android:name=
"android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
/>


三 检查相机和获取相机实例

新建CameraCheck类,主要有2个方法,代码如下

view
sourceprint?

01.
public
class
CameraCheck
{


02.


03.
public
static
boolean
CheckCamera(Context
mContext) {


04.
if
(mContext.getPackageManager().hasSystemFeature(


05.
PackageManager.FEATURE_CAMERA))
{


06.
return
true
;


07.
}
else
{


08.
Toast.makeText(mContext,
"相机不存在!"
,
Toast.LENGTH_SHORT).show();


09.
return
false
;


10.
}


11.
}


12.


13.
/**
A safe way to get an instance of the Camera object. */


14.
public
static
Camera
getCameraInstance(Context mContext) {


15.
Camera
c =
null
;


16.
if
(CheckCamera(mContext))
{


17.
try
{


18.
c
= Camera.open();


19.
}
catch
(Exception
e) {


20.
c=
null
;


21.
}


22.
}


23.
return
c;
//
returns null if camera is unavailable


24.
}


25.
}


第一个方法用来检查相机是否存在,这个方法是来自API文档,使用方法

mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)

hasSystemFeature(String name)方法返回设备是否支持name功能的真假值;

通过方法getCameraInstance返回相机的实例,通过调用该方法,mContext能够获得该相机资源,只有获得了该相机资源才能够对相机进行操作。

四.创建相机预览类(重点)

我们在拍照之前需要对取景进行预览,这里我们需要使用SurfaceView控件,关于SurfaceView控件我们先简单的了解一下(别急,磨刀不误砍柴工)。

SurfaceView是View的子类,所以它拥有View的一切方法和属性,这一点我们从命名上面就可以看出来,比如绘制方法、大小等属性;它比View多了一个Surface的东西,Surface是专门用来绘制的类,而SurfaceView可以控制surface绘制的大小、位置等等;

可能有人会问,那为什么要专门这样一个类来绘制呢?不是有OnDraw()方法吗?相比于OnDraw()方法它有很多优势,如下总结:

(1)在频繁更新UI线程的情况下,可以使用封装好的surface来频繁的更新,因为surface可以使用后台线程对UI界面进行绘制,而OnDraw()等绘制方法很难做到(除非你频繁的调用handler来更新主界面,这得多麻烦啊!);

(2)SurfaceView可以用来绘制2D或者3D图形,绘制一些动态曲线等,它显示的速度会比一般的快很多,因为他是通过硬件加速的方式来绘制的。

(3)它可以用来接受硬件的数据来绘制图像。

所以,通过以上几点我们可以知道,用它来接受相机的预览是理所当然的。那么它的使用方法是怎么样的呢?下创建一个surfaceView的继承类一般需要实现如下几个方法:

(1)surfaceCreated(SurfaceHolderholder):在该类创建的时候调用,这里一般需要实现一些初始化的工作,SurfaceHodler用来设定surface的大小位置等等;

(2)surfaceChanged(SurfaceHolderholder,int format,int width,int height)在surface大小发生改变时候调用,这里实现图形的绘制;

(3)surfaceDestroyed(SurfaceHolderholder)在surface销毁时候调用,这里一般对资源进行释放;

(4)实现SurfaceHodler.CallBack回调方法,在surfaceView创建完成后自动调用类本身;

在实现之前我们先来看我们的需求,我们要实现的功能:预览、拍照、自动聚焦、触摸聚焦、连续拍照、照片存储。下面我们来创建一个SurfaceView类CameraPreview,它继承了SurfaceView,并实现接口SurfaceHolder.Callback

因此我们需要在surfaceCreated方法中创建一个camer实例,这个实例可以在这个类中进行调用,实现代码如下:

view
sourceprint?

01.
/**


02.
*
创建的时候自动调用该方法


03.
*/


04.
@Override


05.
public
void
surfaceCreated(SurfaceHolder
holder) {


06.
if
(mCamera
==
null
)
{


07.
mCamera
= CameraCheck.getCameraInstance(mContext);


08.
}


09.
try
{


10.
if
(mCamera!=
null
){


11.
mCamera.setPreviewDisplay(holder);


12.
}


13.
}
catch
(IOException
e) {


14.
if
(
null
!=
mCamera) {


15.
mCamera.release();


16.
mCamera
=
null
;


17.
isPreview=
false
;


18.
}


19.
e.printStackTrace();


20.
}


21.


22.
}


这句代码 mCamera.setPreviewDisplay(holder)的意思是创建一个预览的hodler;我们在surfaceChanged中进行预览窗口的绘制调用的是startPreview()方法来开始绘制,代码如下:

view
sourceprint?

01.
/**


02.
*
当surface的大小发生改变的时候自动调用的


03.
*/


04.
@Override


05.
public
void
surfaceChanged(SurfaceHolder
holder,
int
format,
int
width,


06.
int
height)
{


07.
if
(mHolder.getSurface()
==
null
)
{


08.
return
;


09.
}


10.
try
{


11.
setCameraParms();


12.
mCamera.setPreviewDisplay(holder);


13.
mCamera.startPreview();


14.
reAutoFocus();


15.
}
catch
(Exception
e) {


16.
Log.d(TAG,
"Error
starting camera preview: "
+
e.getMessage());


17.
}


18.
}


其中有2个比较关键的方法没有实现, setCameraParms()和reAutoFocus(),setCameraParms();函数用来设置预览图片的参数,其中关键的为预览图片的大小和拍照保存的尺寸大小,很多的网上实现的程序拍出来的照片很小模糊的原因就是没有设置好照片的尺寸,这个照片的尺寸是根据手机本身能够支持的尺寸有很大关系。reAutoFocus()是自动聚焦的方法,需要动态获取reAutoFocus()函数是自动聚焦的实现;

我们首先来看一下setCameraParms()方法的实现:

view
sourceprint?

01.
private
void
setCameraParms(){


02.
Camera.Parameters
myParam = mCamera.getParameters();


03.
List<Camera.Size>
mSupportedsizeList =myParam.getSupportedPictureSizes();


04.
if
(mSupportedsizeList.size()
>
1
)
{


05.
Iterator<Camera.Size>
itos = mSupportedsizeList.iterator();


06.
while
(itos.hasNext()){


07.
Camera.Size
curSize = itos.next();


08.
int
curSupporSize=curSize.width
* curSize.height;


09.
int
fixPictrueSize=
setFixPictureWidth  * setFixPictureHeight;


10.
if
(
curSupporSize>fixPictrueSize && curSupporSize <= maxPictureSize) {


11.
setFixPictureWidth
= curSize.width;


12.
setFixPictureHeight
= curSize.height;


13.
}


14.
}


15.
}


16.
myParam.setJpegQuality(
100
);


17.
mCamera.setParameters(myParam);


18.
if
(myParam.getMaxNumDetectedFaces()
>
0
){


19.
mCamera.startFaceDetection();


20.
}


21.
}


22.


通过myParam.getSupportedPictureSizes();获取到手机支持的所有尺寸的枚举,并设置最大的固定尺寸这里设置最大为maxPictureSize = 5000000

reAutoFocus()的实现为:

view
sourceprint?

01.
<span
style=
"white-space:pre"
>
</span>
/**


02.
*
Call the camera to Auto Focus


03.
*/


04.
public
void
reAutoFocus()
{


05.
if
(isSupportAutoFocus)
{


06.
mCamera.autoFocus(
new
AutoFocusCallback()
{


07.
@Override


08.
public
void
onAutoFocus(
boolean
success,
Camera camera) {


09.
}


10.
});


11.
}


12.
}


使用回调函数autoFocus来实现自动聚焦

五.拍照

拍照方法有一个难点是横竖屏拍照的转换和存储,网上大都实现的是默认的横屏拍照,一旦换成竖屏后预览就会出现问题,而且存储的照片也有问题,因此为了解决这个问题,我们需要时刻监听方向传感器的变化,得到当前的旋转角度,我么可以通过调用OrientationEventListener系统监听类来得到当前角度,自定义MyOrientationDetector代码如下:

view
sourceprint?

01.
/**


02.
*
方向变化监听器,监听传感器方向的改变


03.
*
@author zw.yan


04.
*


05.
*/


06.
public
class
MyOrientationDetector
extends
OrientationEventListener{


07.
int
Orientation;


08.
public
MyOrientationDetector(Context
context ) {


09.
super
(context
);


10.
}


11.
@Override


12.
public
void
onOrientationChanged(
int
orientation)
{


13.
Log.i(
"MyOrientationDetector
"
,
"onOrientationChanged:"
+orientation);


14.
this
.Orientation=orientation;


15.
Log.d(
"MyOrientationDetector"
,
"当前的传感器方向为"
+orientation);


16.
}


17.


18.
public
int
getOrientation(){


19.
return
Orientation;


20.
}


21.
}


在预览类中我们定义拍照方法TakePhone(),代码如下:

view
sourceprint?

01.
/**


02.
*
调整照相的方向,设置拍照相片的方向


03.
*/


04.
private
void
takePhoto()
{


05.
cameraOrientation
=
new
MyOrientationDetector(mContext);


06.
if
(mCamera
!=
null
)
{


07.
int
orientation
= cameraOrientation.getOrientation();


08.
Camera.Parameters
cameraParameter = mCamera.getParameters();


09.
cameraParameter.setRotation(
90
);


10.
cameraParameter.set(
"rotation"
,
90
);


11.
if
((orientation
>=
45
)
&& (orientation <
135
))
{


12.
cameraParameter.setRotation(
180
);


13.
cameraParameter.set(
"rotation"
,
180
);


14.
}


15.
if
((orientation
>=
135
)
&& (orientation <
225
))
{


16.
cameraParameter.setRotation(
270
);


17.
cameraParameter.set(
"rotation"
,
270
);


18.
}


19.
if
((orientation
>=
225
)
&& (orientation <
315
))
{


20.
cameraParameter.setRotation(
0
);


21.
cameraParameter.set(
"rotation"
,
0
);


22.
}


23.
mCamera.setParameters(cameraParameter);


24.
mCamera.takePicture(shutterCallback,
pictureCallback,mPicture);


25.
}


26.
}


在角度范围内自动调整旋转图片的角度,具体旋转的方式如代码,从而使存储的图片能够正常显示。

六.图片保存

在拍照时需要对图片进行保存,但是不能影响图片的下一次拍照,因此我们需要采用异步线程的方式,可以使用AsyncTask类,在拍照完成时进行调用如下代码:

view
sourceprint?

01.
public
class
SavePictureTask
extends
AsyncTask<
byte
[],
String,String> {


02.
@SuppressLint
(
"SimpleDateFormat"
)


03.
@Override


04.
protected
String
doInBackground(
byte
[]...
params) {


05.
File
pictureFile = FileUtil.getOutputMediaFile(MEDIA_TYPE_IMAGE,


06.
mContext);


07.
if
(pictureFile
==
null
)
{


08.
Toast.makeText(mContext,
"请插入存储卡!"
,
Toast.LENGTH_SHORT).show();


09.
return
null
;


10.
}


11.
try
{


12.
FileOutputStream
fos =
new
FileOutputStream(pictureFile);


13.
fos.write(params[
0
]);


14.
fos.flush();


15.
fos.close();


16.
}
catch
(FileNotFoundException
e) {


17.
Log.d(TAG,
"File
not found: "
+ e.getMessage());


18.
}
catch
(IOException
e) {


19.
Log.d(TAG,
"Error
accessing file: "
+
e.getMessage());


20.
}


21.


22.
return
null
;


23.
}


24.
}


这是基本对文件异步线程的IO操作有什么不明白的可以去看对应的API文档。

下面我将整个类贴出来:

view
sourceprint?

001.
/**


002.
*
sufaceView 的预览类,其中SurfaceHolder.CallBack用来监听Surface的变化,


003.
*
当Surface发生改变的时候自动调用该回调方法


004.
*
通过调用方SurfaceHolder.addCallBack来绑定该方法


005.
*
@author zw.yan


006.
*


007.
*/


008.
public
class
CameraPreview
extends
SurfaceView
implements


009.
SurfaceHolder.Callback
{


010.


011.
private
String
TAG =
"CameraPreview"
;


012.
/**


013.
*
Surface的控制器,用来控制预览等操作


014.
*/


015.
private
SurfaceHolder
mHolder;


016.
/**


017.
*
相机实例


018.
*/


019.
private
Camera
mCamera =
null
;


020.
/**


021.
*
图片处理


022.
*/


023.
public
static
final
int
MEDIA_TYPE_IMAGE
=
1
;


024.
/**


025.
*
预览状态标志


026.
*/


027.
private
boolean
isPreview
=
false
;


028.
/**


029.
*
设置一个固定的最大尺寸


030.
*/


031.
private
int
maxPictureSize
=
5000000
;


032.
/**


033.
*
是否支持自动聚焦,默认不支持


034.
*/


035.
private
Boolean
isSupportAutoFocus =
false
;


036.
/**


037.
*
获取当前的context


038.
*/


039.
private
Context
mContext;


040.
/**


041.
*
当前传感器的方向,当方向发生改变的时候能够自动从传感器管理类接受通知的辅助类


042.
*/


043.
MyOrientationDetector
cameraOrientation;


044.
/**


045.
*
设置最适合当前手机的图片宽度


046.
*/


047.
int
setFixPictureWidth
=
0
;


048.
/**


049.
*
设置当前最适合的图片高度


050.
*/


051.
int
setFixPictureHeight
=
0
;


052.


053.
@SuppressWarnings
(
"deprecation"
)


054.
public
CameraPreview(Context
context) {


055.
super
(context);


056.
this
.mContext
= context;


057.
isSupportAutoFocus
= context.getPackageManager().hasSystemFeature(


058.
PackageManager.FEATURE_CAMERA_AUTOFOCUS);


059.
mHolder
= getHolder();


060.
//兼容android
3.0以下的API,如果超过3.0则不需要设置该方法


061.
if
(Build.VERSION.SDK_INT
< Build.VERSION_CODES.HONEYCOMB){


062.
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);


063.
}


064.
mHolder.addCallback(
this
);
//绑定当前的回调方法


065.
}


066.


067.
/**


068.
*
创建的时候自动调用该方法


069.
*/


070.
@Override


071.
public
void
surfaceCreated(SurfaceHolder
holder) {


072.
if
(mCamera
==
null
)
{


073.
mCamera
= CameraCheck.getCameraInstance(mContext);


074.
}


075.
try
{


076.
if
(mCamera!=
null
){


077.
mCamera.setPreviewDisplay(holder);


078.
}


079.
}
catch
(IOException
e) {


080.
if
(
null
!=
mCamera) {


081.
mCamera.release();


082.
mCamera
=
null
;


083.
isPreview=
false
;


084.
}


085.
e.printStackTrace();


086.
}


087.


088.
}


089.
/**


090.
*
当surface的大小发生改变的时候自动调用的


091.
*/


092.
@Override


093.
public
void
surfaceChanged(SurfaceHolder
holder,
int
format,
int
width,


094.
int
height)
{


095.
if
(mHolder.getSurface()
==
null
)
{


096.
return
;


097.
}


098.
try
{


099.
setCameraParms();


100.
mCamera.setPreviewDisplay(holder);


101.
mCamera.startPreview();


102.
reAutoFocus();


103.
}
catch
(Exception
e) {


104.
Log.d(TAG,
"Error
starting camera preview: "
+
e.getMessage());


105.
}


106.
}


107.


108.
private
void
setCameraParms(){


109.
Camera.Parameters
myParam = mCamera.getParameters();


110.
List<Camera.Size>
mSupportedsizeList =myParam.getSupportedPictureSizes();


111.
if
(mSupportedsizeList.size()
>
1
)
{


112.
Iterator<Camera.Size>
itos = mSupportedsizeList.iterator();


113.
while
(itos.hasNext()){


114.
Camera.Size
curSize = itos.next();


115.
int
curSupporSize=curSize.width
* curSize.height;


116.
int
fixPictrueSize=
setFixPictureWidth  * setFixPictureHeight;


117.
if
(
curSupporSize>fixPictrueSize && curSupporSize <= maxPictureSize) {


118.
setFixPictureWidth
= curSize.width;


119.
setFixPictureHeight
= curSize.height;


120.
}


121.
}


122.
}


123.
myParam.setJpegQuality(
100
);


124.
mCamera.setParameters(myParam);


125.
if
(myParam.getMaxNumDetectedFaces()
>
0
){


126.
mCamera.startFaceDetection();


127.
}


128.
}


129.


130.
@Override


131.
public
void
surfaceDestroyed(SurfaceHolder
holder) {


132.
mCamera.stopPreview();


133.
mCamera.release();


134.
mCamera
=
null
;


135.
}


136.


137.
/**


138.
*
Call the camera to Auto Focus


139.
*/


140.
public
void
reAutoFocus()
{


141.
if
(isSupportAutoFocus)
{


142.
mCamera.autoFocus(
new
AutoFocusCallback()
{


143.
@Override


144.
public
void
onAutoFocus(
boolean
success,
Camera camera) {


145.
}


146.
});


147.
}


148.
}


149.
/**


150.
*
自动聚焦,然后拍照


151.
*/


152.
public
void
takePicture()
{


153.
if
(mCamera
!=
null
)
{


154.
mCamera.autoFocus(autoFocusCallback);


155.
}


156.
}


157.


158.
private
AutoFocusCallback
autoFocusCallback =
new
AutoFocusCallback()
{


159.


160.
public
void
onAutoFocus(
boolean
success,
Camera camera) {


161.
//
TODO Auto-generated method stub


162.


163.
if
(success)
{


164.
Log.i(TAG,
"autoFocusCallback:
success..."
);


165.
takePhoto();


166.
}
else
{


167.
Log.i(TAG,
"autoFocusCallback:
fail..."
);


168.
if
(isSupportAutoFocus)
{


169.
takePhoto();


170.
}


171.
}


172.
}


173.
};


174.
/**


175.
*
调整照相的方向,设置拍照相片的方向


176.
*/


177.
private
void
takePhoto()
{


178.
cameraOrientation
=
new
MyOrientationDetector(mContext);


179.
if
(mCamera
!=
null
)
{


180.
int
orientation
= cameraOrientation.getOrientation();


181.
Camera.Parameters
cameraParameter = mCamera.getParameters();


182.
cameraParameter.setRotation(
90
);


183.
cameraParameter.set(
"rotation"
,
90
);


184.
if
((orientation
>=
45
)
&& (orientation <
135
))
{


185.
cameraParameter.setRotation(
180
);


186.
cameraParameter.set(
"rotation"
,
180
);


187.
}


188.
if
((orientation
>=
135
)
&& (orientation <
225
))
{


189.
cameraParameter.setRotation(
270
);


190.
cameraParameter.set(
"rotation"
,
270
);


191.
}


192.
if
((orientation
>=
225
)
&& (orientation <
315
))
{


193.
cameraParameter.setRotation(
0
);


194.
cameraParameter.set(
"rotation"
,
0
);


195.
}


196.
mCamera.setParameters(cameraParameter);


197.
mCamera.takePicture(shutterCallback,
pictureCallback,mPicture);


198.
}


199.
}


200.


201.
private
ShutterCallback
shutterCallback =
new
ShutterCallback()
{


202.
@Override


203.
public
void
onShutter()
{


204.
//
TODO Auto-generated method stub


205.
}


206.
};


207.


208.
private
PictureCallback
pictureCallback =
new
PictureCallback()
{


209.


210.
@Override


211.
public
void
onPictureTaken(
byte
[]
arg0,Camera arg1) {


212.
//
TODO Auto-generated method stub


213.


214.
}


215.
};


216.
private
PictureCallback
mPicture =
new
PictureCallback()
{


217.


218.
@Override


219.
public
void
onPictureTaken(
byte
[]
data,Camera camera) {


220.
new
SavePictureTask().execute(data);


221.
mCamera.startPreview();
//重新开始预览


222.
}


223.
};


224.


225.
public
class
SavePictureTask
extends
AsyncTask<
byte
[],
String,String> {


226.
@SuppressLint
(
"SimpleDateFormat"
)


227.
@Override


228.
protected
String
doInBackground(
byte
[]...
params) {


229.
File
pictureFile = FileUtil.getOutputMediaFile(MEDIA_TYPE_IMAGE,


230.
mContext);


231.
if
(pictureFile
==
null
)
{


232.
Toast.makeText(mContext,
"请插入存储卡!"
,
Toast.LENGTH_SHORT).show();


233.
return
null
;


234.
}


235.
try
{


236.
FileOutputStream
fos =
new
FileOutputStream(pictureFile);


237.
fos.write(params[
0
]);


238.
fos.flush();


239.
fos.close();


240.
}
catch
(FileNotFoundException
e) {


241.
Log.d(TAG,
"File
not found: "
+ e.getMessage());


242.
}
catch
(IOException
e) {


243.
Log.d(TAG,
"Error
accessing file: "
+
e.getMessage());


244.
}


245.


246.
return
null
;


247.
}


248.
}


249.
@Override


250.
public
boolean
onTouchEvent(MotionEvent
event) {


251.
reAutoFocus();


252.
return
false
;


253.
}


254.


255.


256.
}


文件的布局和调用如下:

view
sourceprint?

01.
public
class
CameraActivity
extends
Activity{


02.


03.
private
CameraPreview
mPreview;


04.
public
static
final
int
MEDIA_TYPE_IMAGE
=
1
;


05.
public
static
final
int
MEDIA_TYPE_VIDEO
=
2
;


06.
private
String
TAG=
"CameraActivity"
;


07.
private
FrameLayout
preview;


08.
private
ImageButton
captureButton;


09.
@Override


10.
protected
void
onCreate(Bundle
savedInstanceState) {


11.
//
TODO Auto-generated method stub


12.
super
.onCreate(savedInstanceState);


13.
requestWindowFeature(Window.FEATURE_NO_TITLE);


14.
this
.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);


15.
setContentView(R.layout.camera_preview);


16.
mPreview
=
new
CameraPreview(
this
);


17.
preview
= (FrameLayout) findViewById(R.id.camera_preview);


18.
preview.addView(mPreview);


19.
captureButton
= (ImageButton) findViewById(R.id.button_capture);


20.
captureButton.setOnClickListener(
new
View.OnClickListener()
{


21.
@Override


22.
public
void
onClick(View
v) {


23.
mPreview.takePicture();


24.
}


25.


26.
});


27.
}


28.


29.
@Override


30.
protected
void
onDestroy()
{


31.
//
TODO Auto-generated method stub


32.
super
.onDestroy();


33.
}


34.


35.


36.


37.
}


view
sourceprint?

01.
<?xml
version=
"1.0"
encoding=
"utf-8"
?>


02.
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"


03.
android:orientation=
"horizontal"


04.
android:layout_width=
"match_parent"


05.
android:layout_height=
"match_parent"


06.
android:background=
"#000"
>


07.
<FrameLayout


08.
android:id=
"@+id/camera_preview"


09.
android:layout_width=
"match_parent"


10.
android:layout_height=
"match_parent"


11.
android:layout_weight=
"1"


12.
/>


13.


14.
<ImageButton


15.
android:id=
"@+id/button_capture"


16.
android:layout_width=
"wrap_content"


17.
android:layout_height=
"wrap_content"


18.
android:layout_gravity=
"center"


19.
android:src=
"@drawable/camera_icon"


20.
android:background=
"#00000000"


21.
/>


22.
</LinearLayout>


最终效果如下:



转自:http://www.it165.net/pro/html/201408/20629.html

注意,里面有一些类没有具体说明,具体可以查看后面的代码下载链接,有什么不明白的可以发邮件,邮件地址为dali_yan@yeah.net
转载请注明出处,代码下载地址:下载地址(别走!请留下你的评论)
http://www.it165.net/uploadfile/files/2014/0825/CameraLibary.rar


延伸阅读:

1、Android 多媒体和相机详解一

2、Android调用系统相机拍照 并且模仿实现水印相机简单功能

3、AndroidDevelopers:控制照相机

4、Android调用系统相机拍照保存以及调用系统相册的方法

5、Android调用相机实现拍照并裁剪图片 调用手机中的相册图片并裁剪图片

6、Android自定义照相机注意事项

7、android照片涂画功能实现过程及原理

8、Android网络由手机与手机WIFI互传照片谈AndroidTCPSocket开发要点
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: