Android實現從相簿選擇或者直接拍照來設定圓形的頭像CircleImageView
本人第一次寫技術部落格,只是為了對自己平時遇到的一些問題進行一個總結,可以讓以後能更好的翻看學習,也可以讓更多的人借鑑。
廢話不多說,正題開始:
首先先說明如何進行從相簿選擇或者直接拍照來設定頭像,然後在進行圓形頭像的設定。具體的介面效果如下所示:
實現底部彈出的程式碼如下SelectPickPopupWindow.class,需要整合PopupWindow,程式碼:
import android.app.Activity; import android.content.Context; import android.graphics.drawable.ColorDrawable;這個自定義的底部彈窗工具類寫好以後,對應的佈局檔案如下所示:import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.PopupWindow; public class SelectPicPopupWindow extendsPopupWindow { private Button btn_take_photo, btn_pick_photo, btn_cancel; private View mMenuView; public SelectPicPopupWindow(Activity context, View.OnClickListener itemsOnClick) { super(context); LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); mMenuView = inflater.inflate(R.layout.activity_select_pic_popup_window, null); btn_take_photo = (Button) mMenuView.findViewById(R.id.btn_take_photo); btn_pick_photo = (Button) mMenuView.findViewById(R.id.btn_pick_photo); btn_cancel = (Button) mMenuView.findViewById(R.id.btn_cancel); btn_cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dismiss(); } }); btn_pick_photo.setOnClickListener(itemsOnClick); btn_take_photo.setOnClickListener(itemsOnClick); //設定SelectPicPopupWindow的View this.setContentView(mMenuView); //設定SelectPicPopupWindow彈出窗體的寬 this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT); //設定SelectPicPopupWindow彈出窗體的高 this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); //設定SelectPicPopupWindow彈出窗體可點選 this.setFocusable(true); //設定SelectPicPopupWindow彈出窗體動畫效果 this.setAnimationStyle(R.style.AnimBottom); //例項化一個ColorDrawable顏色為半透明 ColorDrawable dw = new ColorDrawable(0000000000); //設定SelectPicPopupWindow彈出窗體的背景 this.setBackgroundDrawable(dw); //mMenuView新增OnTouchListener監聽判斷獲取觸屏位置如果在選擇框外面則銷燬彈出框 mMenuView.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { int height = mMenuView.findViewById(R.id.pop_layout).getTop(); int y = (int) event.getY(); if (event.getAction() == MotionEvent.ACTION_UP) { if (y < height) { dismiss(); } } return true; } }); } }
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="vertical"> <LinearLayout android:id="@+id/pop_layout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="#343434" android:gravity="center_horizontal" android:orientation="vertical"> <Button android:id="@+id/btn_take_photo" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="20dip" android:layout_marginRight="20dip" android:layout_marginTop="20dip" android:background="#8e8e8e" android:text="拍照" android:textStyle="bold" /> <Button android:id="@+id/btn_pick_photo" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="20dip" android:layout_marginRight="20dip" android:layout_marginTop="5dip" android:background="#8e8e8e" android:text="從相簿選擇" android:textStyle="bold" /> <Button android:id="@+id/btn_cancel" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="15dip" android:layout_marginLeft="20dip" android:layout_marginRight="20dip" android:layout_marginTop="15dip" android:background="#8e8e8e" android:text="取消" android:textColor="#ffffff" android:textStyle="bold" /> </LinearLayout> </RelativeLayout>
這個底部的彈窗結束以後,在需要進行底部彈窗的地方進行呼叫就可以了。我這邊實現的關鍵程式碼如下所示:
//自定義的彈出框類 SelectPicPopupWindow menuWindow;先進行宣告,然後在點選編輯按鈕的時候呼叫,點選的監聽程式碼如下:
case R.id.img_edit: //例項化SelectPicPopupWindow menuWindow = new SelectPicPopupWindow(MyInfoActivity.this, itemsOnClick); //顯示視窗 //設定layout在PopupWindow中顯示的位置 menuWindow.showAtLocation(MyInfoActivity.this.findViewById(R.id.rela_my_info), Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0); break;
這樣就實現了點選頭像編輯,底部彈出彈窗的效果。
然後我們對這個彈窗的按鈕進行監聽來進行照片的選擇以及拍照等功能的操作。
import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; import android.net.Uri; import android.os.Environment; import android.provider.MediaStore; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; import android.view.Gravity; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast;import com.kegoal.view.SelectPicPopupWindow; import java.io.File; public class MyInfoActivity extends AppCompatActivity implements View.OnClickListener { private ImageView my_img, img_edit; //自定義的彈出框類 SelectPicPopupWindow menuWindow; /* 頭像檔案 */ private static final String IMAGE_FILE_NAME = "temp_head_image.jpg"; /* 請求識別碼 */ private static final int CODE_GALLERY_REQUEST = 0xa0; private static final int CODE_CAMERA_REQUEST = 0xa1; private static final int CODE_RESULT_REQUEST = 0xa2; // 裁剪後圖片的寬(X)和高(Y),100 X 100的正方形。 private static int output_X = 100; private static int output_Y = 100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_info);
//獲取資源init()方法,自己定義。 init(); } //為底部彈出的視窗進行按鈕的監聽。 private View.OnClickListener itemsOnClick = new View.OnClickListener() { public void onClick(View v) { menuWindow.dismiss(); switch (v.getId()) { //通過拍照獲取照片 case R.id.btn_take_photo: choseHeadImageFromCameraCapture(); break; //從相簿獲取照片 case R.id.btn_pick_photo: choseHeadImageFromGallery(); break; default: break; } } }; // 從本地相簿選取圖片作為頭像 private void choseHeadImageFromGallery() { Intent intentFromGallery = new Intent(); // 設定檔案型別 intentFromGallery.setType("image/*"); intentFromGallery.setAction(Intent.ACTION_PICK); startActivityForResult(intentFromGallery, CODE_GALLERY_REQUEST); } // 啟動手機相機拍攝照片作為頭像 private void choseHeadImageFromCameraCapture() { Intent intentFromCapture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 判斷儲存卡是否可用,儲存照片檔案 if (hasSdcard()) { intentFromCapture.putExtra(MediaStore.EXTRA_OUTPUT, Uri .fromFile(new File(Environment .getExternalStorageDirectory(), IMAGE_FILE_NAME))); } startActivityForResult(intentFromCapture, CODE_CAMERA_REQUEST); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { // 使用者沒有進行有效的設定操作,返回 if (resultCode == RESULT_CANCELED) { // Toast.makeText(getApplication(), "取消", Toast.LENGTH_LONG).show(); return; } switch (requestCode) { case CODE_GALLERY_REQUEST: cropRawPhoto(intent.getData()); break; case CODE_CAMERA_REQUEST: if (hasSdcard()) { File tempFile = new File( Environment.getExternalStorageDirectory(), IMAGE_FILE_NAME); cropRawPhoto(Uri.fromFile(tempFile)); } else { Toast.makeText(getApplication(), "沒有SDCard!", Toast.LENGTH_LONG) .show(); } break; case CODE_RESULT_REQUEST: if (intent != null) { setImageToHeadView(intent); } break; } super.onActivityResult(requestCode, resultCode, intent); } /** * 裁剪原始的圖片 */ public void cropRawPhoto(Uri 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", output_X); intent.putExtra("outputY", output_Y); intent.putExtra("return-data", true); startActivityForResult(intent, CODE_RESULT_REQUEST); } /** * 提取儲存裁剪之後的圖片資料,並設定頭像部分的View */ private void setImageToHeadView(Intent intent) { Bundle extras = intent.getExtras(); if (extras != null) { Bitmap photo = extras.getParcelable("data"); my_img.setImageBitmap(photo); } } /** * 檢查裝置是否存在SDCard的工具方法 */ public static boolean hasSdcard() { String state = Environment.getExternalStorageState(); if (state.equals(Environment.MEDIA_MOUNTED)) { // 有儲存的SDCard return true; } else { return false; } } }
此時,我們就實現了對頭像的選擇方式的實現,my_edit的imageview是我們的頭像所對應的控制元件,而img_edit這個控制元件則是我們的編輯頭像的按鈕。
最後的一步也就是實現我們的頭像是圓形的操作。只需要將我們的imageview進行自定義成圓形的就行了,這樣不管你裡面放的什麼樣的圖片,都會顯示圓形的。不過不能設定能background,我們要利用src來進行對imageview的替換。具體實現程式碼如下所示:
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.widget.ImageView;/** * Created by Administrator on 2016/7/11 0011. */ public class CircleImageView extends ImageView { private static final ImageView.ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; private static final int COLORDRAWABLE_DIMENSION = 1; private static final int DEFAULT_BORDER_WIDTH = 0; private static final int DEFAULT_BORDER_COLOR = Color.BLACK; private final RectF mDrawableRect = new RectF(); private final RectF mBorderRect = new RectF(); private final Matrix mShaderMatrix = new Matrix(); private final Paint mBitmapPaint = new Paint(); private final Paint mBorderPaint = new Paint(); private int mBorderColor = DEFAULT_BORDER_COLOR; private int mBorderWidth = DEFAULT_BORDER_WIDTH; private Bitmap mBitmap; private BitmapShader mBitmapShader; private int mBitmapWidth; private int mBitmapHeight; private float mDrawableRadius; private float mBorderRadius; private boolean mReady; private boolean mSetupPending; public CircleImageView(Context context) { super(context); } public CircleImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CircleImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); super.setScaleType(SCALE_TYPE); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0); mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH); mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, DEFAULT_BORDER_COLOR); a.recycle(); mReady = true; if (mSetupPending) { setup(); mSetupPending = false; } } @Override public ScaleType getScaleType() { return SCALE_TYPE; } @Override public void setScaleType(ScaleType scaleType) { if (scaleType != SCALE_TYPE) { throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType)); } } @Override protected void onDraw(Canvas canvas) { if (getDrawable() == null) { return; } canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, mBitmapPaint); canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, mBorderPaint); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); setup(); } public int getBorderColor() { return mBorderColor; } public void setBorderColor(int borderColor) { if (borderColor == mBorderColor) { return; } mBorderColor = borderColor; mBorderPaint.setColor(mBorderColor); invalidate(); } public int getBorderWidth() { return mBorderWidth; } public void setBorderWidth(int borderWidth) { if (borderWidth == mBorderWidth) { return; } mBorderWidth = borderWidth; setup(); } @Override public void setImageBitmap(Bitmap bm) { super.setImageBitmap(bm); mBitmap = bm; setup(); } @Override public void setImageDrawable(Drawable drawable) { super.setImageDrawable(drawable); mBitmap = getBitmapFromDrawable(drawable); setup(); } @Override public void setImageResource(int resId) { super.setImageResource(resId); mBitmap = getBitmapFromDrawable(getDrawable()); setup(); } private Bitmap getBitmapFromDrawable(Drawable drawable) { if (drawable == null) { return null; } if (drawable instanceof BitmapDrawable) { return ((BitmapDrawable) drawable).getBitmap(); } try { Bitmap bitmap; if (drawable instanceof ColorDrawable) { bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG); } else { bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG); } Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); drawable.draw(canvas); return bitmap; } catch (OutOfMemoryError e) { return null; } } private void setup() { if (!mReady) { mSetupPending = true; return; } if (mBitmap == null) { return; } mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); mBitmapPaint.setAntiAlias(true); mBitmapPaint.setShader(mBitmapShader); mBorderPaint.setStyle(Paint.Style.STROKE); mBorderPaint.setAntiAlias(true); mBorderPaint.setColor(mBorderColor); mBorderPaint.setStrokeWidth(mBorderWidth); mBitmapHeight = mBitmap.getHeight(); mBitmapWidth = mBitmap.getWidth(); mBorderRect.set(0, 0, getWidth(), getHeight()); mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2); mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth); mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2); updateShaderMatrix(); invalidate(); } private void updateShaderMatrix() { float scale; float dx = 0; float dy = 0; mShaderMatrix.set(null); if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) { scale = mDrawableRect.height() / (float) mBitmapHeight; dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f; } else { scale = mDrawableRect.width() / (float) mBitmapWidth; dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f; } mShaderMatrix.setScale(scale, scale); mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth); mBitmapShader.setLocalMatrix(mShaderMatrix); } }這是圓形的imageview的工具類。
然後需要在values/attrs.xml中寫入以下程式碼:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CircleImageView"> <attr name="border_width" format="dimension" /> <attr name="border_color" format="color" /> </declare-styleable> </resources>最後,就可以在我們需要用到的imageview的地方進行使用,具體程式碼如下:
<com.view.CircleImageView android:id="@+id/my_img" android:layout_width="130dp" android:layout_height="130dp" android:layout_centerHorizontal="true" android:src="@mipmap/head" />
這些都是自己在編寫專案的過程中的一些總結,有很多地方不能直接進行抄寫,只是提供一個思路讓大家參考下,主要還是自己記錄,有不足之處還望包含。
如有轉載,請表明出處。謝謝。
相關推薦
Android實現從相簿選擇或者直接拍照來設定圓形的頭像CircleImageView
本人第一次寫技術部落格,只是為了對自己平時遇到的一些問題進行一個總結,可以讓以後能更好的翻看學習,也可以讓更多的人借鑑。 廢話不多說,正題開始: 首先先說明如何進行從相簿選擇或者直接拍照來設定頭像,然後在進行圓形頭像的設定。具體的介面效果如下所示:
Android相簿選擇或者直接拍照來設定圓形的頭像CircleImageView
實現底部彈出的程式碼如下SelectPickPopupWindow.class,需要整合PopupWindow,程式碼 import android.app.Activity; import android.content.Context; import android.g
android從相簿選擇圖片和拍照選擇圖片
在android開發中選擇圖片的方式大致可以分類兩種,一種是從手機相簿獲取,另外一種則是通過呼叫手機拍照獲得 手機相簿中獲取,這種方式需要讀取儲存卡的許可權 <uses-permission android:name="android.permission.REA
iOS 修改頭像,幾行程式碼實現從相簿選擇照片
我的GitHub:點選開啟連結 SelectPhotoManager.h #import <Foundation/Foundation.h> #import <UIKi
ionic3 實現拍照與從相簿選擇功能
參考了很多網上的資料,但是每個人遇到的問題都不一樣,我這裡出現的問題,可能是node版本,還有外掛版本之類的問題,問題以及解決方式可以看這個圖。 一、外掛依賴引入 (1)配置相機 在控制行輸入命令: ionic cordova plugin add cordova-
呼叫Android系統攝像頭進行拍照以及從相簿選擇圖片
很多時候我們需要呼叫系統攝像頭進行拍照或者從相簿選擇照片,然後對得到的圖片進行一些處理。比如微信設定頭像,就可以選擇呼叫裝置存在攝像頭APP進行拍照,然後對影象進行裁剪,最終設定為頭像。 下面來進行講解。 主要分為以下幾個部分: 1、獲得攝像頭Feature和寫檔案的許
Android頭像上傳/拍照/從相簿選擇Demo(個人資訊模組會用到)
個人資訊中一般都會帶有頭像設定功能,本Demo是從我專案中拿出來的,在做個模組時遇到了許多問題,最後百度一一堅決了,雖不說是最好的,但也能應付基本功能了。 也許新手會遇到一個問題,在其它手機均沒問題,但在小米3手機就是不行,後來發現利用繫結URI傳遞資料可以擷取很大的圖,
拍照上傳,從相簿選擇上傳
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <link href="css/mui.mi
Android 二維碼生成,掃描,近距離識別優化,從相簿選擇二維碼識別
做了一個二維碼掃描圖片,主要是掃描不出來,看到一篇部落格,其中的第二種方法可以掃描到,在此做筆記,以備後用,前面的進入相簿,返回,到獲取圖片路徑方法都一樣; (1):二維碼生成的方法順便貼上: private Bitmap createQRImage(String url, final
ionic拍照,從相簿選擇功能
在介紹外掛的使用之前,我們有必要先大致瞭解下外掛的原理 一、外掛工作原理分析 一個外掛是如何正確地在IONIC框架下執行的呢? 前臺的HTML/js程式碼又是如何與後面具體平臺做資料互動的呢? 這個就需要對外掛的工作原理及各個模組之間的流程關係有一個基本的瞭解。 為了讓外掛能夠訪問具體平臺系統的程式碼,Cor
Android實現本地圖片選擇及預覽縮放效果仿春雨醫生
在做專案時經常會遇到選擇本地圖片的需求,以前都是懶得寫直接呼叫系統方法來選擇圖片,但是這樣並不能實現多選效果,最近又遇到了,所以還是寫一個demo好了,以後也方便使用。還是首先來看看效果 顯示的圖片使用RecyclerView實現的,利用Glide來載入;下面彈出的圖片資料夾效果是採用
Android實現呼叫攝像頭,選擇本地照片的功能
首先我們看佈局程式碼的檔案: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:
Android實現從底部彈出Dialog(和PopWindow實現的效果一樣)
上菜,不,上圖: 相信上圖的效果,大家在android 裝置中經常碰到.有時候進行分享操作的時候-----要求從從底部自下而上彈出.上圖中的效果**既可以通過自定義Dialog實現也可以通過自定義PopWindow來實現.**關於popWindow
Android開發從相簿中選取照片
最近專案在做一個功能:就是需要從使用者選擇頭像跳轉到相簿選擇圖片,這應該是一個很簡單的需求,但是在網上搜了一下有好多都講的很亂,其實用幾十行程式碼就可以實現的為什麼要說的那麼複雜呢,下面就簡單說一下嘍。 下面說兩種方法分別是直接選擇相簿返回,另外一種為選擇相簿之
從相簿選擇圖片回傳
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="htt
Android實現銀行卡詳情選擇佈局
大家好,這兩天正好沒什麼事情做然後有朋友問我一個佈局的問題,效果是這樣的: 然後主要用到的是下面幾點 - addView() 動態往佈局裡面新增控制元件或者佈局 - 當一行滿了之後自動換行到下一行 - 根據服務端返回的json資料進行填充,並且實現單
Android 呼叫系統相簿選擇圖片並顯示
主要程式碼: package wkk.app2; import android.app.Activity; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; imp
android實現從一個activity跳轉到另一個activity中
<pre name="code" class="java"> </pre><pre class="java" name="code"><span style="font-size:18px;">要實現從1個activity跳到
從相簿選擇圖片後儲存到本地
#import <Photos/Photos.h> NSURL *assetURL = info[UIImagePickerControllerReferenceURL]; PHFetchResult *assets = [PHAsset fet
Android實現從底部彈出的Dialog
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xml