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

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

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

一.实现流程

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

二.权限声明

这个不讲了,直接增加声明权限代码,不明确的能够网上查查看

        <uses-permission android:name="android.permission.CAMERA" />
	<uses-feature android:name="android.hardware.camera" />
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
	<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
	<uses-feature android:name="android.hardware.camera.autofocus" />
	<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

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

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

public class CameraCheck {

	public static boolean CheckCamera(Context mContext) {
		if (mContext.getPackageManager().hasSystemFeature(
				PackageManager.FEATURE_CAMERA)) {
			return true;
		} else {
			Toast.makeText(mContext, "相机不存在!", Toast.LENGTH_SHORT).show();
			return false;
		}
	}

	/** A safe way to get an instance of the Camera object. */
	public static Camera getCameraInstance(Context mContext) {
		Camera c = null;
		if (CheckCamera(mContext)) {
			try {
				c = Camera.open();
			} catch (Exception e) {
				c=null;
			}
		}
		return c; // returns null if camera is unavailable
	}
}

第一个方法用来检查相机是否存在,这种方法是来自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实例,这个实例能够在这个类中进行调用,实现代码例如以下:

/**
	 * 创建的时候自己主动调用该方法
	 */
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		if (mCamera == null) {
			mCamera = CameraCheck.getCameraInstance(mContext);
		}
		try {
			if(mCamera!=null){
				mCamera.setPreviewDisplay(holder);
			}
		} catch (IOException e) {
			if (null != mCamera) {
				mCamera.release();
				mCamera = null;
				isPreview=false;
			}
			e.printStackTrace();
		}

	}

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

/**
	 * 当surface的大小发生改变的时候自己主动调用的
	 */
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		if (mHolder.getSurface() == null) {
			return;
		}
		try {
			setCameraParms();
			mCamera.setPreviewDisplay(holder);
			mCamera.startPreview();
			reAutoFocus();
		} catch (Exception e) {
			Log.d(TAG, "Error starting camera preview: " + e.getMessage());
		}
	}

当中有2个比較关键的方法没有实现, setCameraParms()和reAutoFocus(),setCameraParms();函数用来设置预览图片的參数,当中关键的为预览图片的大小和拍照保存的尺寸大小,非常多的网上实现的程序拍出来的照片非常小模糊的原因就是没有设置好照片的尺寸,这个照片的尺寸是依据手机本身可以支持的尺寸有非常大关系。reAutoFocus()是自己主动聚焦的方法,须要动态获取reAutoFocus()函数是自己主动聚焦的实现;

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

private void setCameraParms(){
		Camera.Parameters myParam = mCamera.getParameters();
		List<Camera.Size> mSupportedsizeList =myParam.getSupportedPictureSizes();
		if(mSupportedsizeList.size() > 1) {
			Iterator<Camera.Size> itos = mSupportedsizeList.iterator();
			while (itos.hasNext()){
				Camera.Size curSize = itos.next();
				int curSupporSize=curSize.width * curSize.height;
				int fixPictrueSize= setFixPictureWidth  * setFixPictureHeight;
				if( curSupporSize>fixPictrueSize && curSupporSize <= maxPictureSize) {
					setFixPictureWidth  = curSize.width;
					setFixPictureHeight = curSize.height;
				}
			}
		}<pre name="code" class="java">	if (setFixPictureWidth != 0 && setFixPictureHeight != 0) {
			myParam.setPictureSize(setFixPictureWidth , setFixPictureHeight);
		}

myParam.setJpegQuality(100);mCamera.setParameters(myParam);if (myParam.getMaxNumDetectedFaces() > 0){ mCamera.startFaceDetection();}}


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

reAutoFocus()的实现为:

<span style="white-space:pre">	</span>/**
	 * Call the camera to Auto Focus
	 */
	public void reAutoFocus() {
		if (isSupportAutoFocus) {
			mCamera.autoFocus(new AutoFocusCallback() {
				@Override
				public void onAutoFocus(boolean success, Camera camera) {
				}
			});
		}
	}

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

