├── .gitignore
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── interheart
│ │ └── com
│ │ └── circlecamera
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── dong
│ │ │ └── circlecamera
│ │ │ ├── MainActivity.java
│ │ │ └── view
│ │ │ ├── CameraListener.java
│ │ │ ├── CameraPreview.java
│ │ │ ├── CircleCameraLayout.java
│ │ │ ├── CircleView.java
│ │ │ ├── CircleView2.java
│ │ │ └── Util.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── interheart
│ └── com
│ └── circlecamera
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── image
└── 20180525184119.png
├── readme.md
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | defaultConfig {
6 | applicationId "com.dong.circlecamera"
7 | minSdkVersion 15
8 | targetSdkVersion 26
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 | implementation 'com.android.support:appcompat-v7:26.1.0'
24 | implementation 'com.android.support.constraint:constraint-layout:1.1.0'
25 | testImplementation 'junit:junit:4.12'
26 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
28 | }
29 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/interheart/com/circlecamera/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package interheart.com.circlecamera;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("interheart.com.circlecamera", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
19 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dong/circlecamera/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.dong.circlecamera;
2 |
3 | import android.Manifest;
4 | import android.content.DialogInterface;
5 | import android.content.pm.PackageManager;
6 | import android.graphics.Bitmap;
7 | import android.os.Bundle;
8 | import android.support.annotation.NonNull;
9 | import android.support.v4.app.ActivityCompat;
10 | import android.support.v7.app.AlertDialog;
11 | import android.support.v7.app.AppCompatActivity;
12 | import android.view.View;
13 | import android.widget.ImageView;
14 | import android.widget.Toast;
15 |
16 | import com.dong.circlecamera.view.CameraListener;
17 | import com.dong.circlecamera.view.CameraPreview;
18 | import com.dong.circlecamera.view.CircleCameraLayout;
19 | import com.dong.circlecamera.view.Util;
20 |
21 | /**
22 | * @author dong
23 | * @create 2018/5/25
24 | * @Describe 自定义圆形拍照、解决非全屏(竖屏)下预览相机拉伸问题。
25 | */
26 | public class MainActivity extends AppCompatActivity implements View.OnClickListener {
27 |
28 | private static final int PERMISSION_REQUEST_CODE = 10;
29 | private String[] mPermissions = {Manifest.permission.CAMERA};
30 |
31 | private CircleCameraLayout rootLayout;
32 | private ImageView imageView;
33 | private CameraPreview cameraPreview;
34 | private boolean hasPermissions;
35 | private boolean resume = false;//解决home键黑屏问题
36 |
37 | @Override
38 | protected void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | setContentView(R.layout.activity_main);
41 |
42 | findViewById(R.id.bt_take_photo).setOnClickListener(this);
43 | findViewById(R.id.bt_re_take_photo).setOnClickListener(this);
44 | rootLayout = findViewById(R.id.rootLayout);
45 | imageView = findViewById(R.id.image);
46 |
47 | //权限检查
48 | if (Util.checkPermissionAllGranted(this, mPermissions)) {
49 | hasPermissions = true;
50 | } else {
51 | ActivityCompat.requestPermissions(this, mPermissions, PERMISSION_REQUEST_CODE);
52 | }
53 |
54 |
55 | }
56 |
57 | @Override
58 | protected void onResume() {
59 | super.onResume();
60 | if (hasPermissions) {
61 | startCamera();
62 | resume = true;
63 | }
64 | }
65 |
66 | private void startCamera() {
67 | if (null != cameraPreview) cameraPreview.releaseCamera();
68 | cameraPreview = new CameraPreview(this);
69 | rootLayout.removeAllViews();
70 | rootLayout.setCameraPreview(cameraPreview);
71 | if (!hasPermissions || resume) {
72 | rootLayout.startView();
73 | }
74 | cameraPreview.setCameraListener(new CameraListener() {
75 | @Override
76 | public void onCaptured(Bitmap bitmap) {
77 | if (null != bitmap) {
78 | imageView.setImageBitmap(bitmap);
79 | Toast.makeText(MainActivity.this, "拍照成功", Toast.LENGTH_SHORT).show();
80 | } else {
81 | Toast.makeText(MainActivity.this, "拍照失败", Toast.LENGTH_SHORT).show();
82 | }
83 | }
84 | });
85 | }
86 |
87 | @Override
88 | public void onClick(View v) {
89 | if (null == cameraPreview) return;
90 | switch (v.getId()) {
91 | case R.id.bt_take_photo:
92 | cameraPreview.captureImage();//抓取照片
93 | break;
94 | case R.id.bt_re_take_photo:
95 | cameraPreview.startPreview();
96 | break;
97 | }
98 | }
99 |
100 | @Override
101 | protected void onDestroy() {
102 | super.onDestroy();
103 | if (null != cameraPreview) {
104 | cameraPreview.releaseCamera();
105 | }
106 | rootLayout.release();
107 | }
108 |
109 | /**
110 | * 申请权限结果返回处理
111 | */
112 | @Override
113 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
114 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
115 | if (requestCode == PERMISSION_REQUEST_CODE) {
116 | boolean isAllGranted = true;
117 | for (int grant : grantResults) { // 判断是否所有的权限都已经授予了
118 | if (grant != PackageManager.PERMISSION_GRANTED) {
119 | isAllGranted = false;
120 | break;
121 | }
122 | }
123 | if (isAllGranted) { // 所有的权限都授予了
124 | startCamera();
125 | } else {// 提示需要权限的原因
126 | AlertDialog.Builder builder = new AlertDialog.Builder(this);
127 | builder.setMessage("拍照需要允许权限, 是否再次开启?")
128 | .setTitle("提示")
129 | .setPositiveButton("确认", new DialogInterface.OnClickListener() {
130 | @Override
131 | public void onClick(DialogInterface dialog, int which) {
132 | ActivityCompat.requestPermissions(MainActivity.this, mPermissions, PERMISSION_REQUEST_CODE);
133 | }
134 | })
135 | .setNegativeButton("取消", new DialogInterface.OnClickListener() {
136 | @Override
137 | public void onClick(DialogInterface dialog, int which) {
138 | dialog.dismiss();
139 | finish();
140 | }
141 | });
142 | builder.create().show();
143 | }
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dong/circlecamera/view/CameraListener.java:
--------------------------------------------------------------------------------
1 | package com.dong.circlecamera.view;
2 |
3 | import android.graphics.Bitmap;
4 |
5 | /**
6 | * Created by dong on 2018/5/23.
7 | */
8 |
9 | public interface CameraListener {
10 |
11 | void onCaptured(Bitmap bitmap);
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dong/circlecamera/view/CameraPreview.java:
--------------------------------------------------------------------------------
1 | package com.dong.circlecamera.view;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Matrix;
7 | import android.hardware.Camera;
8 | import android.util.DisplayMetrics;
9 | import android.util.Log;
10 | import android.view.MotionEvent;
11 | import android.view.Surface;
12 | import android.view.SurfaceHolder;
13 | import android.view.SurfaceView;
14 |
15 | import java.io.IOException;
16 | import java.util.List;
17 |
18 | /**
19 | * Created by dong on 2018/5/23.
20 | */
21 |
22 | public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
23 | private static final String TAG = "CameraPreview";
24 |
25 | private Camera mCamera;
26 | private SurfaceHolder mHolder;
27 | private Activity mContext;
28 | private CameraListener listener;
29 | private int cameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
30 | private int displayDegree = 90;
31 |
32 | public CameraPreview(Activity context) {
33 | super(context);
34 | mContext = context;
35 | mCamera = Camera.open(cameraId);
36 | mHolder = getHolder();
37 | mHolder.addCallback(this);
38 | mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
39 | }
40 |
41 | public void setCameraListener(CameraListener listener) {
42 | this.listener = listener;
43 | }
44 |
45 | /**
46 | * 拍照获取bitmap
47 | */
48 | public void captureImage() {
49 | try {
50 | mCamera.takePicture(null, null, new Camera.PictureCallback() {
51 | @Override
52 | public void onPictureTaken(byte[] data, Camera camera) {
53 | if (null != listener) {
54 | Bitmap bitmap = rotateBitmap(BitmapFactory.decodeByteArray(data, 0, data.length),
55 | displayDegree);
56 | listener.onCaptured(bitmap);
57 | }
58 | }
59 | });
60 | } catch (Exception e) {
61 | e.printStackTrace();
62 | if (null != listener) {
63 | listener.onCaptured(null);
64 | }
65 | }
66 | }
67 |
68 | /**
69 | * 预览拍照
70 | */
71 | public void startPreview() {
72 | mCamera.startPreview();
73 | }
74 |
75 | @Override
76 | public boolean onTouchEvent(MotionEvent event) {
77 | if (null != mCamera) {
78 | mCamera.autoFocus(null);
79 | }
80 | return super.onTouchEvent(event);
81 | }
82 |
83 | @Override
84 | public void surfaceCreated(SurfaceHolder holder) {
85 | try {
86 | startCamera(holder);
87 | } catch (IOException e) {
88 | e.printStackTrace();
89 | }
90 | }
91 |
92 | @Override
93 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
94 | if (mHolder.getSurface() == null) {
95 | return;
96 | }
97 | try {
98 | mCamera.stopPreview();
99 | } catch (Exception e) {
100 | e.printStackTrace();
101 | }
102 | try {
103 | startCamera(mHolder);
104 | } catch (Exception e) {
105 | Log.e(TAG, e.toString());
106 | }
107 | }
108 |
109 | private void startCamera(SurfaceHolder holder) throws IOException {
110 | mCamera.setPreviewDisplay(holder);
111 | setCameraDisplayOrientation(mContext, cameraId, mCamera);
112 |
113 | Camera.Size preSize = getCameraSize();
114 |
115 | Camera.Parameters parameters = mCamera.getParameters();
116 | parameters.setPreviewSize(preSize.width, preSize.height);
117 | parameters.setPictureSize(preSize.width, preSize.height);
118 | parameters.setJpegQuality(100);
119 | mCamera.setParameters(parameters);
120 | mCamera.startPreview();
121 | }
122 |
123 | public Camera.Size getCameraSize() {
124 | if (null != mCamera) {
125 | Camera.Parameters parameters = mCamera.getParameters();
126 | DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
127 | Camera.Size preSize = Util.getCloselyPreSize(true, metrics.widthPixels, metrics.heightPixels,
128 | parameters.getSupportedPreviewSizes());
129 | return preSize;
130 | }
131 | return null;
132 | }
133 |
134 | @Override
135 | public void surfaceDestroyed(SurfaceHolder holder) {
136 | releaseCamera();
137 | }
138 |
139 |
140 | /**
141 | * Android API: Display Orientation Setting
142 | * Just change screen display orientation,
143 | * the rawFrame data never be changed.
144 | */
145 | private void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {
146 | Camera.CameraInfo info = new Camera.CameraInfo();
147 | Camera.getCameraInfo(cameraId, info);
148 | int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
149 | int degrees = 0;
150 | switch (rotation) {
151 | case Surface.ROTATION_0:
152 | degrees = 0;
153 | break;
154 | case Surface.ROTATION_90:
155 | degrees = 90;
156 | break;
157 | case Surface.ROTATION_180:
158 | degrees = 180;
159 | break;
160 | case Surface.ROTATION_270:
161 | degrees = 270;
162 | break;
163 | }
164 | if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
165 | displayDegree = (info.orientation + degrees) % 360;
166 | displayDegree = (360 - displayDegree) % 360; // compensate the mirror
167 | } else {
168 | displayDegree = (info.orientation - degrees + 360) % 360;
169 | }
170 | camera.setDisplayOrientation(displayDegree);
171 | }
172 |
173 |
174 | /**
175 | * 将图片按照某个角度进行旋转
176 | *
177 | * @param bm 需要旋转的图片
178 | * @param degree 旋转角度
179 | * @return 旋转后的图片
180 | */
181 | private Bitmap rotateBitmap(Bitmap bm, int degree) {
182 | Bitmap returnBm = null;
183 |
184 | // 根据旋转角度,生成旋转矩阵
185 | Matrix matrix = new Matrix();
186 | matrix.postRotate(degree);
187 | try {
188 | // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
189 | returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
190 | bm.getHeight(), matrix, true);
191 | } catch (OutOfMemoryError e) {
192 | e.printStackTrace();
193 | }
194 | if (returnBm == null) {
195 | returnBm = bm;
196 | }
197 | if (bm != returnBm) {
198 | bm.recycle();
199 | }
200 | return returnBm;
201 | }
202 |
203 | /**
204 | * 释放资源
205 | */
206 | public synchronized void releaseCamera() {
207 | try {
208 | if (null != mCamera) {
209 | mCamera.setPreviewCallback(null);
210 | mCamera.stopPreview();//停止预览
211 | mCamera.release(); // 释放相机资源
212 | mCamera = null;
213 | }
214 | if (null != mHolder) {
215 | mHolder.removeCallback(this);
216 | mHolder = null;
217 | }
218 | } catch (Exception e) {
219 | e.printStackTrace();
220 | }
221 | }
222 |
223 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/dong/circlecamera/view/CircleCameraLayout.java:
--------------------------------------------------------------------------------
1 | package com.dong.circlecamera.view;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Color;
7 | import android.graphics.Outline;
8 | import android.graphics.Rect;
9 | import android.hardware.Camera;
10 | import android.os.Build;
11 | import android.os.Handler;
12 | import android.os.Looper;
13 | import android.support.annotation.RequiresApi;
14 | import android.support.v4.content.ContextCompat;
15 | import android.util.AttributeSet;
16 | import android.util.Log;
17 | import android.view.View;
18 | import android.view.ViewGroup;
19 | import android.view.ViewOutlineProvider;
20 | import android.widget.FrameLayout;
21 | import android.widget.RelativeLayout;
22 |
23 |
24 | import com.dong.circlecamera.R;
25 |
26 | import java.util.Timer;
27 | import java.util.TimerTask;
28 |
29 | /**
30 | * Created by dong on 2018/5/23.
31 | */
32 |
33 | public class CircleCameraLayout extends RelativeLayout {
34 |
35 | public CircleCameraLayout(Context context) {
36 | super(context);
37 | init(context, null, -1, -1);
38 | }
39 |
40 | public CircleCameraLayout(Context context, AttributeSet attrs) {
41 | super(context, attrs);
42 | init(context, attrs, -1, -1);
43 | }
44 |
45 | public CircleCameraLayout(Context context, AttributeSet attrs, int defStyleAttr) {
46 | super(context, attrs, defStyleAttr);
47 | init(context, attrs, defStyleAttr, -1);
48 | }
49 |
50 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
51 | public CircleCameraLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
52 | super(context, attrs, defStyleAttr, defStyleRes);
53 | init(context, attrs, defStyleAttr, defStyleRes);
54 | }
55 |
56 |
57 | private Timer timer;
58 | private TimerTask pressTask;
59 | private Context mContext;
60 | private int circleWidth = 0;//指定半径
61 | private int borderWidth = 0;//指定边框
62 | private CameraPreview cameraPreview;//摄像预览
63 |
64 | private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
65 | mContext = context;
66 | timer = new Timer();
67 | if (attrs != null && defStyleAttr == -1 && defStyleRes == -1) {
68 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleCameraLayout, defStyleAttr, defStyleRes);
69 | circleWidth = (int) typedArray.getDimension(R.styleable.CircleCameraLayout_circle_camera_width, ViewGroup.LayoutParams.WRAP_CONTENT);
70 | borderWidth = (int) typedArray.getDimension(R.styleable.CircleCameraLayout_border_width, 5);
71 | typedArray.recycle();
72 | }
73 | startView();
74 | }
75 |
76 | /**
77 | * 设置照相预览
78 | *
79 | * @param cameraPreview
80 | */
81 | public void setCameraPreview(CameraPreview cameraPreview) {
82 | this.cameraPreview = cameraPreview;
83 | }
84 |
85 | /**
86 | * 释放回收
87 | */
88 | public void release() {
89 | if (null != pressTask) {
90 | pressTask.cancel();
91 | pressTask = null;
92 | }
93 | if (null != timer) {
94 | timer.cancel();
95 | timer = null;
96 | }
97 | }
98 |
99 | //延时启动摄像头
100 | public void startView() {
101 | pressTask = new TimerTask() {
102 | @Override
103 | public void run() {
104 | new Handler(Looper.getMainLooper()).post(new Runnable() {
105 | @Override
106 | public void run() {
107 | pressTask.cancel();
108 | pressTask = null;
109 | if (null != cameraPreview) {
110 | show();
111 | } else {
112 | startView();
113 | }
114 | }
115 | });
116 | }
117 | };
118 | timer.schedule(pressTask, 50);
119 | }
120 |
121 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
122 | private void show() {
123 | //cmaera根view--layout
124 | RelativeLayout cameraRoot = new RelativeLayout(mContext);
125 | RelativeLayout.LayoutParams rootParams = new RelativeLayout.LayoutParams(
126 | ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
127 | rootParams.addRule(CENTER_IN_PARENT, TRUE);
128 | cameraRoot.setBackgroundColor(Color.TRANSPARENT);
129 | cameraRoot.setClipChildren(false);
130 |
131 |
132 | //camera--layout
133 | FrameLayout cameraLayout = new FrameLayout(mContext);
134 | Camera.Size preSize = cameraPreview.getCameraSize();
135 | int cameraHeight = (int) ((float) preSize.width / (float) preSize.height * circleWidth);
136 | RelativeLayout.LayoutParams cameraParams = new RelativeLayout.LayoutParams(circleWidth, cameraHeight);
137 | cameraParams.addRule(CENTER_IN_PARENT, TRUE);
138 | cameraLayout.setLayoutParams(cameraParams);
139 | cameraLayout.addView(cameraPreview);
140 |
141 | cameraLayout.setOutlineProvider(viewOutlineProvider);//把自定义的轮廓提供者设置给imageView
142 | cameraLayout.setClipToOutline(true);//开启裁剪
143 |
144 | //circleView--layout
145 | // CircleView circleView = new CircleView(mContext);
146 | CircleView2 circleView = new CircleView2(mContext);
147 | circleView.setBorderWidth(circleWidth, borderWidth);
148 |
149 | //设置margin值---隐藏超出部分布局
150 | int margin = (cameraHeight - circleWidth) / 2 - borderWidth / 2;
151 | rootParams.setMargins(0, -margin, 0, -margin);
152 | cameraRoot.setLayoutParams(rootParams);
153 |
154 | //添加camera
155 | cameraRoot.addView(cameraLayout);
156 | //添加circle
157 | cameraRoot.addView(circleView);
158 | //添加根布局
159 | this.addView(cameraRoot);
160 | }
161 |
162 | //自定义一个轮廓提供者
163 | public ViewOutlineProvider viewOutlineProvider = new ViewOutlineProvider() {
164 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
165 | @Override
166 | public void getOutline(View view, Outline outline) {
167 | //裁剪成一个圆形
168 | int left0 = 0;
169 | int top0 = (view.getHeight() - view.getWidth()) / 2;
170 | int right0 = view.getWidth();
171 | int bottom0 = (view.getHeight() - view.getWidth()) / 2 + view.getWidth();
172 | outline.setOval(left0, top0, right0, bottom0);
173 | }
174 | };
175 |
176 | }
177 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dong/circlecamera/view/CircleView.java:
--------------------------------------------------------------------------------
1 | package com.dong.circlecamera.view;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.Path;
8 | import android.graphics.PorterDuff;
9 | import android.graphics.PorterDuffXfermode;
10 | import android.os.Build;
11 | import android.support.annotation.Nullable;
12 | import android.util.AttributeSet;
13 | import android.view.View;
14 | import android.widget.RelativeLayout;
15 |
16 | import com.dong.circlecamera.R;
17 |
18 |
19 | /**
20 | * Created by dong on 2018/5/23.
21 | */
22 |
23 | public class CircleView extends View {
24 |
25 | public CircleView(Context context) {
26 | super(context);
27 | init();
28 | }
29 |
30 | public CircleView(Context context, @Nullable AttributeSet attrs) {
31 | super(context, attrs);
32 | init();
33 | }
34 |
35 | public CircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
36 | super(context, attrs, defStyleAttr);
37 | init();
38 | }
39 |
40 | private Paint borderPaint;
41 | private int borderWidth;
42 |
43 | /**
44 | * @param circleWidth 指定view宽高
45 | * @param borderWidth 边框宽度
46 | */
47 | public void setBorderWidth(int circleWidth, int borderWidth) {
48 | this.borderWidth = borderWidth;
49 | RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(circleWidth, circleWidth + borderWidth * 2);
50 | params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
51 | setLayoutParams(params);
52 | }
53 |
54 | private void init() {
55 | int borderColor = getResources().getColor(R.color.colorAccent);
56 | if (null == borderPaint){
57 | borderPaint = new Paint();
58 | borderPaint.setColor(borderColor);
59 | borderPaint.setStyle(Paint.Style.STROKE);
60 | borderPaint.setAntiAlias(true);//抗锯齿
61 | borderPaint.setDither(true);//防抖动
62 | }
63 | }
64 |
65 | @Override
66 | protected void onDraw(Canvas canvas) {
67 | super.onDraw(canvas);
68 | //画边框
69 | if (borderWidth != 0) {
70 | borderPaint.setStrokeWidth(borderWidth);
71 | float x = getWidth() / 2.0F;
72 | float y = getHeight() / 2.0F;
73 | float radius = getWidth() / 2.0F - borderWidth / 2.0F + 1;
74 | canvas.drawCircle(x, y, radius, borderPaint);
75 | }
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dong/circlecamera/view/CircleView2.java:
--------------------------------------------------------------------------------
1 | package com.dong.circlecamera.view;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.Path;
8 | import android.graphics.PorterDuff;
9 | import android.graphics.PorterDuffXfermode;
10 | import android.graphics.RectF;
11 | import android.os.Build;
12 | import android.support.annotation.Nullable;
13 | import android.util.AttributeSet;
14 | import android.util.Log;
15 | import android.view.View;
16 | import android.widget.RelativeLayout;
17 |
18 | import com.dong.circlecamera.R;
19 |
20 |
21 | /**
22 | * Created by dong on 2018/5/23.
23 | * kl
24 | */
25 |
26 | public class CircleView2 extends View {
27 |
28 | public CircleView2(Context context) {
29 | super(context);
30 | init();
31 | }
32 |
33 | public CircleView2(Context context, @Nullable AttributeSet attrs) {
34 | super(context, attrs);
35 | init();
36 | }
37 |
38 | public CircleView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
39 | super(context, attrs, defStyleAttr);
40 | init();
41 | }
42 |
43 | private Paint paint;
44 | private int borderWidth;
45 | private RectF rectF;
46 |
47 | /**
48 | * @param circleWidth 指定view宽高
49 | * @param borderWidth 边框宽度
50 | */
51 | public void setBorderWidth(int circleWidth, int borderWidth) {
52 | this.borderWidth = borderWidth;
53 | RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(circleWidth, circleWidth + borderWidth * 2);
54 | params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
55 | setLayoutParams(params);
56 | }
57 |
58 | private void init() {
59 | setBackgroundColor(Color.TRANSPARENT);
60 | //圆形边框
61 | int borderColor = getResources().getColor(R.color.colorAccent);
62 | paint = new Paint();
63 | paint.setColor(borderColor);
64 | paint.setStyle(Paint.Style.STROKE);
65 | paint.setAntiAlias(true);//抗锯齿
66 | paint.setDither(true);//防抖动
67 | }
68 |
69 | @Override
70 | protected void onDraw(Canvas canvas) {
71 | super.onDraw(canvas);
72 | if (borderWidth != 0) {
73 | paint.setStrokeWidth(borderWidth);
74 | int left = borderWidth / 2;
75 | int top = (getHeight() - (getWidth())) / 2 + borderWidth / 2;
76 | int right = getWidth() - borderWidth / 2;
77 | int bottom = (getHeight() - getWidth()) / 2 + getWidth() - borderWidth / 2;
78 |
79 | if (null == rectF) rectF = new RectF(left, top, right, bottom);
80 | canvas.drawArc(rectF, 0, 360, false, paint);
81 | }
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/dong/circlecamera/view/Util.java:
--------------------------------------------------------------------------------
1 | package com.dong.circlecamera.view;
2 |
3 | import android.content.Context;
4 | import android.content.pm.PackageManager;
5 | import android.hardware.Camera;
6 | import android.support.v4.content.ContextCompat;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * Created by dong on 2018/5/23.
12 | */
13 |
14 | public class Util {
15 |
16 | /**
17 | * 通过对比得到与宽高比最接近的预览尺寸(如果有相同尺寸,优先选择)
18 | *
19 | * @param isPortrait 是否竖屏
20 | * @param surfaceWidth 需要被进行对比的原宽
21 | * @param surfaceHeight 需要被进行对比的原高
22 | * @param preSizeList 需要对比的预览尺寸列表
23 | * @return 得到与原宽高比例最接近的尺寸
24 | */
25 | public static Camera.Size getCloselyPreSize(boolean isPortrait, int surfaceWidth, int surfaceHeight, List preSizeList) {
26 | int reqTmpWidth;
27 | int reqTmpHeight;
28 | // 当屏幕为垂直的时候需要把宽高值进行调换,保证宽大于高
29 | if (isPortrait) {
30 | reqTmpWidth = surfaceHeight;
31 | reqTmpHeight = surfaceWidth;
32 | } else {
33 | reqTmpWidth = surfaceWidth;
34 | reqTmpHeight = surfaceHeight;
35 | }
36 | //先查找preview中是否存在与surfaceview相同宽高的尺寸
37 | for (Camera.Size size : preSizeList) {
38 | if ((size.width == reqTmpWidth) && (size.height == reqTmpHeight)) {
39 | return size;
40 | }
41 | }
42 | // 得到与传入的宽高比最接近的size
43 | float reqRatio = ((float) reqTmpWidth) / reqTmpHeight;
44 | float curRatio, deltaRatio;
45 | float deltaRatioMin = Float.MAX_VALUE;
46 | Camera.Size retSize = null;
47 | for (Camera.Size size : preSizeList) {
48 | curRatio = ((float) size.width) / size.height;
49 | deltaRatio = Math.abs(reqRatio - curRatio);
50 | if (deltaRatio < deltaRatioMin) {
51 | deltaRatioMin = deltaRatio;
52 | retSize = size;
53 | }
54 | }
55 | return retSize;
56 | }
57 |
58 |
59 | /**
60 | * 检查是否拥有指定的所有权限
61 | */
62 | public static boolean checkPermissionAllGranted(Context context, String[] permissions) {
63 | for (String permission : permissions) {
64 | if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
65 | // 只要有一个权限没有被授予, 则直接返回 false
66 | return false;
67 | }
68 | }
69 | return true;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
22 |
23 |
27 |
28 |
29 |
34 |
35 |
38 |
39 |
40 |
41 |
42 |
43 |
48 |
49 |
55 |
56 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dong1024/CircleCamera/d5c479a558b797f4eb570e5e41225c6de579ab6e/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dong1024/CircleCamera/d5c479a558b797f4eb570e5e41225c6de579ab6e/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dong1024/CircleCamera/d5c479a558b797f4eb570e5e41225c6de579ab6e/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dong1024/CircleCamera/d5c479a558b797f4eb570e5e41225c6de579ab6e/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dong1024/CircleCamera/d5c479a558b797f4eb570e5e41225c6de579ab6e/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dong1024/CircleCamera/d5c479a558b797f4eb570e5e41225c6de579ab6e/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dong1024/CircleCamera/d5c479a558b797f4eb570e5e41225c6de579ab6e/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dong1024/CircleCamera/d5c479a558b797f4eb570e5e41225c6de579ab6e/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dong1024/CircleCamera/d5c479a558b797f4eb570e5e41225c6de579ab6e/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dong1024/CircleCamera/d5c479a558b797f4eb570e5e41225c6de579ab6e/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CircleCamera
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/interheart/com/circlecamera/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package interheart.com.circlecamera;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.0.1'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dong1024/CircleCamera/d5c479a558b797f4eb570e5e41225c6de579ab6e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri May 25 17:59:28 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/image/20180525184119.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dong1024/CircleCamera/d5c479a558b797f4eb570e5e41225c6de579ab6e/image/20180525184119.png
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | 功能说明:
2 | 1、自定义圆形拍照、解决非全屏(竖屏)下预览相机拉伸问题。
3 | 2、平板摄像不规则分辨率下预览能够正常显示。
4 |
5 |
6 | 
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------