private SurfaceView mSurfaceView;
private SurfaceHolder mHolder;
private Size mPreviewSize;
private Size adapterSize;
//private List mSupportedPreviewSizes;
private Camera mCamera;
private boolean isSupportAutoFocus = false;
private Camera.Parameters parameters = null;
private Context mContext;
//private int mCurrentCameraId = 0;
private int screenWidth;
private int screenHeight;
CameraPreview(Context context, SurfaceView sv) {
super(context);
mContext = context;
mSurfaceView = sv;
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mHolder.setKeepScreenOn(true);
isSupportAutoFocus = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA_AUTOFOCUS);
DisplayMetrics dm = new DisplayMetrics();
((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm);
screenWidth = dm.widthPixels;
screenHeight = dm.heightPixels;
}
public void setCamera(Camera camera) {
mCamera = camera;
initCamera();
}
public void initCamera() {
if (mCamera != null) {
Camera.Parameters params = mCamera.getParameters();
//mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
if (mPreviewSize == null) {
mPreviewSize = findBestPreviewResolution();
}
if (adapterSize == null) {
adapterSize = findBestPictureResolution();
}
if (adapterSize != null) {
params.setPictureSize(adapterSize.width, adapterSize.height);
}
if (mPreviewSize != null) {
params.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
}
params.setPictureFormat(PixelFormat.JPEG);
List focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
mCamera.setParameters(params);
}
setDispaly(params, mCamera);
//setCameraDisplayOrientation((Activity) mContext, mCurrentCameraId, mCamera);
mCamera.setParameters(params);
}
}
//控制圖像的正確顯示方向
private void setDispaly(Camera.Parameters parameters, Camera camera) {
if (Build.VERSION.SDK_INT >= 8) {
setDisplayOrientation(camera, 90);
} else {
parameters.setRotation(90);
}
}
//實(shí)現(xiàn)的圖像的正確顯示
private void setDisplayOrientation(Camera camera, int i) {
Method downPolymorphic;
try {
downPolymorphic = camera.getClass().getMethod(“setDisplayOrientation”,
new Class[]{int.class});
if (downPolymorphic != null) {
downPolymorphic.invoke(camera, new Object[]{i});
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, 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; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
// if (mSupportedPreviewSizes != null) {
// mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
// }
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException e) {
if (null != mCamera) {
mCamera.release();
mCamera = null;
}
e.printStackTrace();
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (holder.getSurface() == null) {
return;
}
if (mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
mCamera.startPreview();
reAutoFocus();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
}
}
/**
- 最小預(yù)覽界面的分辨率
*/
private static final int MIN_PREVIEW_PIXELS = 480 * 320;
/**
- 最大寬高比差
*/
private static final double MAX_ASPECT_DISTORTION = 0.15;
/**
-
找出最適合的預(yù)覽界面分辨率
-
@return
*/
private Camera.Size findBestPreviewResolution() {
Camera.Parameters cameraParameters = mCamera.getParameters();
Camera.Size defaultPreviewResolution = cameraParameters.getPreviewSize();
List<Camera.Size> rawSupportedSizes = cameraParameters.getSupportedPreviewSizes();
if (rawSupportedSizes == null) {
return defaultPreviewResolution;
}
// 按照分辨率從大到小排序
List<Camera.Size> supportedPreviewResolutions = new ArrayList<Camera.Size>(rawSupportedSizes);
Collections.sort(supportedPreviewResolutions, new Comparator() {
@Override
public int compare(Camera.Size a, Camera.Size b) {
int aPixels = a.height * a.width;
int bPixels = b.height * b.width;
if (bPixels < aPixels) {
return -1;
}
if (bPixels > aPixels) {
return 1;
}
return 0;
}
});
StringBuilder previewResolutionSb = new StringBuilder();
for (Camera.Size supportedPreviewResolution : supportedPreviewResolutions) {
previewResolutionSb.append(supportedPreviewResolution.width).append(‘x’).append(supportedPreviewResolution.height)
.append(’ ');
}
// 移除不符合條件的分辨率
double screenAspectRatio = (double) screenWidth
/ screenHeight;
Iterator it = supportedPreviewResolutions.iterator();
while (it.hasNext()) {
Camera.Size supportedPreviewResolution = it.next();
int width = supportedPreviewResolution.width;
int height = supportedPreviewResolution.height;
// 移除低于下限的分辨率,盡可能取高分辨率
if (width * height < MIN_PREVIEW_PIXELS) {
it.remove();
continue;
}
// 在camera分辨率與屏幕分辨率寬高比不相等的情況下,找出差距最小的一組分辨率
// 由于camera的分辨率是width>height,我們?cè)O(shè)置的portrait模式中,width<height
// 因此這里要先交換然preview寬高比后在比較
boolean isCandidatePortrait = width > height;
int maybeFlippedWidth = isCandidatePortrait ? height : width;
int maybeFlippedHeight = isCandidatePortrait ? width : height;
double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;
double distortion = Math.abs(aspectRatio - screenAspectRatio);
if (distortion > MAX_ASPECT_DISTORTION) {
it.remove();
continue;
}
// 找到與屏幕分辨率完全匹配的預(yù)覽界面分辨率直接返回
if (maybeFlippedWidth == screenWidth
&& maybeFlippedHeight == screenHeight) {
return supportedPreviewResolution;
}
}
// 如果沒(méi)有找到合適的,并且還有候選的像素,則設(shè)置其中最大比例的,對(duì)于配置比較低的機(jī)器不太合適
if (!supportedPreviewResolutions.isEmpty()) {
Camera.Size largestPreview = supportedPreviewResolutions.get(0);
return largestPreview;
}
// 沒(méi)有找到合適的,就返回默認(rèn)的
return defaultPreviewResolution;
}
private Camera.Size findBestPictureResolution() {
Camera.Parameters cameraParameters = mCamera.getParameters();
List<Camera.Size> supportedPicResolutions = cameraParameters.getSupportedPictureSizes(); // 至少會(huì)返回一個(gè)值
StringBuilder picResolutionSb = new StringBuilder();
for (Camera.Size supportedPicResolution : supportedPicResolutions) {
picResolutionSb.append(supportedPicResolution.width).append(‘x’)
.append(supportedPicResolution.height).append(" ");
}
Camera.Size defaultPictureResolution = cameraParameters.getPictureSize();
// 排序
List<Camera.Size> sortedSupportedPicResolutions = new ArrayList<Camera.Size>(
supportedPicResolutions);
Collections.sort(sortedSupportedPicResolutions, new Comparator<Camera.Size>() {
@Override
public int compare(Camera.Size a, Camera.Size b) {
int aPixels = a.height * a.width;
int bPixels = b.height * b.width;
if (bPixels < aPixels) {
return -1;
}
if (bPixels > aPixels) {
return 1;
}
return 0;
}
});
// 移除不符合條件的分辨率
double screenAspectRatio = screenWidth
/ (double) screenHeight;
Iterator<Camera.Size> it = sortedSupportedPicResolutions.iterator();
while (it.hasNext()) {
Camera.Size supportedPreviewResolution = it.next();
int width = supportedPreviewResolution.width;
int height = supportedPreviewResolution.height;
// 在camera分辨率與屏幕分辨率寬高比不相等的情況下,找出差距最小的一組分辨率
// 由于camera的分辨率是width>height,我們?cè)O(shè)置的portrait模式中,width<height
// 因此這里要先交換然后在比較寬高比
boolean isCandidatePortrait = width > height;
int maybeFlippedWidth = isCandidatePortrait ? height : width;
int maybeFlippedHeight = isCandidatePortrait ? width : height;
double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;
double distortion = Math.abs(aspectRatio - screenAspectRatio);
if (distortion > MAX_ASPECT_DISTORTION) {
it.remove();
continue;
}
}
// 如果沒(méi)有找到合適的,并且還有候選的像素,對(duì)于照片,則取其中最大比例的,而不是選擇與屏幕分辨率相同的
if (!sortedSupportedPicResolutions.isEmpty()) {
return sortedSupportedPicResolutions.get(0);
}
// 沒(méi)有找到合適的,就返回默認(rèn)的
return defaultPictureResolution;
}
private Size getOptimalPreviewSize(List 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;
}
public void reAutoFocus() {
if (isSupportAutoFocus) {
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
}
});
}
}
public List getResolutionList() {
return mCamera.getParameters().getSupportedPreviewSizes();
}
public Camera.Size getResolution() {
Camera.Parameters params = mCamera.getParameters();
Camera.Size s = params.getPreviewSize();
return s;
}
/*public void setCurrentCameraId(int current) {
mCurrentCameraId = current;
}*/
//定點(diǎn)對(duì)焦的代碼
public void pointFocus(MotionEvent event) {
mCamera.cancelAutoFocus();
parameters = mCamera.getParameters();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
//showPoint(x, y);
focusOnTouch(event);
}
mCamera.setParameters(parameters);
autoFocus();
}
//實(shí)現(xiàn)自動(dòng)對(duì)焦
public void autoFocus() {
new Thread() {
@Override
public void run() {
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (mCamera == null) {
return;
}
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (success) {
initCamera();//實(shí)現(xiàn)相機(jī)的參數(shù)初始化
}
}
});
}
};
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private void showPoint(int x, int y) {
if (parameters.getMaxNumMeteringAreas() > 0) {
List<Camera.Area> areas = new ArrayList<Camera.Area>();
WindowManager wm = (WindowManager) getContext()
.getSystemService(Context.WINDOW_SERVICE);
//xy變換了
int rectY = -x * 2000 / wm.getDefaultDisplay().getWidth() + 1000;
int rectX = y * 2000 / wm.getDefaultDisplay().getHeight() - 1000;
int left = rectX < -900 ? -1000 : rectX - 100;
int top = rectY < -900 ? -1000 : rectY - 100;
int right = rectX > 900 ? 1000 : rectX + 100;
int bottom = rectY > 900 ? 1000 : rectY + 100;
Rect area1 = new Rect(left, top, right, bottom);
areas.add(new Camera.Area(area1, 800));
parameters.setMeteringAreas(areas);
}
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
}
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void focusOnTouch(MotionEvent event) {
Rect focusRect = calculateTapArea(event.getRawX(), event.getRawY(), 1f);
Rect meteringRect = calculateTapArea(event.getRawX(), event.getRawY(), 1.5f);
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
if (parameters.getMaxNumFocusAreas() > 0) {
List<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
focusAreas.add(new Camera.Area(focusRect, 1000));
parameters.setFocusAreas(focusAreas);
}
if (parameters.getMaxNumMeteringAreas() > 0) {
List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
meteringAreas.add(new Camera.Area(meteringRect, 1000));
parameters.setMeteringAreas(meteringAreas);
}
mCamera.setParameters(parameters);
mCamera.autoFocus(this);
}
/**
- Convert touch position x:y to {@link Camera.Area} position -1000:-1000 to 1000:1000.
*/
private Rect calculateTapArea(float x, float y, float coefficient) {
float focusAreaSize = 300;
int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();
int centerX = (int) (x / getResolution().width * 2000 - 1000);
int centerY = (int) (y / getResolution().height * 2000 - 1000);
int left = clamp(centerX - areaSize / 2, -1000, 1000);
int right = clamp(left + areaSize, -1000, 1000);
int top = clamp(centerY - areaSize / 2, -1000, 1000);
int bottom = clamp(top + areaSize, -1000, 1000);
return new Rect(left, top, right, bottom);
}
private int clamp(int x, int min, int max) {
if (x > max) {
return max;
}
if (x < min) {
return min;
}
return x;
}
@Override
public void onAutoFocus(boolean success, Camera camera) {
}
public void setNull() {
adapterSize = null;
mPreviewSize = null;
}
}
以下是CameraActivity類:
public class CameraActivity extends Activity implements View.OnTouchListener,OnClickListener {
public static final String CAMERA_PATH_VALUE1 = “PHOTO_PATH”;
public static final String CAMERA_PATH_VALUE2 = “PATH”;
public static final String CAMERA_TYPE = “CAMERA_TYPE”;
public static final String CAMERA_RETURN_PATH = “return_path”;
private int PHOTO_SIZE_W = 2000;
private int PHOTO_SIZE_H = 2000;
public static final int CAMERA_TYPE_1 = 1;
public static final int CAMERA_TYPE_2 = 2;
private final int PROCESS = 1;
private CameraPreview preview;
private Camera camera;
private Context mContext;
private View focusIndex;
private ImageView flashBtn;
private int mCurrentCameraId = 0; // 1是前置 0是后置
private SurfaceView mSurfaceView;
private CameraGrid mCameraGrid;
private int type = 1; //引用的矩形框
private Button mBtnSearch;
private Button mBtnTakePhoto;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
//requestWindowFeature(Window.FEATURE_NO_TITLE);
//getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏
//getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//拍照過(guò)程屏幕一直處于高亮
setContentView(R.layout.camera_home);
type = getIntent().getIntExtra(CAMERA_TYPE, CAMERA_TYPE_2);
initView();
InitData();
}
private void initView() {
focusIndex = (View) findViewById(R.id.focus_index);
flashBtn = (ImageView) findViewById(R.id.flash_view);
mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
mCameraGrid = (CameraGrid) findViewById(R.id.camera_grid);
mBtnSearch = (Button) findViewById(R.id.search);
mBtnTakePhoto = (Button) findViewById(R.id.takephoto);
}
private void InitData() {
preview = new CameraPreview(this, mSurfaceView);
preview.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
((FrameLayout) findViewById(R.id.layout)).addView(preview);
preview.setKeepScreenOn(true);
mSurfaceView.setOnTouchListener(this);
mCameraGrid.setType(type);
}
private Handler handler = new Handler();
private void takePhoto() {
try {
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
} catch (Throwable t) {
t.printStackTrace();
Toast.makeText(getApplication(), “拍照失敗,請(qǐng)重試!”, Toast.LENGTH_LONG)
.show();
try {
camera.startPreview();
} catch (Throwable e) {
}
}
}
@Override
protected void onResume() {
super.onResume();
int numCams = Camera.getNumberOfCameras();
if (numCams > 0) {
try {
mCurrentCameraId = 0;
camera = Camera.open(mCurrentCameraId);
camera.startPreview();
preview.setCamera(camera);
preview.reAutoFocus();
} catch (RuntimeException ex) {
Toast.makeText(mContext, “未發(fā)現(xiàn)相機(jī)”, Toast.LENGTH_LONG).show();
}
}
}
@Override
protected void onPause() {
if (camera != null) {
camera.stopPreview();
preview.setCamera(null);
camera.release();
camera = null;
preview.setNull();
}
super.onPause();
}
自我介紹一下,小編13年上海交大畢業(yè),曾經(jīng)在小公司待過(guò),也去過(guò)華為、OPPO等大廠,18年進(jìn)入阿里一直到現(xiàn)在。
深知大多數(shù)初中級(jí)安卓工程師,想要提升技能,往往是自己摸索成長(zhǎng),但自己不成體系的自學(xué)效果低效又漫長(zhǎng),而且極易碰到天花板技術(shù)停滯不前!
因此收集整理了一份《2024年最新Android移動(dòng)開(kāi)發(fā)全套學(xué)習(xí)資料》送給大家,初衷也很簡(jiǎn)單,就是希望能夠幫助到想自學(xué)提升又不知道該從何學(xué)起的朋友,同時(shí)減輕大家的負(fù)擔(dān)。
由于文件比較大,這里只是將部分目錄截圖出來(lái),每個(gè)節(jié)點(diǎn)里面都包含大廠面經(jīng)、學(xué)習(xí)筆記、源碼講義、實(shí)戰(zhàn)項(xiàng)目、講解視頻
如果你覺(jué)得這些內(nèi)容對(duì)你有幫助,可以添加下面V無(wú)償領(lǐng)取?。▊渥ndroid)
推薦學(xué)習(xí)資料
-
腦圖
由于文章篇幅問(wèn)題點(diǎn)擊鏈接查看詳細(xì)文章以及獲取學(xué)習(xí)筆記:GitHub
s = Camera.getNumberOfCameras();
if (numCams > 0) {
try {
mCurrentCameraId = 0;
camera = Camera.open(mCurrentCameraId);
camera.startPreview();
preview.setCamera(camera);
preview.reAutoFocus();
} catch (RuntimeException ex) {
Toast.makeText(mContext, “未發(fā)現(xiàn)相機(jī)”, Toast.LENGTH_LONG).show();
}
}
}
@Override
protected void onPause() {
if (camera != null) {
camera.stopPreview();
preview.setCamera(null);
camera.release();
camera = null;
preview.setNull();
}
super.onPause();
}
自我介紹一下,小編13年上海交大畢業(yè),曾經(jīng)在小公司待過(guò),也去過(guò)華為、OPPO等大廠,18年進(jìn)入阿里一直到現(xiàn)在。
深知大多數(shù)初中級(jí)安卓工程師,想要提升技能,往往是自己摸索成長(zhǎng),但自己不成體系的自學(xué)效果低效又漫長(zhǎng),而且極易碰到天花板技術(shù)停滯不前!
因此收集整理了一份《2024年最新Android移動(dòng)開(kāi)發(fā)全套學(xué)習(xí)資料》送給大家,初衷也很簡(jiǎn)單,就是希望能夠幫助到想自學(xué)提升又不知道該從何學(xué)起的朋友,同時(shí)減輕大家的負(fù)擔(dān)。
[外鏈圖片轉(zhuǎn)存中…(img-xvpDDIQM-1710825578837)]
[外鏈圖片轉(zhuǎn)存中…(img-Zq9sR6SA-1710825578838)]
[外鏈圖片轉(zhuǎn)存中…(img-GnBFH99m-1710825578839)]
[外鏈圖片轉(zhuǎn)存中…(img-zAlqX13A-1710825578839)]文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-852934.html
由于文件比較大,這里只是將部分目錄截圖出來(lái),每個(gè)節(jié)點(diǎn)里面都包含大廠面經(jīng)、學(xué)習(xí)筆記、源碼講義、實(shí)戰(zhàn)項(xiàng)目、講解視頻
如果你覺(jué)得這些內(nèi)容對(duì)你有幫助,可以添加下面V無(wú)償領(lǐng)?。。▊渥ndroid)
[外鏈圖片轉(zhuǎn)存中…(img-uh5VQEOV-1710825578839)]文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-852934.html
推薦學(xué)習(xí)資料
-
腦圖
[外鏈圖片轉(zhuǎn)存中…(img-fgLvLPbG-1710825578840)]
[外鏈圖片轉(zhuǎn)存中…(img-1JDHMtTY-1710825578840)]
[外鏈圖片轉(zhuǎn)存中…(img-rSA1uxOU-1710825578841)]
由于文章篇幅問(wèn)題點(diǎn)擊鏈接查看詳細(xì)文章以及獲取學(xué)習(xí)筆記:GitHub
到了這里,關(guān)于Android相機(jī)開(kāi)發(fā)實(shí)戰(zhàn),面試題+筆記+項(xiàng)目實(shí)戰(zhàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!