五.拍照

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

/**
 * 方向变化监听器,监听传感器方向的改变
 * @author zw.yan
 *
 */
public class MyOrientationDetector extends OrientationEventListener{
	int Orientation;
    public MyOrientationDetector(Context context ) {
        super(context );
    }
    @Override
    public void onOrientationChanged(int orientation) {
        Log.i("MyOrientationDetector ","onOrientationChanged:"+orientation);
        this.Orientation=orientation;
        Log.d("MyOrientationDetector","当前的传感器方向为"+orientation);
    }

    public int getOrientation(){
    	return Orientation;
    }
}

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

/**
	 * 调整照相的方向,设置拍照相片的方向
	 */
	private void takePhoto() {
		cameraOrientation = new MyOrientationDetector(mContext);
		if (mCamera != null) {
			int orientation = cameraOrientation.getOrientation();
			Camera.Parameters cameraParameter = mCamera.getParameters();
			cameraParameter.setRotation(90);
			cameraParameter.set("rotation", 90);
			if ((orientation >= 45) && (orientation < 135)) {
				cameraParameter.setRotation(180);
				cameraParameter.set("rotation", 180);
			}
			if ((orientation >= 135) && (orientation < 225)) {
				cameraParameter.setRotation(270);
				cameraParameter.set("rotation", 270);
			}
			if ((orientation >= 225) && (orientation < 315)) {
				cameraParameter.setRotation(0);
				cameraParameter.set("rotation", 0);
			}
			mCamera.setParameters(cameraParameter);
			mCamera.takePicture(shutterCallback, pictureCallback, mPicture);
		}
	}

在角度范围内自己主动调整旋转图片的角度,详细旋转的方式如代码,从而使存储的图片可以正常显示。

六.图片保存

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

public class SavePictureTask extends AsyncTask<byte[], String, String> {
		@SuppressLint("SimpleDateFormat")
		@Override
		protected String doInBackground(byte[]... params) {
			File pictureFile = FileUtil.getOutputMediaFile(MEDIA_TYPE_IMAGE,
					mContext);
			if (pictureFile == null) {
				Toast.makeText(mContext, "请插入存储卡!", Toast.LENGTH_SHORT).show();
				return null;
			}
			try {
				FileOutputStream fos = new FileOutputStream(pictureFile);
				fos.write(params[0]);
				fos.flush();
				fos.close();
			} catch (FileNotFoundException e) {
				Log.d(TAG, "File not found: " + e.getMessage());
			} catch (IOException e) {
				Log.d(TAG, "Error accessing file: " + e.getMessage());
			}

			return null;
		}
	}

这是基本对文件异步线程的IO操作有什么不明确的能够去看相应的API文档。

以下我将整个类贴出来:

/**
 * sufaceView 的预览类,当中SurfaceHolder.CallBack用来监听Surface的变化,
 * 当Surface发生改变的时候自己主动调用该回调方法
 * 通过调用方SurfaceHolder.addCallBack来绑定该方法
 * @author zw.yan
 *
 */
