Android之圆形头像(实现相机拍摄+相册选择+图片裁剪功能)

Java基础

浏览数:51

2020-6-16

 

转载请标明出处https://my.oschina.net/FlyinTang/blog/751595

最近的一些学习心得

功能实现:点击圆形头像之后可以实现相册上传或者开启相机,然后把得到的图片经过剪裁,把剪裁过的图片设置为头像的背景图

步骤:第一步:自定义一个类,继承ImageView,重写draw方法,实现外观为圆形

第二步:在xml文件中引用该控件

第三步:实现圆形头像的点击事件,点击后显示对话框界面,询问你是打开相册还是相机(自动省略显示对话框的代码)

第四步:根据用户选择情况,打开相册或者相机

第五步:将拍摄的图片或者相册选中的图片进行剪裁,将结果保存在指定内存区域

第六步:更新头像图片

 

具体实现:第一步:自定义一个类,继承ImageView,重写draw方法,实现外观为圆形

//圆形头像类
public class MyRoundPhoto extends ImageView{

	private Paint p;
	private Bitmap bitmap;
	private Context context;
	private int wAndHeight[]=new int[2];
	private File file;
	
	public MyRoundPhoto(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
		
		//获得控件长宽(px)
		wAndHeight = getWidthAndHeight(context,attrs);
		
		this.context = context;
		
        //初始化控件
        init();
		
		

	}

	public MyRoundPhoto(Context context) {
		super(context);
		// TODO Auto-generated constructor stub

        //获得控件长宽(px)
		wAndHeight=getWidthAndHeight(context,attrs);
		
		this.context = context;
		init();
	}

	public MyRoundPhoto(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		//获得控件长宽(px)
		wAndHeight=getWidthAndHeight(context,attrs);
		
		// TODO Auto-generated constructor stub
		this.context = context;
		init();
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);
		canvas.drawBitmap(bitmap, new Matrix(), p);
		
	}
	
	private void init(){
		//从手机存储区域获取图片文件(该位置为手机相册选中的图片经过剪裁后的图片的存储路径)
		file = new File(Environment.getExternalStorageDirectory(),Info.PHOTO_NAME);
		
        //如果图片文件存在,则显示,否则则创建并显示
		if(file.exists()){
			Log.v("文件存在", "是");
			this.bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
		}
		else{
			Log.v("文件不存在", "是");
			
			//生成默认图片的文件
			this.bitmap=BitmapFactory.decodeStream(context.getResources().openRawResource(R.drawable.defalut));
			//person.setPicture()
			FileOutputStream fos=null;
			try {
				fos = new FileOutputStream(file);
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); //压缩
			try {
				fos.flush();
				fos.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
		//将方形的位图转换为圆形的位图
		this.bitmap = toRoundBitmap(this.bitmap);
		p = new Paint();
			
	}
	
	private Bitmap toRoundBitmap(Bitmap map){
		
		
		//int height = map.getHeight()+100;
		int height=convertDIP2PX(context,this.wAndHeight[1]); //位图的高度(px)
		int width = convertDIP2PX(context,this.wAndHeight[0]);//位图的宽度(px)
		
		//创建画布
		Bitmap bit = Bitmap.createBitmap(width, height, Config.ARGB_8888);
		Canvas canvas = new Canvas(bit);
		
		//画笔
		Paint paint = new Paint();
		paint.setAntiAlias(false);
		int r = (width>height)?height:width;
		
		
		
		//绘制圆形
		RectF rectF = new RectF(0,0,r,r);
		canvas.drawRoundRect(rectF, r/2, r/2, paint);
		
		//画头像
		//canvas.drawARGB(0, 0, 0, 0);
		paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
		canvas.drawBitmap(map, null,rectF, paint);
		
		//返回圆形位图
		return bit;
	}
	
    //使当前视图无效,从而使系统重新绘制视图
	public void myValidate(){
		bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
		bitmap=toRoundBitmap(bitmap);
		invalidate();
		
	}
	
    //将dp转换为px
	private static int convertDIP2PX(Context context, int dip) { 
	    float scale = context.getResources().getDisplayMetrics().density; 
	    return (int)(dip*scale + 0.5f*(dip>=0?1:-1)); 
	} 
	
	//根据xml文件中的属性,返回宽高(px)
    private static int[] getWidthAndHeight(Context context,AttributeSet attrs){
		int height,width;
		int n = attrs.getAttributeCount();
		int wAndH[] = new int[2];
		
		
		for(int i=0;i<n;i++){
			String str = attrs.getAttributeName(i);
			
			//获取宽度
			if(str.equals("layout_width")){				
				//System.out.println(attrs.getAttributeName(0));
				String sttr = attrs.getAttributeValue(i);
				String temp = "";
				int j=0;
				while(sttr.charAt(j)>='0'&&sttr.charAt(j)<='9'){
					temp+=sttr.charAt(j);
					j++;
				}
				wAndH[0]=Integer.parseInt(temp);
				temp="";
				continue;
			}
			
			//获取长度
			if(str.equals("layout_height")){
				//System.out.println(attrs.getAttributeName(1));
				String sttr = attrs.getAttributeValue(i);
				String temp = "";
				int j=0;
				while(sttr.charAt(j)>='0'&&sttr.charAt(j)<='9'){
					temp+=sttr.charAt(j);
					j++;
				}
				//System.out.println("temp"+temp);
				wAndH[1]=Integer.parseInt(temp);
				temp="";
				continue;
			}
		}
		return wAndH;
	}	
}

第二步:在xml文件中引用该控件

 <com.包名.MyRoundPhoto
          		android:id="@+id/myRoundPhoto"
                android:layout_width="100dp"
                android:layout_height="100dp"  >
                
            </com.包名.MyRoundPhoto>

第三步:实现圆形头像的点击事件,点击后显示对话框界面,询问你是打开相册还是相机(自动省略显示对话框的代码)

public void onClick(View v) {
		// TODO Auto-generated method stub
		
		//点击头像
		if(v.getId()==R.id.myRoundPhoto){
			//打开DialogActivity,询问打开照相机还是相册
			Intent intent = new Intent(GuideActivity.this,DialogActivity.class);
			startActivityForResult(intent, Info.PICK_PHOTO);
		}
	}

 第四步:根据用户选择情况,打开相册或者相机

	image =new File(Environment.getExternalStorageDirectory(),Info.PHOTO_NAME);

    public void onClick(View v) {
		// TODO Auto-generated method stub
		switch(v.getId()){
		
		//打开相机
		case R.id.imageButton1:{
			Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
			intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image));
			startActivityForResult(intent, Info.OPEN_CAMERA);		
			break;
		}
		
		//打开相册
		case R.id.imageButton2:{
			Intent intent = new Intent(Intent.ACTION_PICK);
			intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image));
			intent.setType("image/*");
			startActivityForResult(intent, Info.OPEN_GALLERY);
			break;
		}
		}
	}

