目前几乎所有的APP在用户注册时都会有设置头像的需求,大致分为三种情况:
(1)通过获取本地相册的图片,经过裁剪后作为头像。
(2)通过启动手机相机,现拍图片然后裁剪作为头像。
(3)在APP中添加一些自带的头像资源,供用户选择(不够人性化,目前很少使用)。
这次我们简单介绍下通过获取本地相册以及相机拍摄的方法设置头像,实现思路如下:
(1)通过startActivityForResult方法,分别传递调用系统相册的Intent和调用相机拍照的Intent来做选择
(2)调用Android系统中自带的图片剪裁,实现图片的剪裁并在onActivityResult方法中获取数据。
关于如何处理Activity的返回结果,请参照往期博文《Android中Activity处理返回结果的实现方式》。
本次演示效果如下(分别为从本地相册获取以及从相机拍摄获取头像):
简单布局文件这里不再做赘述,本次试验使用隐式intent调用相机以及本地相册,未在配置清单上添加权限,依然可以调用。java实现代码如下:
1 import android.content.Intent; 2 import android.graphics.Bitmap; 3 import android.net.Uri; 4 import android.os.Bundle; 5 import android.os.Environment; 6 import android.provider.MediaStore; 7 import android.support.v7.app.AppCompatActivity; 8 import android.view.View; 9 import android.widget.Button; 10 import android.widget.ImageView; 11 import android.widget.Toast; 12 import java.io.File; 13 14 public class MainActivity extends AppCompatActivity implements View.OnClickListener { 15 private Button buttonLocal, buttonCamera; 16 private ImageView imageView; 17 //相机拍摄的头像文件(本次演示存放在SD卡根目录下) 18 private static final File USER_ICON = new File(Environment.getExternalStorageDirectory(), "user_icon.jpg"); 19 //请求识别码(分别为本地相册、相机、图片裁剪) 20 private static final int CODE_PHOTO_REQUEST = 1; 21 private static final int CODE_CAMERA_REQUEST = 2; 22 private static final int CODE_PHOTO_CLIP = 3; 23 @Override 24 protected void onCreate(Bundle savedInstanceState) { 25 super.onCreate(savedInstanceState); 26 setContentView(R.layout.activity_main); 27 buttonLocal = (Button) findViewById(R.id.buttonLocal); 28 buttonCamera = (Button) findViewById(R.id.buttonCamera); 29 imageView = (ImageView) findViewById(R.id.imageView); 30 buttonLocal.setOnClickListener(this); 31 buttonCamera.setOnClickListener(this); 32 } 33 //设置点击事件 34 @Override 35 public void onClick(View view) { 36 switch (view.getId()) { 37 case R.id.buttonLocal: 38 //调用获取本地图片的方法 39 getPicFromLocal(); 40 break; 41 case R.id.buttonCamera: 42 //调用相机拍照的方法 43 getPicFromCamera(); 44 break; 45 default: 46 break; 47 } 48 } 49 /** 50 * 从本机相册获取图片 51 */ 52 private void getPicFromLocal() { 53 Intent intent = new Intent(); 54 // 获取本地相册方法一 55 intent.setAction(Intent.ACTION_GET_CONTENT); 56 intent.setType("image/*"); 57 //获取本地相册方法二 58 // intent.setAction(Intent.ACTION_PICK); 59 // intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 60 // "image/*"); 61 startActivityForResult(intent, CODE_PHOTO_REQUEST); 62 } 63 /** 64 * 通过相机拍摄获取图片, 65 * 并存入设置的路径中 66 */ 67 private void getPicFromCamera() { 68 Intent intent = new Intent(); 69 intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); 70 // 下面这句指定调用相机拍照后的照片存储的路径 71 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(USER_ICON)); 72 startActivityForResult(intent, CODE_CAMERA_REQUEST); 73 } 74 /** 75 * 图片裁剪 76 * 77 * @param uri 78 */ 79 private void photoClip(Uri uri) { 80 // 调用系统中自带的图片剪裁 81 Intent intent = new Intent(); 82 intent.setAction("com.android.camera.action.CROP"); 83 intent.setDataAndType(uri, "image/*"); 84 // 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪 85 intent.putExtra("crop", "true"); 86 // aspectX aspectY 是宽高的比例 87 intent.putExtra("aspectX", 1); 88 intent.putExtra("aspectY", 1); 89 /*outputX outputY 是裁剪图片宽高 90 *这里仅仅是头像展示,不建议将值设置过高 91 * 否则超过binder机制的缓存大小的1M限制 92 * 报TransactionTooLargeException 93 */ 94 intent.putExtra("outputX", 150); 95 intent.putExtra("outputY", 150); 96 intent.putExtra("return-data", true); 97 startActivityForResult(intent, CODE_PHOTO_CLIP); 98 } 99 /** 100 * 提取保存裁剪之后的图片数据,并设置头像部分的View 101 */ 102 private void setImageToHeadView(Intent intent) { 103 Bundle extras = intent.getExtras(); 104 if (extras != null) { 105 Bitmap photo = extras.getParcelable("data"); 106 imageView.setImageBitmap(photo); 107 } 108 } 109 @Override 110 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 111 // 用户没有进行有效的设置操作,返回 112 if (resultCode == RESULT_CANCELED) { 113 Toast.makeText(MainActivity.this, "取消", Toast.LENGTH_LONG).show(); 114 return; 115 } 116 switch (requestCode) { 117 case CODE_CAMERA_REQUEST: 118 if (USER_ICON.exists()) { 119 photoClip(Uri.fromFile(USER_ICON)); 120 } 121 break; 122 case CODE_PHOTO_REQUEST: 123 if (data != null) { 124 photoClip(data.getData()); 125 } 126 break; 127 case CODE_PHOTO_CLIP: 128 if (data != null) { 129 setImageToHeadView(data); 130 } 131 break; 132 } 133 super.onActivityResult(requestCode, resultCode, data); 134 } 135 }
这里要注意的是在裁剪图片时,长和宽不要设置太大,否则超过binder机制的缓存大小的限制(受手机配置影响).报TransactionTooLargeException,在代码中已经做了详细标注,请各位看官在实现的时候万万注意。