public class CameraPreview extends SurfaceView implements
		SurfaceHolder.Callback {

	private String TAG = "CameraPreview";
	/**
	 * Surface的控制器,用来控制预览等操作
	 */
	private SurfaceHolder mHolder;
	/**
	 * 相机实例
	 */
	private Camera mCamera = null;
	/**
	 * 图片处理
	 */
	public static final int MEDIA_TYPE_IMAGE = 1;
	/**
	 * 预览状态标志
	 */
	private boolean isPreview = false;
	/**
	 * 设置一个固定的最大尺寸
	 */
	private int maxPictureSize = 5000000;
	/**
	 * 是否支持自己主动聚焦,默认不支持
	 */
	private Boolean isSupportAutoFocus = false;
	/**
	 * 获取当前的context
	 */
	private Context mContext;
	/**
	 * 当前传感器的方向,当方向发生改变的时候可以自己主动从传感器管理类接受通知的辅助类
	 */
	MyOrientationDetector cameraOrientation;
	/**
	 * 设置最适合当前手机的图片宽度
	 */
	int setFixPictureWidth = 0;
	/**
	 * 设置当前最适合的图片高度
	 */
	int setFixPictureHeight = 0;

	@SuppressWarnings("deprecation")
	public CameraPreview(Context context) {
		super(context);
		this.mContext = context;
		isSupportAutoFocus = context.getPackageManager().hasSystemFeature(
				PackageManager.FEATURE_CAMERA_AUTOFOCUS);
		mHolder = getHolder();
		//兼容android 3.0下面的API,假设超过3.0则不须要设置该方法
		if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB){
			mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		}
		mHolder.addCallback(this);//绑定当前的回调方法
	}

	/**
	 * 创建的时候自己主动调用该方法
	 */
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		if (mCamera == null) {
			mCamera = CameraCheck.getCameraInstance(mContext);
		}
		try {
			if(mCamera!=null){
				mCamera.setPreviewDisplay(holder);
			}
		} catch (IOException e) {
			if (null != mCamera) {
				mCamera.release();
				mCamera = null;
				isPreview=false;
			}
			e.printStackTrace();
		}

	}
	/**
	 * 当surface的大小发生改变的时候自己主动调用的
	 */
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		if (mHolder.getSurface() == null) {
			return;
		}
		try {
			setCameraParms();
			mCamera.setPreviewDisplay(holder);
			mCamera.startPreview();
			reAutoFocus();
		} catch (Exception e) {
			Log.d(TAG, "Error starting camera preview: " + e.getMessage());
		}
	}

	private void setCameraParms(){
		Camera.Parameters myParam = mCamera.getParameters();
		List<Camera.Size> mSupportedsizeList =myParam.getSupportedPictureSizes();
		if(mSupportedsizeList.size() > 1) {
			Iterator<Camera.Size> itos = mSupportedsizeList.iterator();
			while (itos.hasNext()){
				Camera.Size curSize = itos.next();
				int curSupporSize=curSize.width * curSize.height;
				int fixPictrueSize= setFixPictureWidth  * setFixPictureHeight;
				if( curSupporSize>fixPictrueSize && curSupporSize <= maxPictureSize) {
					setFixPictureWidth  = curSize.width;
					setFixPictureHeight = curSize.height;
				}
			}
		}<pre name="code" class="java">	if (setFixPictureWidth != 0 && setFixPictureHeight != 0) {
			myParam.setPictureSize(setFixPictureWidth , setFixPictureHeight);
		}<pre name="code" class="java"><span style="white-space:pre">		</span>myParam.setJpegQuality(100);
		mCamera.setParameters(myParam);
		if (myParam.getMaxNumDetectedFaces() > 0){
		       mCamera.startFaceDetection();
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		mCamera.stopPreview();
		mCamera.release();
		mCamera = null;
	}

	/**
	 * Call the camera to Auto Focus
	 */
	public void reAutoFocus() {
		if (isSupportAutoFocus) {
			mCamera.autoFocus(new AutoFocusCallback() {
				@Override
				public void onAutoFocus(boolean success, Camera camera) {
				}
			});
		}
	}
	/**
	 * 自己主动聚焦,然后拍照
	 */
	public void takePicture() {
		if (mCamera != null) {
			mCamera.autoFocus(autoFocusCallback);
		}
	}

	private AutoFocusCallback autoFocusCallback = new AutoFocusCallback() {

		public void onAutoFocus(boolean success, Camera camera) {
			// TODO Auto-generated method stub

			if (success) {
				Log.i(TAG, "autoFocusCallback: success...");
				takePhoto();
			} else {
				Log.i(TAG, "autoFocusCallback: fail...");
				if (isSupportAutoFocus) {
					takePhoto();
				}
			}
		}
	};
	/**
	 * 调整照相的方向,设置拍照相片的方向
	 */
	private void takePhoto() {
		cameraOrientation = new MyOrientationDetector(mContext);
		if (mCamera != null) {
			int orientation = cameraOrientation.getOrientation();
			Camera.Parameters cameraParameter = mCamera.getParameters();
			cameraParameter.setRotation(90);
			cameraParameter.set("rotation", 90);
			if ((orientation >= 45) && (orientation < 135)) {
				cameraParameter.setRotation(180);
				cameraParameter.set("rotation", 180);
			}
			if ((orientation >= 135) && (orientation < 225)) {
				cameraParameter.setRotation(270);
				cameraParameter.set("rotation", 270);
			}
			if ((orientation >= 225) && (orientation < 315)) {
				cameraParameter.setRotation(0);
				cameraParameter.set("rotation", 0);
			}
			mCamera.setParameters(cameraParameter);
			mCamera.takePicture(shutterCallback, pictureCallback, mPicture);
		}
	}

	private ShutterCallback shutterCallback = new ShutterCallback() {
		@Override
		public void onShutter() {
			// TODO Auto-generated method stub
		}
	};

	private PictureCallback pictureCallback = new PictureCallback() {

		@Override
		public void onPictureTaken(byte[] arg0, Camera arg1) {
			// TODO Auto-generated method stub

		}
	};
	private PictureCallback mPicture = new PictureCallback() {

		@Override
		public void onPictureTaken(byte[] data, Camera camera) {
			new SavePictureTask().execute(data);
			mCamera.startPreview();//又一次開始预览
		}
	};

	public class SavePictureTask extends AsyncTask<byte[], String, String> {
		@SuppressLint("SimpleDateFormat")
		@Override
		protected String doInBackground(byte[]... params) {
			File pictureFile = FileUtil.getOutputMediaFile(MEDIA_TYPE_IMAGE,
					mContext);
			if (pictureFile == null) {
				Toast.makeText(mContext, "请插入存储卡!", Toast.LENGTH_SHORT).show();
				return null;
			}
			try {
				FileOutputStream fos = new FileOutputStream(pictureFile);
				fos.write(params[0]);
				fos.flush();
				fos.close();
			} catch (FileNotFoundException e) {
				Log.d(TAG, "File not found: " + e.getMessage());
			} catch (IOException e) {
				Log.d(TAG, "Error accessing file: " + e.getMessage());
			}

			return null;
		}
	}
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		reAutoFocus();
		return false;
	}

}