第五步:将拍摄的图片或者相册选中的图片进行剪裁,将结果保存在指定内存区域

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO Auto-generated method stub
		super.onActivityResult(requestCode, resultCode, data);
		
		switch(requestCode){
		//打开相机	
		case Info.OPEN_CAMERA:{
			if(resultCode==RESULT_OK){
				
				//启动裁剪activity
				Log.v("启动剪裁程序", "是的");
				Intent intent1 = new Intent("com.android.camera.action.CROP");
	            intent1.setDataAndType(Uri.fromFile(image), "image/*");
	            intent1.putExtra("crop", "true");
	            intent1.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image));//
	            intent1.putExtra("aspectX", 1);
	            intent1.putExtra("aspectY", 1);
	            intent1.putExtra("outputFormat", Bitmap.CompressFormat.JPEG);
	            intent1.putExtra("outputX", 720);
	            intent1.putExtra("outputY", 720);
	            intent1.putExtra("return-data", false);
	            startActivityForResult(intent1, Info.CROP_PHOTO);
			}
			break;
		}
		
		//打开相册
		case Info.OPEN_GALLERY:{
			
			if(resultCode==RESULT_OK){		
				//启动剪裁程序
				Log.v("启动剪裁程序", "是的");
				Intent intent1 = new Intent("com.android.camera.action.CROP");
	            intent1.setDataAndType(Uri.fromFile(image), "image/*");
	            intent1.putExtra("crop", "true");
	            intent1.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image));//
	            intent1.putExtra("aspectX", 1);
	            intent1.putExtra("aspectY", 1);
	            intent1.putExtra("outputFormat", Bitmap.CompressFormat.JPEG);
	            intent1.putExtra("outputX", 720);
	            intent1.putExtra("outputY", 720);
	            intent1.putExtra("return-data", false);
	            startActivityForResult(intent1, Info.CROP_PHOTO);
			}		
			break;
		}
		
		//裁剪图片
		case Info.CROP_PHOTO:{
			Intent intent=new Intent();
			setResult(this.RESULT_OK, intent);
			finish();
			break;
		}
		}
	}

第六步:更新头像图片

      protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO Auto-generated method stub
		super.onActivityResult(requestCode, resultCode, data);
		
		switch(requestCode){
		//选择头像
		case Info.PICK_PHOTO:{
			//如果摄取图片成功
			if(resultCode==RESULT_OK){
				Log.v("requstCodeGuideOne", "PICK_PHOTO");
				btn_choosePhoto.myValidate(); //使原有视图无效,从而使系统重新绘制视图
			}
			break;
		}
		
		default:{
			break;
		}
		}
	}

注意:需要添加的权限

<uses-permission  
        android:name="android.permission.READ_EXTERNAL_STORAGE"  
        />  
<uses-permission  
    android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

 

作者:FlyinTang