編輯:關於Android編程
1 public class ReferenceLine extends View { 2 3 private Paint mLinePaint; 4 5 public ReferenceLine(Context context) { 6 super(context); 7 init(); 8 } 9 10 public ReferenceLine(Context context, AttributeSet attrs) { 11 super(context, attrs); 12 init(); 13 } 14 15 public ReferenceLine(Context context, AttributeSet attrs, int defStyleAttr) { 16 super(context, attrs, defStyleAttr); 17 init(); 18 } 19 20 private void init() { 21 mLinePaint = new Paint(); 22 mLinePaint.setAntiAlias(true); 23 mLinePaint.setColor(Color.parseColor("#45e0e0e0")); 24 mLinePaint.setStrokeWidth(1); 25 } 26 27 28 29 @Override 30 protected void onDraw(Canvas canvas) { 31 int screenWidth = Utils.getScreenWH(getContext()).widthPixels; 32 int screenHeight = Utils.getScreenWH(getContext()).heightPixels; 33 34 int width = screenWidth/3; 35 int height = screenHeight/3; 36 37 for (int i = width, j = 0;i < screenWidth && j<2;i += width, j++) { 38 canvas.drawLine(i, 0, i, screenHeight, mLinePaint); 39 } 40 for (int j = height,i = 0;j < screenHeight && i < 2;j += height,i++) { 41 canvas.drawLine(0, j, screenWidth, j, mLinePaint); 42 } 43 } 44 45 46 }
2、自定義相機代碼 這裡主要是要創建一個SurfaceView,將攝像頭的預覽界面放到SurfaceView中顯示。
1 package com.bbk.lling.camerademo.camare; 2 3 import android.content.Context; 4 import android.content.res.Configuration; 5 import android.graphics.PixelFormat; 6 import android.graphics.Rect; 7 import android.hardware.Camera; 8 import android.hardware.Camera.AutoFocusCallback; 9 import android.hardware.Camera.PictureCallback; 10 import android.util.AttributeSet; 11 import android.util.Log; 12 import android.view.MotionEvent; 13 import android.view.SurfaceHolder; 14 import android.view.SurfaceView; 15 import android.view.View; 16 import android.widget.RelativeLayout; 17 import android.widget.Toast; 18 19 import com.bbk.lling.camerademo.utils.Utils; 20 21 import java.io.IOException; 22 import java.util.ArrayList; 23 import java.util.Date; 24 import java.util.List; 25 26 /** 27 * @Class: CameraPreview 28 * @Description: 自定義相機 29 * @author: lling(www.cnblogs.com/liuling) 30 * @Date: 2015/10/25 31 */ 32 public class CameraPreview extends SurfaceView implements 33 SurfaceHolder.Callback, AutoFocusCallback { 34 private static final String TAG = "CameraPreview"; 35 36 private int viewWidth = 0; 37 private int viewHeight = 0; 38 39 /** 監聽接口 */ 40 private OnCameraStatusListener listener; 41 42 private SurfaceHolder holder; 43 private Camera camera; 44 private FocusView mFocusView; 45 46 //創建一個PictureCallback對象,並實現其中的onPictureTaken方法 47 private PictureCallback pictureCallback = new PictureCallback() { 48 49 // 該方法用於處理拍攝後的照片數據 50 @Override 51 public void onPictureTaken(byte[] data, Camera camera) { 52 // 停止照片拍攝 53 try { 54 camera.stopPreview(); 55 } catch (Exception e) { 56 } 57 // 調用結束事件 58 if (null != listener) { 59 listener.onCameraStopped(data); 60 } 61 } 62 }; 63 64 // Preview類的構造方法 65 public CameraPreview(Context context, AttributeSet attrs) { 66 super(context, attrs); 67 // 獲得SurfaceHolder對象 68 holder = getHolder(); 69 // 指定用於捕捉拍照事件的SurfaceHolder.Callback對象 70 holder.addCallback(this); 71 // 設置SurfaceHolder對象的類型 72 holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 73 setOnTouchListener(onTouchListener); 74 } 75 76 // 在surface創建時激發 77 public void surfaceCreated(SurfaceHolder holder) { 78 Log.e(TAG, "==surfaceCreated=="); 79 if(!Utils.checkCameraHardware(getContext())) { 80 Toast.makeText(getContext(), "攝像頭打開失敗!", Toast.LENGTH_SHORT).show(); 81 return; 82 } 83 // 獲得Camera對象 84 camera = getCameraInstance(); 85 try { 86 // 設置用於顯示拍照攝像的SurfaceHolder對象 87 camera.setPreviewDisplay(holder); 88 } catch (IOException e) { 89 e.printStackTrace(); 90 // 釋放手機攝像頭 91 camera.release(); 92 camera = null; 93 } 94 updateCameraParameters(); 95 if (camera != null) { 96 camera.startPreview(); 97 } 98 setFocus(); 99 } 100 101 // 在surface銷毀時激發 102 public void surfaceDestroyed(SurfaceHolder holder) { 103 Log.e(TAG, "==surfaceDestroyed=="); 104 // 釋放手機攝像頭 105 camera.release(); 106 camera = null; 107 } 108 109 // 在surface的大小發生改變時激發 110 public void surfaceChanged(final SurfaceHolder holder, int format, int w, 111 int h) { 112 // stop preview before making changes 113 try { 114 camera.stopPreview(); 115 } catch (Exception e){ 116 // ignore: tried to stop a non-existent preview 117 } 118 // set preview size and make any resize, rotate or 119 // reformatting changes here 120 updateCameraParameters(); 121 // start preview with new settings 122 try { 123 camera.setPreviewDisplay(holder); 124 camera.startPreview(); 125 126 } catch (Exception e){ 127 Log.d(TAG, "Error starting camera preview: " + e.getMessage()); 128 } 129 setFocus(); 130 } 131 132 /** 133 * 點擊顯示焦點區域 134 */ 135 OnTouchListener onTouchListener = new OnTouchListener() { 136 @SuppressWarnings("deprecation") 137 @Override 138 public boolean onTouch(View v, MotionEvent event) { 139 if (event.getAction() == MotionEvent.ACTION_DOWN) { 140 int width = mFocusView.getWidth(); 141 int height = mFocusView.getHeight(); 142 mFocusView.setX(event.getX() - (width / 2)); 143 mFocusView.setY(event.getY() - (height / 2)); 144 mFocusView.beginFocus(); 145 } else if (event.getAction() == MotionEvent.ACTION_UP) { 146 focusOnTouch(event); 147 } 148 return true; 149 } 150 }; 151 152 /** 153 * 獲取攝像頭實例 154 * @return 155 */ 156 private Camera getCameraInstance() { 157 Camera c = null; 158 try { 159 int cameraCount = 0; 160 Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); 161 cameraCount = Camera.getNumberOfCameras(); // get cameras number 162 163 for (int camIdx = 0; camIdx < cameraCount; camIdx++) { 164 Camera.getCameraInfo(camIdx, cameraInfo); // get camerainfo 165 // 代表攝像頭的方位,目前有定義值兩個分別為CAMERA_FACING_FRONT前置和CAMERA_FACING_BACK後置 166 if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { 167 try { 168 c = Camera.open(camIdx); //打開後置攝像頭 169 } catch (RuntimeException e) { 170 Toast.makeText(getContext(), "攝像頭打開失敗!", Toast.LENGTH_SHORT).show(); 171 } 172 } 173 } 174 if (c == null) { 175 c = Camera.open(0); // attempt to get a Camera instance 176 } 177 } catch (Exception e) { 178 Toast.makeText(getContext(), "攝像頭打開失敗!", Toast.LENGTH_SHORT).show(); 179 } 180 return c; 181 } 182 183 private void updateCameraParameters() { 184 if (camera != null) { 185 Camera.Parameters p = camera.getParameters(); 186 187 setParameters(p); 188 189 try { 190 camera.setParameters(p); 191 } catch (Exception e) { 192 Camera.Size previewSize = findBestPreviewSize(p); 193 p.setPreviewSize(previewSize.width, previewSize.height); 194 p.setPictureSize(previewSize.width, previewSize.height); 195 camera.setParameters(p); 196 } 197 } 198 } 199 200 /** 201 * @param p 202 */ 203 private void setParameters(Camera.Parameters p) { 204 List<String> focusModes = p.getSupportedFocusModes(); 205 if (focusModes 206 .contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { 207 p.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); 208 } 209 210 long time = new Date().getTime(); 211 p.setGpsTimestamp(time); 212 // 設置照片格式 213 p.setPictureFormat(PixelFormat.JPEG); 214 Camera.Size previewSize = findPreviewSizeByScreen(p); 215 p.setPreviewSize(previewSize.width, previewSize.height); 216 p.setPictureSize(previewSize.width, previewSize.height); 217 p.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); 218 if (getContext().getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) { 219 camera.setDisplayOrientation(90); 220 p.setRotation(90); 221 } 222 } 223 224 // 進行拍照,並將拍攝的照片傳入PictureCallback接口的onPictureTaken方法 225 public void takePicture() { 226 if (camera != null) { 227 try { 228 camera.takePicture(null, null, pictureCallback); 229 } catch (Exception e) { 230 e.printStackTrace(); 231 } 232 } 233 } 234 235 // 設置監聽事件 236 public void setOnCameraStatusListener(OnCameraStatusListener listener) { 237 this.listener = listener; 238 } 239 240 @Override 241 public void onAutoFocus(boolean success, Camera camera) { 242 243 } 244 245 public void start() { 246 if (camera != null) { 247 camera.startPreview(); 248 } 249 } 250 251 public void stop() { 252 if (camera != null) { 253 camera.stopPreview(); 254 } 255 } 256 257 /** 258 * 相機拍照監聽接口 259 */ 260 public interface OnCameraStatusListener { 261 // 相機拍照結束事件 262 void onCameraStopped(byte[] data); 263 } 264 265 @Override 266 protected void onMeasure(int widthSpec, int heightSpec) { 267 viewWidth = MeasureSpec.getSize(widthSpec); 268 viewHeight = MeasureSpec.getSize(heightSpec); 269 super.onMeasure( 270 MeasureSpec.makeMeasureSpec(viewWidth, MeasureSpec.EXACTLY), 271 MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY)); 272 } 273 274 /** 275 * 將預覽大小設置為屏幕大小 276 * @param parameters 277 * @return 278 */ 279 private Camera.Size findPreviewSizeByScreen(Camera.Parameters parameters) { 280 if (viewWidth != 0 && viewHeight != 0) { 281 return camera.new Size(Math.max(viewWidth, viewHeight), 282 Math.min(viewWidth, viewHeight)); 283 } else { 284 return camera.new Size(Utils.getScreenWH(getContext()).heightPixels, 285 Utils.getScreenWH(getContext()).widthPixels); 286 } 287 } 288 289 /** 290 * 找到最合適的顯示分辨率 (防止預覽圖像變形) 291 * @param parameters 292 * @return 293 */ 294 private Camera.Size findBestPreviewSize(Camera.Parameters parameters) { 295 296 // 系統支持的所有預覽分辨率 297 String previewSizeValueString = null; 298 previewSizeValueString = parameters.get("preview-size-values"); 299 300 if (previewSizeValueString == null) { 301 previewSizeValueString = parameters.get("preview-size-value"); 302 } 303 304 if (previewSizeValueString == null) { // 有些手機例如m9獲取不到支持的預覽大小 就直接返回屏幕大小 305 return camera.new Size(Utils.getScreenWH(getContext()).widthPixels, 306 Utils.getScreenWH(getContext()).heightPixels); 307 } 308 float bestX = 0; 309 float bestY = 0; 310 311 float tmpRadio = 0; 312 float viewRadio = 0; 313 314 if (viewWidth != 0 && viewHeight != 0) { 315 viewRadio = Math.min((float) viewWidth, (float) viewHeight) 316 / Math.max((float) viewWidth, (float) viewHeight); 317 } 318 319 String[] COMMA_PATTERN = previewSizeValueString.split(","); 320 for (String prewsizeString : COMMA_PATTERN) { 321 prewsizeString = prewsizeString.trim(); 322 323 int dimPosition = prewsizeString.indexOf('x'); 324 if (dimPosition == -1) { 325 continue; 326 } 327 328 float newX = 0; 329 float newY = 0; 330 331 try { 332 newX = Float.parseFloat(prewsizeString.substring(0, dimPosition)); 333 newY = Float.parseFloat(prewsizeString.substring(dimPosition + 1)); 334 } catch (NumberFormatException e) { 335 continue; 336 } 337 338 float radio = Math.min(newX, newY) / Math.max(newX, newY); 339 if (tmpRadio == 0) { 340 tmpRadio = radio; 341 bestX = newX; 342 bestY = newY; 343 } else if (tmpRadio != 0 && (Math.abs(radio - viewRadio)) < (Math.abs(tmpRadio - viewRadio))) { 344 tmpRadio = radio; 345 bestX = newX; 346 bestY = newY; 347 } 348 } 349 350 if (bestX > 0 && bestY > 0) { 351 return camera.new Size((int) bestX, (int) bestY); 352 } 353 return null; 354 } 355 356 /** 357 * 設置焦點和測光區域 358 * 359 * @param event 360 */ 361 public void focusOnTouch(MotionEvent event) { 362 363 int[] location = new int[2]; 364 RelativeLayout relativeLayout = (RelativeLayout)getParent(); 365 relativeLayout.getLocationOnScreen(location); 366 367 Rect focusRect = Utils.calculateTapArea(mFocusView.getWidth(), 368 mFocusView.getHeight(), 1f, event.getRawX(), event.getRawY(), 369 location[0], location[0] + relativeLayout.getWidth(), location[1], 370 location[1] + relativeLayout.getHeight()); 371 Rect meteringRect = Utils.calculateTapArea(mFocusView.getWidth(), 372 mFocusView.getHeight(), 1.5f, event.getRawX(), event.getRawY(), 373 location[0], location[0] + relativeLayout.getWidth(), location[1], 374 location[1] + relativeLayout.getHeight()); 375 376 Camera.Parameters parameters = camera.getParameters(); 377 parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); 378 379 if (parameters.getMaxNumFocusAreas() > 0) { 380 List<Camera.Area> focusAreas = new ArrayList<Camera.Area>(); 381 focusAreas.add(new Camera.Area(focusRect, 1000)); 382 383 parameters.setFocusAreas(focusAreas); 384 } 385 386 if (parameters.getMaxNumMeteringAreas() > 0) { 387 List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>(); 388 meteringAreas.add(new Camera.Area(meteringRect, 1000)); 389 390 parameters.setMeteringAreas(meteringAreas); 391 } 392 393 try { 394 camera.setParameters(parameters); 395 } catch (Exception e) { 396 } 397 camera.autoFocus(this); 398 } 399 400 /** 401 * 設置聚焦的圖片 402 * @param focusView 403 */ 404 public void setFocusView(FocusView focusView) { 405 this.mFocusView = focusView; 406 } 407 408 /** 409 * 設置自動聚焦,並且聚焦的圈圈顯示在屏幕中間位置 410 */ 411 public void setFocus() { 412 if(!mFocusView.isFocusing()) { 413 try { 414 camera.autoFocus(this); 415 mFocusView.setX((Utils.getWidthInPx(getContext())-mFocusView.getWidth()) / 2); 416 mFocusView.setY((Utils.getHeightInPx(getContext())-mFocusView.getHeight()) / 2); 417 mFocusView.beginFocus(); 418 } catch (Exception e) { 419 } 420 } 421 } 422 423 }
3、Activity中使用自定義相機
1 public class TakePhoteActivity extends Activity implements CameraPreview.OnCameraStatusListener, 2 SensorEventListener { 3 private static final String TAG = "TakePhoteActivity"; 4 public static final Uri IMAGE_URI = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 5 public static final String PATH = Environment.getExternalStorageDirectory() 6 .toString() + "/AndroidMedia/"; 7 CameraPreview mCameraPreview; 8 CropImageView mCropImageView; 9 RelativeLayout mTakePhotoLayout; 10 LinearLayout mCropperLayout; 11 @Override 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 // 設置橫屏 15 // setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 16 // 設置全屏 17 requestWindowFeature(Window.FEATURE_NO_TITLE); 18 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 19 WindowManager.LayoutParams.FLAG_FULLSCREEN); 20 setContentView(R.layout.activity_take_phote); 21 // Initialize components of the app 22 mCropImageView = (CropImageView) findViewById(R.id.CropImageView); 23 mCameraPreview = (CameraPreview) findViewById(R.id.cameraPreview); 24 FocusView focusView = (FocusView) findViewById(R.id.view_focus); 25 mTakePhotoLayout = (RelativeLayout) findViewById(R.id.take_photo_layout); 26 mCropperLayout = (LinearLayout) findViewById(R.id.cropper_layout); 27 28 mCameraPreview.setFocusView(focusView); 29 mCameraPreview.setOnCameraStatusListener(this); 30 mCropImageView.setGuidelines(2); 31 32 mSensorManager = (SensorManager) getSystemService(Context. 33 SENSOR_SERVICE); 34 mAccel = mSensorManager.getDefaultSensor(Sensor. 35 TYPE_ACCELEROMETER); 36 37 } 38 39 boolean isRotated = false; 40 41 @Override 42 protected void onResume() { 43 super.onResume(); 44 if(!isRotated) { 45 TextView hint_tv = (TextView) findViewById(R.id.hint); 46 ObjectAnimator animator = ObjectAnimator.ofFloat(hint_tv, "rotation", 0f, 90f); 47 animator.setStartDelay(800); 48 animator.setDuration(1000); 49 animator.setInterpolator(new LinearInterpolator()); 50 animator.start(); 51 View view = findViewById(R.id.crop_hint); 52 AnimatorSet animSet = new AnimatorSet(); 53 ObjectAnimator animator1 = ObjectAnimator.ofFloat(view, "rotation", 0f, 90f); 54 ObjectAnimator moveIn = ObjectAnimator.ofFloat(view, "translationX", 0f, -50f); 55 animSet.play(animator1).before(moveIn); 56 animSet.setDuration(10); 57 animSet.start(); 58 isRotated = true; 59 } 60 mSensorManager.registerListener(this, mAccel, SensorManager.SENSOR_DELAY_UI); 61 } 62 63 @Override 64 protected void onPause() { 65 super.onPause(); 66 mSensorManager.unregisterListener(this); 67 } 68 69 @Override 70 public void onConfigurationChanged(Configuration newConfig) { 71 Log.e(TAG, "onConfigurationChanged"); 72 super.onConfigurationChanged(newConfig); 73 } 74 75 public void takePhoto(View view) { 76 if(mCameraPreview != null) { 77 mCameraPreview.takePicture(); 78 } 79 } 80 81 public void close(View view) { 82 finish(); 83 } 84 85 /** 86 * 關閉截圖界面 87 * @param view 88 */ 89 public void closeCropper(View view) { 90 showTakePhotoLayout(); 91 } 92 93 /** 94 * 開始截圖,並保存圖片 95 * @param view 96 */ 97 public void startCropper(View view) { 98 //獲取截圖並旋轉90度 99 CropperImage cropperImage = mCropImageView.getCroppedImage(); 100 Log.e(TAG, cropperImage.getX() + "," + cropperImage.getY()); 101 Log.e(TAG, cropperImage.getWidth() + "," + cropperImage.getHeight()); 102 Bitmap bitmap = Utils.rotate(cropperImage.getBitmap(), -90); 103 // Bitmap bitmap = mCropImageView.getCroppedImage(); 104 // 系統時間 105 long dateTaken = System.currentTimeMillis(); 106 // 圖像名稱 107 String filename = DateFormat.format("yyyy-MM-dd kk.mm.ss", dateTaken) 108 .toString() + ".jpg"; 109 Uri uri = insertImage(getContentResolver(), filename, dateTaken, PATH, 110 filename, bitmap, null); 111 cropperImage.getBitmap().recycle(); 112 cropperImage.setBitmap(null); 113 Intent intent = new Intent(this, ShowCropperedActivity.class); 114 intent.setData(uri); 115 intent.putExtra("path", PATH + filename); 116 intent.putExtra("width", bitmap.getWidth()); 117 intent.putExtra("height", bitmap.getHeight()); 118 intent.putExtra("cropperImage", cropperImage); 119 startActivity(intent); 120 bitmap.recycle(); 121 finish(); 122 super.overridePendingTransition(R.anim.fade_in, 123 R.anim.fade_out); 124 // doAnimation(cropperImage); 125 } 126 127 private void doAnimation(CropperImage cropperImage) { 128 ImageView imageView = new ImageView(this); 129 View view = LayoutInflater.from(this).inflate( 130 R.layout.image_view_layout, null); 131 ((RelativeLayout) view.findViewById(R.id.root_layout)).addView(imageView); 132 RelativeLayout relativeLayout = ((RelativeLayout) findViewById(R.id.root_layout)); 133 // relativeLayout.addView(imageView); 134 imageView.setX(cropperImage.getX()); 135 imageView.setY(cropperImage.getY()); 136 ViewGroup.LayoutParams lp = imageView.getLayoutParams(); 137 lp.width = (int)cropperImage.getWidth(); 138 lp.height = (int) cropperImage.getHeight(); 139 imageView.setLayoutParams(lp); 140 imageView.setImageBitmap(cropperImage.getBitmap()); 141 try { 142 getWindow().addContentView(view, lp); 143 } catch (Exception e) { 144 e.printStackTrace(); 145 } 146 /*AnimatorSet animSet = new AnimatorSet(); 147 ObjectAnimator translationX = ObjectAnimator.ofFloat(this, "translationX", cropperImage.getX(), 0); 148 ObjectAnimator translationY = ObjectAnimator.ofFloat(this, "translationY", cropperImage.getY(), 0);*/ 149 150 TranslateAnimation translateAnimation = new TranslateAnimation( 151 0, -cropperImage.getX(), 0, -(Math.abs(cropperImage.getHeight() - cropperImage.getY())));// 當前位置移動到指定位置 152 RotateAnimation rotateAnimation = new RotateAnimation(0, -90, 153 Animation.ABSOLUTE, cropperImage.getX() ,Animation.ABSOLUTE, cropperImage.getY()); 154 AnimationSet animationSet = new AnimationSet(true); 155 animationSet.addAnimation(translateAnimation); 156 animationSet.addAnimation(rotateAnimation); 157 animationSet.setFillAfter(true); 158 animationSet.setDuration(2000L); 159 imageView.startAnimation(animationSet); 160 // finish(); 161 } 162 163 /** 164 * 拍照成功後回調 165 * 存儲圖片並顯示截圖界面 166 * @param data 167 */ 168 @Override 169 public void onCameraStopped(byte[] data) { 170 Log.i("TAG", "==onCameraStopped=="); 171 // 創建圖像 172 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 173 // 系統時間 174 long dateTaken = System.currentTimeMillis(); 175 // 圖像名稱 176 String filename = DateFormat.format("yyyy-MM-dd kk.mm.ss", dateTaken) 177 .toString() + ".jpg"; 178 // 存儲圖像(PATH目錄) 179 Uri source = insertImage(getContentResolver(), filename, dateTaken, PATH, 180 filename, bitmap, data); 181 //准備截圖 182 try { 183 mCropImageView.setImageBitmap(MediaStore.Images.Media.getBitmap(this.getContentResolver(), source)); 184 // mCropImageView.rotateImage(90); 185 } catch (IOException e) { 186 Log.e(TAG, e.getMessage()); 187 } 188 showCropperLayout(); 189 } 190 191 /** 192 * 存儲圖像並將信息添加入媒體數據庫 193 */ 194 private Uri insertImage(ContentResolver cr, String name, long dateTaken, 195 String directory, String filename, Bitmap source, byte[] jpegData) { 196 OutputStream outputStream = null; 197 String filePath = directory + filename; 198 try { 199 File dir = new File(directory); 200 if (!dir.exists()) { 201 dir.mkdirs(); 202 } 203 File file = new File(directory, filename); 204 if (file.createNewFile()) { 205 outputStream = new FileOutputStream(file); 206 if (source != null) { 207 source.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); 208 } else { 209 outputStream.write(jpegData); 210 } 211 } 212 } catch (FileNotFoundException e) { 213 Log.e(TAG, e.getMessage()); 214 return null; 215 } catch (IOException e) { 216 Log.e(TAG, e.getMessage()); 217 return null; 218 } finally { 219 if (outputStream != null) { 220 try { 221 outputStream.close(); 222 } catch (Throwable t) { 223 } 224 } 225 } 226 ContentValues values = new ContentValues(7); 227 values.put(MediaStore.Images.Media.TITLE, name); 228 values.put(MediaStore.Images.Media.DISPLAY_NAME, filename); 229 values.put(MediaStore.Images.Media.DATE_TAKEN, dateTaken); 230 values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); 231 values.put(MediaStore.Images.Media.DATA, filePath); 232 return cr.insert(IMAGE_URI, values); 233 } 234 235 private void showTakePhotoLayout() { 236 mTakePhotoLayout.setVisibility(View.VISIBLE); 237 mCropperLayout.setVisibility(View.GONE); 238 } 239 240 private void showCropperLayout() { 241 mTakePhotoLayout.setVisibility(View.GONE); 242 mCropperLayout.setVisibility(View.VISIBLE); 243 mCameraPreview.start(); //繼續啟動攝像頭 244 } 245 246 247 private float mLastX = 0; 248 private float mLastY = 0; 249 private float mLastZ = 0; 250 private boolean mInitialized = false; 251 private SensorManager mSensorManager; 252 private Sensor mAccel; 253 @Override 254 public void onSensorChanged(SensorEvent event) { 255 256 float x = event.values[0]; 257 float y = event.values[1]; 258 float z = event.values[2]; 259 if (!mInitialized){ 260 mLastX = x; 261 mLastY = y; 262 mLastZ = z; 263 mInitialized = true; 264 } 265 float deltaX = Math.abs(mLastX - x); 266 float deltaY = Math.abs(mLastY - y); 267 float deltaZ = Math.abs(mLastZ - z); 268 269 if(deltaX > 0.8 || deltaY > 0.8 || deltaZ > 0.8){ 270 mCameraPreview.setFocus(); 271 } 272 mLastX = x; 273 mLastY = y; 274 mLastZ = z; 275 } 276 277 @Override 278 public void onAccuracyChanged(Sensor sensor, int accuracy) { 279 } 280 }
actiity中注冊了SensorEventListener,也就是使用傳感器監聽用戶手機的移動,如果有一定距離的移動,則自動聚焦,這樣體驗好一點。 我對比了一下小猿搜題和學霸君兩款app的拍照功能,個人感覺小猿搜題的體驗要好一些,因為從主界面進入拍照界面,連個界面沒有一個旋轉的過渡,而學霸君就有一個過渡,有一絲絲的影響體驗。也就是說學霸君的拍照界面是橫屏的,在activity的onCreate方法裡面調用了setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)來設置全屏,而切換界面的時候又從豎屏切換為橫屏,就會有個過渡的效果,影響了體驗。
今天,我們就來談下android中圖片的變形的特效,在上講博客中我們談到android中圖片中的色彩特效來實現的。改變它的顏色主要通過ColorMatrix類來實現。現在
先看效果圖 如何使用 import java.text.DateFormat; import java.text.ParseException; import jav
相信不少朋友在平常的學習和工作當中都會用到SD存儲卡,雖然它具有是很強大的存儲功能,但同時也是非常脆弱的。一旦SD卡罷工,真是欲哭無淚。那麼到底sd卡壞了怎
進程等待一個進程在終止時會關閉所有的文件描述符,釋放在用戶空間分配出來的內存,但它的PCB還保留著,而且內核中還保存著一些信息,如果是正常終止,則保存著退出狀態,如果是異