文件的布局和调用例如以下:

public class CameraActivity extends Activity{

    private CameraPreview mPreview;
	public static final int MEDIA_TYPE_IMAGE = 1;
	public static final int MEDIA_TYPE_VIDEO = 2;
	private String TAG="CameraActivity";
	private FrameLayout preview;
	private ImageButton captureButton;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(R.layout.camera_preview);
        mPreview = new CameraPreview(this);
        preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(mPreview);
        captureButton = (ImageButton) findViewById(R.id.button_capture);
		captureButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				mPreview.takePicture();
			}

		});
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
	}

}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000">
  <FrameLayout
    android:id="@+id/camera_preview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1"
    />

  <ImageButton
    android:id="@+id/button_capture"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:src="@drawable/camera_icon"
    android:background="#00000000"
    />
</LinearLayout>

终于效果例如以下:

注意,里面有一些类没有详细说明,详细能够查看后面的代码下载链接,有什么不明确的能够发邮件,邮件地址为[email protected]

转载请注明出处,http://blog.csdn.net/itbailei/article/details/38822791代码下载地址:下载地址(别走!请留下你的评论) sorry,刚才看了一下在下载的资源的setCameraParms()方法中忘记设置尺寸大小了,自己下载完后加上,

if (setFixPictureWidth != 0 && setFixPictureHeight != 0) {
			myParam.setPictureSize(setFixPictureWidth , setFixPictureHeight);
		}

对照上面的代码就可以!

时间: 2024-10-29 08:37:34

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

移动视频开发中横竖屏转换遇到的BUG(Android)

