├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── cymaybe │ │ └── foucssurfaceview │ │ └── ExampleInstrumentedTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── cymaybe │ │ └── foucssurfaceview │ │ ├── activity │ │ └── MainActivity.java │ │ └── fragment │ │ └── PictureFragment.java │ └── res │ ├── drawable-xxhdpi │ ├── ic_take_picture_normal.png │ └── ic_take_picture_pressed.png │ ├── drawable │ └── take_picture_button_bg.xml │ ├── layout-land │ ├── activity_main.xml │ ├── crop_mode_layout.xml │ └── picture_layout.xml │ ├── layout │ ├── activity_main.xml │ ├── crop_mode_layout.xml │ └── picture_layout.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── focussurfaceview ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── cymaybe │ │ └── foucsurfaceview │ │ └── ExampleInstrumentedTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── cymaybe │ │ └── foucsurfaceview │ │ ├── FocusSurfaceView.java │ │ └── animation │ │ ├── SimpleValueAnimator.java │ │ ├── SimpleValueAnimatorListener.java │ │ ├── ValueAnimatorV14.java │ │ └── ValueAnimatorV8.java │ └── res │ └── values │ ├── attrs.xml │ └── strings.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots ├── circle.png ├── circle_pre.png ├── demo.gif ├── free.png ├── free_pre.png ├── ratio_3_4.png ├── ratio_3_4_pre.png ├── square.png └── square_pre.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | 19 | # Local configuration file (sdk path, etc) 20 | local.properties 21 | 22 | # Proguard folder generated by Eclipse 23 | proguard/ 24 | 25 | # Log Files 26 | *.log 27 | 28 | # Android Studio Navigation editor temp files 29 | .navigation/ 30 | 31 | # Android Studio captures folder 32 | captures/ 33 | 34 | 35 | # added by moubiao 2016-03-29 36 | fingerprint-recognition.iml 37 | 38 | # generated files 39 | out/ 40 | 41 | # Windows thumbnail db 42 | Thumbs.db 43 | 44 | # OSX files 45 | .DS_Store 46 | 47 | # Eclipse project files 48 | .classpath 49 | .project 50 | 51 | # Android Studio 52 | *.iml 53 | .idea 54 | 55 | # Local IDEA workspace 56 | .idea/workspace.xml 57 | 58 | # NDK 59 | obj/ 60 | 61 | # added by moubiao 2016-03-30 62 | test/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FocusSurfaceView 2 | 该库大部分参考IsseiAoki的SimpleCropView https://github.com/IsseiAoki/SimpleCropView
3 | 实现了在相机的预览界面指定一个区域的大小,形状和位置,只拍摄该指定区域里的图像
4 | 支持 API Level 10 and above.
5 | ![](https://github.com/CGmaybe10/FocusSurfaceView/blob/master/screenshots/demo.gif)
6 | ![](https://github.com/CGmaybe10/FocusSurfaceView/blob/master/screenshots/circle.png) 7 | ![](https://github.com/CGmaybe10/FocusSurfaceView/blob/master/screenshots/circle_pre.png) 8 | ![](https://github.com/CGmaybe10/FocusSurfaceView/blob/master/screenshots/square.png) 9 | ![](https://github.com/CGmaybe10/FocusSurfaceView/blob/master/screenshots/square_pre.png) 10 | ##使用方法:
11 | 在工程和module里的build.gradle分别添加 12 | ```groovy 13 | allprojects { 14 | repositories { 15 | ... 16 | maven { url 'https://jitpack.io' } 17 | } 18 | } 19 | dependencies { 20 | compile 'com.github.CGmaybe10:FocusSurfaceView:v1.0.1' 21 | } 22 | ``` 23 | ```xml 24 | 45 | ``` 46 | ```java 47 | private FocusSurfaceView previewSFV = (FocusSurfaceView) findViewById(R.id.preview_sv); 48 | mCamera.autoFocus(new Camera.AutoFocusCallback() { 49 | @Override 50 | public void onAutoFocus(boolean success, Camera camera) { 51 | mCamera.takePicture(new Camera.ShutterCallback() { 52 | @Override 53 | public void onShutter() { 54 | } 55 | }, null, null, new Camera.PictureCallback() { 56 | @Override 57 | public void onPictureTaken(byte[] data, Camera camera) { 58 | Bitmap cropBitmap = previewSFV.getPicture(data); 59 | } 60 | }); 61 | } 62 | } 63 | }); 64 | ``` 65 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.0" 6 | defaultConfig { 7 | applicationId "com.cymaybe.foucssurfaceview" 8 | minSdkVersion 14 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.0.1' 28 | compile 'com.android.support:design:25.0.1' 29 | testCompile 'junit:junit:4.12' 30 | compile project(':focussurfaceview') 31 | } 32 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/cymaybe/foucssurfaceview/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.cymaybe.foucssurfaceview; 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 | * Instrumentation 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("com.cymaybe.foucssurfaceview", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/cymaybe/foucssurfaceview/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.cymaybe.foucssurfaceview.activity; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageManager; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.hardware.Camera; 8 | import android.os.Bundle; 9 | import android.support.annotation.Nullable; 10 | import android.support.design.widget.Snackbar; 11 | import android.support.v4.app.ActivityCompat; 12 | import android.support.v4.content.ContextCompat; 13 | import android.support.v7.app.AppCompatActivity; 14 | import android.view.OrientationEventListener; 15 | import android.view.Surface; 16 | import android.view.SurfaceHolder; 17 | import android.view.View; 18 | import android.widget.Button; 19 | 20 | import com.cymaybe.foucssurfaceview.R; 21 | import com.cymaybe.foucssurfaceview.fragment.PictureFragment; 22 | import com.cymaybe.foucsurfaceview.FocusSurfaceView; 23 | 24 | import static android.Manifest.permission.CAMERA; 25 | import static com.cymaybe.foucssurfaceview.fragment.PictureFragment.CROP_PICTURE; 26 | import static com.cymaybe.foucssurfaceview.fragment.PictureFragment.ORIGIN_PICTURE; 27 | 28 | public class MainActivity extends AppCompatActivity implements View.OnClickListener, SurfaceHolder.Callback { 29 | private static final String TAG = "moubiao"; 30 | 31 | private FocusSurfaceView previewSFV; 32 | private Button mTakeBT, mThreeFourBT, mFourThreeBT, mNineSixteenBT, mSixteenNineBT, mFitImgBT, mCircleBT, mFreeBT, mSquareBT, 33 | mCircleSquareBT, mCustomBT; 34 | 35 | private Camera mCamera; 36 | private SurfaceHolder mHolder; 37 | private boolean focus = false; 38 | 39 | @Override 40 | protected void onCreate(@Nullable Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.activity_main); 43 | 44 | initData(); 45 | initView(); 46 | setListener(); 47 | } 48 | 49 | private void initData() { 50 | DetectScreenOrientation detectScreenOrientation = new DetectScreenOrientation(this); 51 | detectScreenOrientation.enable(); 52 | } 53 | 54 | private void initView() { 55 | previewSFV = (FocusSurfaceView) findViewById(R.id.preview_sv); 56 | mHolder = previewSFV.getHolder(); 57 | mHolder.addCallback(MainActivity.this); 58 | mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 59 | 60 | mTakeBT = (Button) findViewById(R.id.take_bt); 61 | mThreeFourBT = (Button) findViewById(R.id.three_four_bt); 62 | mFourThreeBT = (Button) findViewById(R.id.four_three_bt); 63 | mNineSixteenBT = (Button) findViewById(R.id.nine_sixteen_bt); 64 | mSixteenNineBT = (Button) findViewById(R.id.sixteen_nine_bt); 65 | mFitImgBT = (Button) findViewById(R.id.fit_image_bt); 66 | mCircleBT = (Button) findViewById(R.id.circle_bt); 67 | mFreeBT = (Button) findViewById(R.id.free_bt); 68 | mSquareBT = (Button) findViewById(R.id.square_bt); 69 | mCircleSquareBT = (Button) findViewById(R.id.circle_square_bt); 70 | mCustomBT = (Button) findViewById(R.id.custom_bt); 71 | } 72 | 73 | private void setListener() { 74 | mTakeBT.setOnClickListener(this); 75 | mThreeFourBT.setOnClickListener(this); 76 | mFourThreeBT.setOnClickListener(this); 77 | mNineSixteenBT.setOnClickListener(this); 78 | mSixteenNineBT.setOnClickListener(this); 79 | mFitImgBT.setOnClickListener(this); 80 | mCircleBT.setOnClickListener(this); 81 | mFreeBT.setOnClickListener(this); 82 | mSquareBT.setOnClickListener(this); 83 | mCircleSquareBT.setOnClickListener(this); 84 | mCustomBT.setOnClickListener(this); 85 | } 86 | 87 | @Override 88 | public void surfaceCreated(SurfaceHolder surfaceHolder) { 89 | initCamera(); 90 | setCameraParams(); 91 | } 92 | 93 | private void initCamera() { 94 | if (checkPermission()) { 95 | try { 96 | mCamera = android.hardware.Camera.open(0);//1:采集指纹的摄像头. 0:拍照的摄像头. 97 | mCamera.setPreviewDisplay(mHolder); 98 | } catch (Exception e) { 99 | Snackbar.make(mTakeBT, "camera open failed!", Snackbar.LENGTH_SHORT).show(); 100 | finish(); 101 | e.printStackTrace(); 102 | } 103 | } else { 104 | requestPermission(); 105 | } 106 | } 107 | 108 | private boolean checkPermission() { 109 | return ContextCompat.checkSelfPermission(getApplicationContext(), CAMERA) == PackageManager.PERMISSION_GRANTED; 110 | } 111 | 112 | private void requestPermission() { 113 | ActivityCompat.requestPermissions(this, new String[]{CAMERA}, 10000); 114 | } 115 | 116 | @Override 117 | public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { 118 | switch (requestCode) { 119 | case 10000: 120 | if (grantResults.length > 0) { 121 | if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { 122 | initCamera(); 123 | setCameraParams(); 124 | } 125 | } 126 | 127 | break; 128 | } 129 | } 130 | 131 | private void setCameraParams() { 132 | if (mCamera == null) { 133 | return; 134 | } 135 | try { 136 | Camera.Parameters parameters = mCamera.getParameters(); 137 | 138 | int orientation = judgeScreenOrientation(); 139 | if (Surface.ROTATION_0 == orientation) { 140 | mCamera.setDisplayOrientation(90); 141 | parameters.setRotation(90); 142 | } else if (Surface.ROTATION_90 == orientation) { 143 | mCamera.setDisplayOrientation(0); 144 | parameters.setRotation(0); 145 | } else if (Surface.ROTATION_180 == orientation) { 146 | mCamera.setDisplayOrientation(180); 147 | parameters.setRotation(180); 148 | } else if (Surface.ROTATION_270 == orientation) { 149 | mCamera.setDisplayOrientation(180); 150 | parameters.setRotation(180); 151 | } 152 | 153 | parameters.setPictureSize(1280, 720); 154 | parameters.setPreviewSize(1280, 720); 155 | mCamera.setParameters(parameters); 156 | mCamera.startPreview(); 157 | } catch (Exception e) { 158 | e.printStackTrace(); 159 | } 160 | } 161 | 162 | @Override 163 | public void onWindowFocusChanged(boolean hasFocus) { 164 | View decorView = getWindow().getDecorView(); 165 | decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE 166 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 167 | | View.SYSTEM_UI_FLAG_FULLSCREEN 168 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); 169 | } 170 | 171 | /** 172 | * 判断屏幕方向 173 | * 174 | * @return 0:竖屏 1:左横屏 2:反向竖屏 3:右横屏 175 | */ 176 | private int judgeScreenOrientation() { 177 | return getWindowManager().getDefaultDisplay().getRotation(); 178 | } 179 | 180 | @Override 181 | public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { 182 | 183 | } 184 | 185 | @Override 186 | public void surfaceDestroyed(SurfaceHolder surfaceHolder) { 187 | releaseCamera(); 188 | } 189 | 190 | private void releaseCamera() { 191 | if (mCamera != null) { 192 | mCamera.stopPreview(); 193 | mCamera.release(); 194 | mCamera = null; 195 | } 196 | } 197 | 198 | @Override 199 | public void onClick(View view) { 200 | switch (view.getId()) { 201 | case R.id.take_bt: 202 | if (!focus) { 203 | takePicture(); 204 | } 205 | break; 206 | case R.id.three_four_bt: 207 | previewSFV.setCropMode(FocusSurfaceView.CropMode.RATIO_3_4); 208 | break; 209 | case R.id.four_three_bt: 210 | previewSFV.setCropMode(FocusSurfaceView.CropMode.RATIO_4_3); 211 | break; 212 | case R.id.nine_sixteen_bt: 213 | previewSFV.setCropMode(FocusSurfaceView.CropMode.RATIO_9_16); 214 | break; 215 | case R.id.sixteen_nine_bt: 216 | previewSFV.setCropMode(FocusSurfaceView.CropMode.RATIO_16_9); 217 | break; 218 | case R.id.fit_image_bt: 219 | previewSFV.setCropMode(FocusSurfaceView.CropMode.FIT_IMAGE); 220 | break; 221 | case R.id.circle_bt: 222 | previewSFV.setCropMode(FocusSurfaceView.CropMode.CIRCLE); 223 | break; 224 | case R.id.free_bt: 225 | previewSFV.setCropMode(FocusSurfaceView.CropMode.FREE); 226 | break; 227 | case R.id.square_bt: 228 | previewSFV.setCropMode(FocusSurfaceView.CropMode.SQUARE); 229 | break; 230 | case R.id.circle_square_bt: 231 | previewSFV.setCropMode(FocusSurfaceView.CropMode.CIRCLE_SQUARE); 232 | break; 233 | case R.id.custom_bt: 234 | previewSFV.setCropMode(FocusSurfaceView.CropMode.CUSTOM); 235 | break; 236 | default: 237 | break; 238 | } 239 | } 240 | 241 | /** 242 | * 拍照 243 | */ 244 | private void takePicture() { 245 | mCamera.autoFocus(new Camera.AutoFocusCallback() { 246 | @Override 247 | public void onAutoFocus(boolean success, Camera camera) { 248 | focus = success; 249 | if (success) { 250 | mCamera.cancelAutoFocus(); 251 | mCamera.takePicture(new Camera.ShutterCallback() { 252 | @Override 253 | public void onShutter() { 254 | } 255 | }, null, null, new Camera.PictureCallback() { 256 | @Override 257 | public void onPictureTaken(byte[] data, Camera camera) { 258 | Bitmap originBitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 259 | Bitmap cropBitmap = previewSFV.getPicture(data); 260 | PictureFragment pictureFragment = new PictureFragment(); 261 | Bundle bundle = new Bundle(); 262 | bundle.putParcelable(ORIGIN_PICTURE, originBitmap); 263 | bundle.putParcelable(CROP_PICTURE, cropBitmap); 264 | pictureFragment.setArguments(bundle); 265 | pictureFragment.show(getFragmentManager(), null); 266 | 267 | focus = false; 268 | mCamera.startPreview(); 269 | } 270 | }); 271 | } 272 | } 273 | }); 274 | } 275 | 276 | /** 277 | * 用来监测左横屏和右横屏切换时旋转摄像头的角度 278 | */ 279 | private class DetectScreenOrientation extends OrientationEventListener { 280 | DetectScreenOrientation(Context context) { 281 | super(context); 282 | } 283 | 284 | @Override 285 | public void onOrientationChanged(int orientation) { 286 | if (260 < orientation && orientation < 290) { 287 | setCameraParams(); 288 | } else if (80 < orientation && orientation < 100) { 289 | setCameraParams(); 290 | } 291 | } 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /app/src/main/java/com/cymaybe/foucssurfaceview/fragment/PictureFragment.java: -------------------------------------------------------------------------------- 1 | package com.cymaybe.foucssurfaceview.fragment; 2 | 3 | import android.app.DialogFragment; 4 | import android.graphics.Bitmap; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | 12 | import com.cymaybe.foucssurfaceview.R; 13 | 14 | /** 15 | * Created by moubiao on 2016/12/7. 16 | */ 17 | 18 | public class PictureFragment extends DialogFragment { 19 | public static final String ORIGIN_PICTURE = "originPic"; 20 | public static final String CROP_PICTURE = "cropPic"; 21 | 22 | private Bitmap mOriginPicBitmap, mCropPicBitmap; 23 | 24 | @Override 25 | public void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | Bundle data = getArguments(); 28 | if (data != null) { 29 | mOriginPicBitmap = data.getParcelable(ORIGIN_PICTURE); 30 | mCropPicBitmap = data.getParcelable(CROP_PICTURE); 31 | } 32 | } 33 | 34 | @Nullable 35 | @Override 36 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 37 | return inflater.inflate(R.layout.picture_layout, container, false); 38 | } 39 | 40 | @Override 41 | public void onViewCreated(View view, Bundle savedInstanceState) { 42 | ImageView originImg = (ImageView) view.findViewById(R.id.origin_picture_img); 43 | originImg.setImageBitmap(mOriginPicBitmap); 44 | ImageView cropImg = (ImageView) view.findViewById(R.id.crop_picture_img); 45 | cropImg.setImageBitmap(mCropPicBitmap); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_take_picture_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CGmaybe10/FocusSurfaceView/26d0babfd5b4044e980adbd42c98ee2ffdd6f6ca/app/src/main/res/drawable-xxhdpi/ic_take_picture_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_take_picture_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CGmaybe10/FocusSurfaceView/26d0babfd5b4044e980adbd42c98ee2ffdd6f6ca/app/src/main/res/drawable-xxhdpi/ic_take_picture_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/take_picture_button_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout-land/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 29 | 30 | 37 | 38 | 39 | 40 | 41 | 42 |