A、配置使用相机权限
B、provider配置
C、meta-data标签:resource配置文件
2、授权打开系统相机:
A、打开页面授权:通过重写onRequestPermissionsResult方法获取授权结果。
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) !=
PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
requireActivity(),
arrayOf(Manifest.permission.CAMERA),
100
)
} else {
openCamera()
}
B、打开系统相机:下图中的imageUri是一个全局变量,是拍照成功后的图片 uri,拍照成功后在
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
方法中进行处理。
fun openCamera() {
val intent = Intent()
// 指定开启系统相机的Action
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE)
intent.addCategory(Intent.CATEGORY_DEFAULT)
// 根据文件地址创建文件
val file: File? = createImageFile()
if (file?.exists() == true) {
file?.delete()
}
// 把文件地址转换成Uri格式
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
/*7.0以上要通过FileProvider将File转化为Uri*/
imageUri = file?.let {
FileProvider.getUriForFile(
requireContext(), "com.example.camera.fileprovider",
it
)
};
} else {
/*7.0以下则直接使用Uri的fromFile方法将File转化为Uri*/
imageUri = Uri.fromFile(file);
}
// 设置系统相机拍摄照片完成后图片文件的存放地址
// 设置系统相机拍摄照片完成后图片文件的存放地址
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)
startActivityForResult(intent, 100)
}
注意:startActivityForResult() 是如果实在 Fragment中就不要使用 activity启动。
class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = CameraSurfaceView.class.getSimpleName();
private SurfaceHolder mSurfaceHolder;
public CameraSurfaceView(Context context) {
super(context);
init();
}
public CameraSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CameraSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
CameraUtils.openFrontalCamera(CameraUtils.DESIRED_PREVIEW_FPS);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
CameraUtils.startPreviewDisplay(holder);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
CameraUtils.releaseCamera();
}
}
public class CameraUtils {
// 相机默认宽高,相机的宽度和高度跟屏幕坐标不一样,手机屏幕的宽度和高度是反过来的。
public static final int DEFAULT_WIDTH = 1280;
public static final int DEFAULT_HEIGHT = 720;
public static final int DESIRED_PREVIEW_FPS = 270;
private static int mCameraID = Camera.CameraInfo.CAMERA_FACING_FRONT;
private static Camera mCamera;
private static int mCameraPreviewFps;
private static int mOrientation = 0;
/**
* 打开相机,默认打开后置相机
* @param expectFps
*/
public static void openFrontalCamera(int expectFps) {
if (mCamera != null) {
throw new RuntimeException("camera already initialized!");
}
Camera.CameraInfo info = new Camera.CameraInfo();
int numCameras = Camera.getNumberOfCameras();
// for (int i = 0; i < numCameras; i++) {
// Camera.getCameraInfo(i, info);
// if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
// mCamera = Camera.open(0);
// mCameraID = info.facing;
// break;
// }
// }
// 如果没有前置摄像头,则打开默认的后置摄像头
if (mCamera == null) {
mCamera = Camera.open();
mCameraID = Camera.CameraInfo.CAMERA_FACING_BACK;
}
// 没有摄像头时,抛出异常
if (mCamera == null) {
throw new RuntimeException("Unable to open camera");
}
Camera.Parameters parameters = mCamera.getParameters();
mCameraPreviewFps = CameraUtils.chooseFixedPreviewFps(parameters, expectFps * 1000);
parameters.setRecordingHint(true);
mCamera.setParameters(parameters);
setPreviewSize(mCamera, 480, 960);
// setPictureSize(mCamera, CameraUtils.DEFAULT_WIDTH, CameraUtils.DEFAULT_HEIGHT);
mCamera.setDisplayOrientation(mOrientation);
}
/**
* 根据ID打开相机
* @param cameraID
* @param expectFps
*/
public static void openCamera(int cameraID, int expectFps) {
if (mCamera != null) {
throw new RuntimeException("camera already initialized!");
}
mCamera = Camera.open(cameraID);
if (mCamera == null) {
throw new RuntimeException("Unable to open camera");
}
mCameraID = cameraID;
Camera.Parameters parameters = mCamera.getParameters();
mCameraPreviewFps = CameraUtils.chooseFixedPreviewFps(parameters, expectFps * 1000);
parameters.setRecordingHint(true);
mCamera.setParameters(parameters);
setPreviewSize(mCamera, CameraUtils.DEFAULT_WIDTH, CameraUtils.DEFAULT_HEIGHT);
setPictureSize(mCamera, CameraUtils.DEFAULT_WIDTH, CameraUtils.DEFAULT_HEIGHT);
mCamera.setDisplayOrientation(mOrientation);
}
/**
* 开始预览
* @param holder
*/
public static void startPreviewDisplay(SurfaceHolder holder) {
if (mCamera == null) {
throw new IllegalStateException("Camera must be set when start preview");
}
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 切换相机
* @param cameraID
*/
public static void switchCamera(int cameraID, SurfaceHolder holder) {
if (mCameraID == cameraID) {
return;
}
mCameraID = cameraID;
// 释放原来的相机
releaseCamera();
// 打开相机
openCamera(cameraID, CameraUtils.DESIRED_PREVIEW_FPS);
// 打开预览
startPreviewDisplay(holder);
}
/**
* 释放相机
*/
public static void releaseCamera() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
/**
* 开始预览
*/
public static void startPreview() {
if (mCamera != null) {
mCamera.startPreview();
}
}
/**
* 停止预览
*/
public static void stopPreview() {
if (mCamera != null) {
mCamera.stopPreview();
}
}
/**
* 拍照
*/
public static void takePicture(Camera.ShutterCallback shutterCallback,
Camera.PictureCallback rawCallback,
Camera.PictureCallback pictureCallback) {
if (mCamera != null) {
try{
mCamera.takePicture(shutterCallback, rawCallback, pictureCallback);
}catch (RuntimeException exception){
//takePicture failed
}
}
}
/**
* 设置预览大小
* @param camera
* @param expectWidth
* @param expectHeight
*/
public static void setPreviewSize(Camera camera, int expectWidth, int expectHeight) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = calculatePerfectSize(parameters.getSupportedPreviewSizes(),
expectWidth, expectHeight);
parameters.setPreviewSize(size.width, size.height);
camera.setParameters(parameters);
}
/**
* 获取预览大小
* @return
*/
public static Camera.Size getPreviewSize() {
if (mCamera != null) {
return mCamera.getParameters().getPreviewSize();
}
return null;
}
/**
* 设置拍摄的照片大小
* @param camera
* @param expectWidth
* @param expectHeight
*/
public static void setPictureSize(Camera camera, int expectWidth, int expectHeight) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = calculatePerfectSize(parameters.getSupportedPictureSizes(),
expectWidth, expectHeight);
parameters.setPictureSize(size.width, size.height);
camera.setParameters(parameters);
}
/**
* 获取照片大小
* @return
*/
public static Camera.Size getPictureSize() {
if (mCamera != null) {
return mCamera.getParameters().getPictureSize();
}
return null;
}
/**
* 计算最完美的Size
* @param sizes
* @param expectWidth
* @param expectHeight
* @return
*/
public static Camera.Size calculatePerfectSize(List sizes, int expectWidth,
int expectHeight) {
sortList(sizes); // 根据宽度进行排序
Camera.Size result = sizes.get(0);
boolean widthOrHeight = false; // 判断存在宽或高相等的Size
// 辗转计算宽高最接近的值
for (Camera.Size size: sizes) {
// 如果宽高相等,则直接返回
if (size.width == expectWidth && size.height == expectHeight) {
result = size;
break;
}
// 仅仅是宽度相等,计算高度最接近的size
if (size.width == expectWidth) {
widthOrHeight = true;
if (Math.abs(result.height - expectHeight)
> Math.abs(size.height - expectHeight)) {
result = size;
}
}
// 高度相等,则计算宽度最接近的Size
else if (size.height == expectHeight) {
widthOrHeight = true;
if (Math.abs(result.width - expectWidth)
> Math.abs(size.width - expectWidth)) {
result = size;
}
}
// 如果之前的查找不存在宽或高相等的情况,则计算宽度和高度都最接近的期望值的Size
else if (!widthOrHeight) {
if (Math.abs(result.width - expectWidth)
> Math.abs(size.width - expectWidth)
&& Math.abs(result.height - expectHeight)
> Math.abs(size.height - expectHeight)) {
result = size;
}
}
}
return result;
}
private static void sortList(List list) {
Collections.sort(list, new Comparator() {
@Override
public int compare(Camera.Size pre, Camera.Size after) {
if (pre.width > after.width) {
return 1;
} else if (pre.width < after.width) {
return -1;
}
return 0;
}
});
}
/**
* 选择合适的FPS
* @param parameters
* @param expectedThoudandFps 期望的FPS
* @return
*/
public static int chooseFixedPreviewFps(Camera.Parameters parameters, int expectedThoudandFps) {
List supportedFps = parameters.getSupportedPreviewFpsRange();
for (int[] entry : supportedFps) {
if (entry[0] == entry[1] && entry[0] == expectedThoudandFps) {
parameters.setPreviewFpsRange(entry[0], entry[1]);
return entry[0];
}
}
int[] temp = new int[2];
int guess;
parameters.getPreviewFpsRange(temp);
if (temp[0] == temp[1]) {
guess = temp[0];
} else {
guess = temp[1] / 2;
}
return guess;
}
public static int calculateCameraPreviewOrientation(Activity activity) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(mCameraID, info);
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360;
} else {
result = (info.orientation - degrees + 360) % 360;
}
mOrientation = result;
return result;
}
/**
* 获取当前的Camera ID
* @return
*/
public static int getCameraID() {
return mCameraID;
}
/**
* 获取当前预览的角度
* @return
*/
public static int getPreviewOrientation() {
return mOrientation;
}
/**
* 获取FPS(千秒值)
* @return
*/
public static int getCameraPreviewThousandFps() {
return mCameraPreviewFps;
}
}
CameraUtils.startPreview()
CameraUtils.stopPreview()
检测获取权限、给自定义 SurfaceView添加系统预览
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 11) {
mCameraSurfaceView = CameraSurfaceView(requireContext())
binding!!.surfaceView!!.addView(mCameraSurfaceView)
mOrientation = CameraUtils.calculateCameraPreviewOrientation(requireActivity())
}
}
private fun checkCameraHardware() {
if (ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_DENIED
) {
requestPermissions(arrayOf(Manifest.permission.CAMERA), 11)
}
if (requireContext().packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
try {
mCameraSurfaceView = CameraSurfaceView(requireContext())
binding!!.surfaceView!!.addView(mCameraSurfaceView)
mOrientation = CameraUtils.calculateCameraPreviewOrientation(requireActivity())
} catch (e: Exception) {
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val options = BitmapFactory.Options()
options.inJustDecodeBounds = false
if (resultCode == -1 && data != null) {
val uri = data.data
try {
val inputStream = requireContext().contentResolver.openInputStream(
uri!!
)
BitmapFactory.decodeStream(inputStream, null, options)
inputStream!!.close()
val height = options.outHeight
val width = options.outWidth
var sampleSize = 1
val max = Math.max(height, width)
val MAX_SIZE = 769
if (max > MAX_SIZE) {
val nw = width / 2
val nh = height / 2
while (nw / sampleSize > MAX_SIZE || nh / sampleSize > MAX_SIZE) {
sampleSize *= 2
}
}
options.inSampleSize = sampleSize
options.inJustDecodeBounds = false
bitmap = BitmapFactory.decodeStream(
requireContext().contentResolver.openInputStream(
uri
), null, options
)
if (bitmap != null) {
binding.surfaceView.visibility = View.GONE
binding.surfaceViewImage.visibility = View.VISIBLE
binding.surfaceViewImage.setImageBitmap(bitmap)
}
} catch (ioe: IOException) {
}
} else {
Toast.makeText(
requireContext(),
"Please select a photo before editing it.",
Toast.LENGTH_SHORT
).show()
// selectNegative();
}
}
三、Fragmeng源码其中还有调用系统相册的启动方法。
import android.Manifest
import android.app.ProgressDialog
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build
import android.os.Bundle
import android.util.Base64
import android.view.LayoutInflater
import android.view.View
import android.view.View.OnClickListener
import android.view.ViewGroup
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.NavHostFragment
import com.camalo.ganmer.omeman.BaseFragment
import com.camalo.ganmer.omeman.R
import com.camalo.ganmer.omeman.databinding.FragmentHomeBinding
import com.camalo.ganmer.omeman.ui.ViewModel
import com.camalo.ganmer.omeman.ui.a.CameraGVAdapter
import com.camalo.ganmer.omeman.ui.vvx.CameraInfo
import com.camalo.ganmer.omeman.ui.vvx.CameraSurfaceView
import com.camalo.ganmer.omeman.ui.vvx.CameraUtils
import com.camalo.ganmer.omeman.ui.vvx.ImageUtils
import com.camalo.ganmer.omeman.ui.vvx.Sp
import java.io.ByteArrayOutputStream
import java.io.IOException
class HomeFragment : BaseFragment(), OnClickListener, CameraGVAdapter.OnItemClickListener {
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
private var homeViewModel: ViewModel? = null
private var myGVAdapter: CameraGVAdapter? = null
private var selectCamera: Int = 0
private var selectCameraInfo: CameraInfo? = null
private var bitmap: Bitmap? = null
private var mOrientation = 0
private var index = 0
private var mCameraSurfaceView: CameraSurfaceView? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
homeViewModel =
ViewModelProvider(this)[ViewModel::class.java]
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onResume() {
super.onResume()
init()
CameraUtils.startPreview()
}
override fun onPause() {
super.onPause()
CameraUtils.stopPreview()
}
private fun init() {
checkCameraHardware()
selectCameraInfo = homeViewModel?.cameras?.get(0)
binding.ivToTakePricture.setOnClickListener(this)
binding.ivCameraBagBack.setOnClickListener(this)
binding.tvSelectPhotograph.setOnClickListener(this)
binding.ivPhotoBack.setOnClickListener(this)
binding.tvPictureRecord.setOnClickListener(this)
binding.tvSetting.setOnClickListener(this)
binding.ivPhoto.setOnClickListener(this)
binding.ivPhotoPicture.setOnClickListener(this)
binding.tvCameraInfo.setOnClickListener {
if (bitmap != null) {
val bundle = Bundle()
// bundle.putParcelable("info", selectCameraInfo)
bundle.putInt("info_type", selectCamera)
val baos = ByteArrayOutputStream()
bitmap!!.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val data = baos.toByteArray()
val imageString = String(Base64.encode(data, Base64.DEFAULT))
Sp.getInstance().setValue("bitmap",imageString)
// bundle.putByteArray("bitmap", data)
NavHostFragment.findNavController(this)
.navigate(R.id.action_navigation_home_to_EFragment, bundle)
}
}
}
@RequiresApi(Build.VERSION_CODES.O)
override fun onClick(v: View?) {
when (v?.id) {
R.id.tv_setting -> {
NavHostFragment.findNavController(this@HomeFragment)
.navigate(R.id.action_navigation_home_to_navigation_setting)
}
R.id.tv_picture_record -> {
NavHostFragment.findNavController(this@HomeFragment)
.navigate(R.id.action_navigation_home_to_record)
}
R.id.iv_to_take_pricture -> {
index = 2
binding.clCameraBag.visibility = View.GONE
binding.clPhoto.visibility = View.VISIBLE
binding.tvCameraInfo.text = selectCameraInfo?.name
binding.surfaceView.visibility = View.VISIBLE
}
R.id.iv_photo -> {
takePicture()
}
R.id.iv_camera_bag_back -> {
binding.clCameraBag.visibility = View.GONE
}
R.id.tv_select_photograph -> {
index = 1
binding.clPhoto.visibility = View.GONE
binding.clCameraBag.visibility = View.VISIBLE
myGVAdapter = homeViewModel?.cameras?.let {
CameraGVAdapter(
0, requireContext(),
it, R.layout.gv_camera_item
)
}
myGVAdapter?.setCurrentPosition(0, true)
myGVAdapter?.setOnItemClickListener(this)
binding.gvCameraBag.adapter = myGVAdapter
}
R.id.iv_photo_back -> {
binding.clPhoto.visibility = View.GONE
binding.surfaceView.visibility = View.VISIBLE
binding.surfaceViewImage.visibility = View.GONE
bitmap=null
}
R.id.iv_photo_picture -> {
selectNegative(-1)
}
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private fun takePicture() {
CameraUtils.takePicture({ }, null) { data, camera ->
CameraUtils.startPreview()
bitmap = BitmapFactory.decodeByteArray(data, 0, data.size)
binding.surfaceViewImage.visibility = View.VISIBLE
if (bitmap != null) {
bitmap = ImageUtils.getRotatedBitmap(bitmap, mOrientation);
binding.surfaceViewImage.setImageBitmap(bitmap)
}
}
}
private fun selectNegative(requestCode: Int) {
val intent = Intent()
intent.type = "image/*"
intent.action = Intent.ACTION_GET_CONTENT
startActivityForResult(Intent.createChooser(intent, ""), requestCode)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 11) {
mCameraSurfaceView = CameraSurfaceView(requireContext())
binding!!.surfaceView!!.addView(mCameraSurfaceView)
mOrientation = CameraUtils.calculateCameraPreviewOrientation(requireActivity())
}
}
private fun checkCameraHardware() {
if (ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_DENIED
) {
requestPermissions(arrayOf(Manifest.permission.CAMERA), 11)
}
if (requireContext().packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
try {
mCameraSurfaceView = CameraSurfaceView(requireContext())
binding!!.surfaceView!!.addView(mCameraSurfaceView)
mOrientation = CameraUtils.calculateCameraPreviewOrientation(requireActivity())
} catch (e: Exception) {
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val options = BitmapFactory.Options()
options.inJustDecodeBounds = false
if (resultCode == -1 && data != null) {
val uri = data.data
try {
val inputStream = requireContext().contentResolver.openInputStream(
uri!!
)
BitmapFactory.decodeStream(inputStream, null, options)
inputStream!!.close()
val height = options.outHeight
val width = options.outWidth
var sampleSize = 1
val max = Math.max(height, width)
val MAX_SIZE = 769
if (max > MAX_SIZE) {
val nw = width / 2
val nh = height / 2
while (nw / sampleSize > MAX_SIZE || nh / sampleSize > MAX_SIZE) {
sampleSize *= 2
}
}
options.inSampleSize = sampleSize
options.inJustDecodeBounds = false
bitmap = BitmapFactory.decodeStream(
requireContext().contentResolver.openInputStream(
uri
), null, options
)
if (bitmap != null) {
binding.surfaceView.visibility = View.GONE
binding.surfaceViewImage.visibility = View.VISIBLE
binding.surfaceViewImage.setImageBitmap(bitmap)
}
} catch (ioe: IOException) {
}
} else {
Toast.makeText(
requireContext(),
"Please select a photo before editing it.",
Toast.LENGTH_SHORT
).show()
// selectNegative();
}
}
override fun onCameraItemClick(
type: Int,
position: Int,
bitmap: Bitmap?,
cameraInfo: CameraInfo
) {
myGVAdapter?.setCurrentPosition(position, true)
selectCamera = position
selectCameraInfo = cameraInfo
binding.clCameraBag.visibility = View.GONE
binding.clPhoto.visibility = View.VISIBLE
binding.tvCameraInfo.text = selectCameraInfo?.name
binding.surfaceView.visibility = View.VISIBLE
}
}
谢谢阅读,呈请关注。如对鸿蒙开发有兴趣课试读我的专栏:http://t.csdnimg.cn/trIyc