剧情铺垫:首先申明,我是一个Android初学者.最开始我们想做一个视频通话软件,很快就找到了AnyChat.但当时用的是官网的demo,只支持横屏.我们想做成横竖屏都支持的效果. 遇到的问题 1.自己的视频会被对方的视频挡住 2.自己的视频横竖比例不对 3.自己的视频将音量条挡住 4.自己的视频不能居中 问题1的处理 尝试1:由于较熟悉web方面的知识,最先想到用z-index控制View的叠放,结果悲剧的没找到z-index类似物 尝试2:Android中,xml排在后的会覆盖排在前的,但这

(一〇八)iPad开发之横竖屏适配

在iPad开发中,横竖屏的视图常常是不同的,例如侧边栏Dock,在横屏时用于屏幕较宽,可以展示足够多的内容,每个按钮都可以展示出标题:而竖屏时Dock应该比较窄,只显示图标不现实按钮标题. iPad比较重要的知识是不同类型设备的宽高在以点为单位的图形坐标系下固定为768x1024,因此常常利用此值来判断横竖屏. 768.1024.横竖屏判断很常用,可以定义一个公共的常量文件来放这些内容. [常量和宏的定义] ①在.m文件中,定义变量,加上const,注意指针(例如NSString*)使用的是常量

cocos2d-x游戏开发屏幕横竖屏切换

android解决方案: 1.在游戏的主activity中编写一个静态方法(继承Cocos2dxActivity) public static void changedActivityOrientation(int orientation){ switch(orientation) { case 1://横屏 instance.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); break; case 2://竖

iOS iPad开发之横竖屏适配

1. 做横竖屏适配的时,需要判断当前状态是横屏还是竖屏,有两种方法: 第1种:[UIScreen mainScreen].bounds.size.width == 768 优点:把这个抽成宏之后,随时可以判断横竖屏, #define Lanscape ([UIScreen mainScreen].bounds.size.width == 768) 缺点:只在iOS8可行,也就是说在iOS8中横屏的width=1024,竖屏的width=768; 而在iOS7上,横竖屏的width=768 第2种

ios开发强制横竖屏转换

第一种:手动的设置界面元素的旋转,包括状态栏.导航栏和视图.以下代码为从竖屏设置为横屏,坐标系是以竖屏的为基准,所以会出现负数的坐标值. //设置状态栏旋转 [[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeRightanimated:YES]; CGFloat duration = [UIApplication sharedApplication].statusBarOr

移动Web开发—处理设备的横竖屏

为了应对移动设备屏幕的碎片化,我们在开发Mobile Web应用时,一个最佳实践就是采用流式布局,保证最大可能地利用有限的屏幕空间.由于屏幕存在着方向性,用户在切换了屏幕的方向后,有些设计上或实现上的问题就会凸显——我们至少需要处理一下当前显示元素的宽度的适配(当然,要做的可能不仅仅是这个).很多时候,我们需要为不同的屏幕方向来设计对应的应用显示模式,这个时候,实时地获知设备的模竖屏状态就显得极为重要. http://dict.baidu.com/s?wd=%E6%B4%9B%E4%B8%BD%

android开发如何切换横竖屏

横竖屏设置 横竖屏的设置在AndroidManifest.xml文件中: screenOrientation="landscape"为横屏: screenOrientation="portrait"为竖屏:

iOS开发之判断横竖屏切换

/** *  当屏幕即将旋转的时候调用 * *  @param toInterfaceOrientation 旋转完毕后的最终方向 *  @param duration  旋转动画所花费的时间 */ - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { if (UIInterfaceOrientation

Android相机开发那些坑

版权声明:本文由王梓原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/168 来源:腾云阁 https://www.qcloud.com/community 最近我负责开发了一个跟Android相机有关的需求,新功能允许用户使用手机摄像头,快速拍摄特定尺寸(1:1或3:4)的照片,并支持在拍摄出的照片上做贴纸相关的操作.由于之前没有接触过Android相机开发,所以在整个开发过程中踩了不少坑,费了不少时间和精力.这篇文章总