Android App開發常用功能之使用者頭像選擇
阿新 • • 發佈:2019-02-03
前言
現在的APP基本都有個人資料的填寫,基本的都有頭像的選擇,支援拍照和從本地相簿選擇,剪下圓形頭像的功能,現在用個小demo實現以下。
下面看一下效果圖
上程式碼:
主介面程式碼
package com.example.androidpersonal_icon; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.widget.ImageView; import java.io.File; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; public class MainActivity extends Activity { protected static final int CHOOSE_PICTURE = 0; protected static final int TAKE_PICTURE = 1; private static final int CROP_SMALL_PICTURE = 2; protected static Uri tempUri; private ImageView iv_personal_icon; private SelectPicPopupWindow menuWindow; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 新建一個用來儲存照片的資料夾 File destDir = new File(Environment.getExternalStorageDirectory() + "/AndroidPersonal_icon"); if (!destDir.exists()) { destDir.mkdirs(); } iv_personal_icon = (ImageView) findViewById(R.id.iv_personal_icon); iv_personal_icon.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 例項化SelectPicPopupWindow menuWindow = new SelectPicPopupWindow(MainActivity.this, itemsOnClick); // 顯示視窗 menuWindow.showAtLocation(MainActivity.this.findViewById(R.id.main), Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0); // 設定layout在PopupWindow中顯示的位置 } }); // 讀取上一次剪下的照片 if (destDir.exists() && destDir.isDirectory()) { if (destDir.list().length > 0) { Log.d("111111111112", destDir.toString() + "/image_icon.png"); Bitmap bitmap = BitmapFactory.decodeFile(destDir.toString() + "/image_icon.png"); iv_personal_icon.setImageBitmap(bitmap); } else { iv_personal_icon.setBackgroundResource(R.drawable.default_personal_image); } } } // 為彈出視窗實現監聽類 private OnClickListener itemsOnClick = new OnClickListener() { public void onClick(View v) { menuWindow.dismiss(); switch (v.getId()) { case R.id.Layout_take_photo: Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); tempUri = Uri.fromFile( new File(Environment.getExternalStorageDirectory() + "/AndroidPersonal_icon", "image.jpg")); Log.d("11111111", tempUri.toString()); // 指定照片儲存路徑(SD卡),image.jpg為一個臨時檔案,每次拍照後這個圖片都會被替換 openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, tempUri); startActivityForResult(openCameraIntent, TAKE_PICTURE); break; case R.id.Layout_pick_photo: Intent openAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT); openAlbumIntent.setType("image/*"); startActivityForResult(openAlbumIntent, CHOOSE_PICTURE); break; default: break; } } }; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { // 如果返回碼是可以用的 switch (requestCode) { case TAKE_PICTURE: startPhotoZoom(tempUri); // 開始對圖片進行裁剪處理 break; case CHOOSE_PICTURE: startPhotoZoom(data.getData()); // 開始對圖片進行裁剪處理 break; case CROP_SMALL_PICTURE: if (data != null) { setImageToView(data); // 讓剛才選擇裁剪得到的圖片顯示在介面上 } break; } } } /** * 裁剪圖片方法實現 * * @param uri */ protected void startPhotoZoom(Uri uri) { if (uri == null) { Log.i("tag", "The uri is not exist."); } tempUri = uri; Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, "image/*"); // 設定裁剪 intent.putExtra("crop", "true"); // aspectX aspectY 是寬高的比例 intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); // outputX outputY 是裁剪圖片寬高 intent.putExtra("outputX", 150); intent.putExtra("outputY", 150); intent.putExtra("return-data", true); startActivityForResult(intent, CROP_SMALL_PICTURE); } /** * 儲存裁剪之後的圖片資料 * * @param * * @param picdata */ protected void setImageToView(Intent data) { Bundle extras = data.getExtras(); if (extras != null) { Bitmap photo = extras.getParcelable("data"); photo = Utils.toRoundBitmap(photo, tempUri); // 這個時候的圖片已經被處理成圓形的了 iv_personal_icon.setImageBitmap(photo); uploadPic(photo); } } private void uploadPic(Bitmap bitmap) { // 上傳至伺服器 // ... 可以在這裡把Bitmap轉換成file,然後得到file的url,做檔案上傳操作 // 注意這裡得到的圖片已經是圓形圖片了 // bitmap是沒有做個圓形處理的,但已經被裁剪了 String imagePath = Utils.savePhoto(bitmap, Environment.getExternalStorageDirectory().getAbsolutePath() + "/AndroidPersonal_icon", "image_icon"); Log.d("imagePath", imagePath + ""); if (imagePath != null) { // 拿著imagePath上傳了 // ... } } }
圓形頭像剪下程式碼:
package com.example.androidpersonal_icon; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.net.Uri; import android.util.Log; public class Utils { /** * Save image to the SD card * * @param photoBitmap * @param photoName * @param path */ public static String savePhoto(Bitmap photoBitmap, String path, String photoName) { String localPath = null; if (android.os.Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED)) { File dir = new File(path); if (!dir.exists()) { dir.mkdirs(); } File photoFile = new File(path, photoName + ".png"); FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(photoFile); if (photoBitmap != null) { if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) { // 轉換完成 localPath = photoFile.getPath(); fileOutputStream.flush(); } } } catch (FileNotFoundException e) { photoFile.delete(); localPath = null; e.printStackTrace(); } catch (IOException e) { photoFile.delete(); localPath = null; e.printStackTrace(); } finally { try { if (fileOutputStream != null) { fileOutputStream.close(); fileOutputStream = null; } } catch (IOException e) { e.printStackTrace(); } } } return localPath; } /** * 轉換圖片成圓形 * * @param bitmap * 傳入Bitmap物件 * @param tempUri * @return */ public static Bitmap toRoundBitmap(Bitmap bitmap, Uri tempUri) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); float roundPx; float left, top, right, bottom, dst_left, dst_top, dst_right, dst_bottom; if (width <= height) { roundPx = width / 2; left = 0; top = 0; right = width; bottom = width; height = width; dst_left = 0; dst_top = 0; dst_right = width; dst_bottom = width; } else { roundPx = height / 2; float clip = (width - height) / 2; left = clip; right = width - clip; top = 0; bottom = height; width = height; dst_left = 0; dst_top = 0; dst_right = height; dst_bottom = height; } Bitmap output = Bitmap.createBitmap(width, height, Config.ARGB_8888); Canvas canvas = new Canvas(output); final int color = 0xff424242; final Paint paint = new Paint(); final Rect src = new Rect((int) left, (int) top, (int) right, (int) bottom); final Rect dst = new Rect((int) dst_left, (int) dst_top, (int) dst_right, (int) dst_bottom); final RectF rectF = new RectF(dst); paint.setAntiAlias(true);// 設定畫筆無鋸齒 canvas.drawARGB(0, 0, 0, 0); // 填充整個Canvas paint.setColor(color); // 以下有兩種方法畫圓,drawRounRect和drawCircle // canvas.drawRoundRect(rectF, roundPx, roundPx, paint);// // 畫圓角矩形,第一個引數為圖形顯示區域,第二個引數和第三個引數分別是水平圓角半徑和垂直圓角半徑。 canvas.drawCircle(roundPx, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));// 設定兩張圖片相交時的模式,參考http://trylovecatch.iteye.com/blog/1189452 canvas.drawBitmap(bitmap, src, dst, paint); // 以Mode.SRC_IN模式合併bitmap和已經draw了的Circle return output; } }
ok,大功告成,最後別忘了在清單檔案中新增讀寫sd可許可權,不然得不到imagePath
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />