安卓开发:从系统相册选择照片
来源:互联网 发布:中铁四局网络采购平台 编辑:程序博客网 时间:2024/06/05 19:16
概述
与调用系统摄像头拍照类似的,从系统相册选择照片的核心代码也仅仅只是一句呼唤系统Intent:
Intent intent = new Intent("android.intent.action.GET_CONTENT");
不过我们同样也要围绕这句核心代码做很多准备工作。
第一步:获取权限
从系统相册获取照片,需要对存储器的读写操作权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
注意:
比较悲剧的是,这两个权限在Android6.x之后也被划分为高危系统权限,因此仅仅只是在AndroidManifest.xml文件中声明一下是没有用的,还需要转本编写代码进行动态运行时权限申请。详细信息可以参考我的这篇文章:
http://blog.csdn.net/freezingxu/article/details/71409860
第二步:绘制或编写Activity界面
在我的应用场景中,我的界面是这个样子的:
我在界面上用TableLayout做了一个容器,每当从相册选择一张照片后,这张照片就会被放置在这个TableLayout中。如果选择了多张照片,那么就会像上图那样形成一个列表。
这样的界面结构其实非常简单,不过我还是把代码粘帖在这里:
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.yumi.mibao.easyasset.activities.TakePhotoActivity" android:background="@color/metro_white"> <Button android:id="@+id/BUTTON_COMPLETE" android:layout_width="0dp" android:layout_height="48dp" android:background="@color/yumi_red" android:textColor="@color/metro_white" android:text="@string/str_complete" android:layout_marginRight="8dp" app:layout_constraintRight_toRightOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="8dp" app:layout_constraintLeft_toRightOf="@+id/BUTTON_TAKE_PHOTO" android:layout_marginLeft="8dp" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" /> <Button android:id="@+id/BUTTON_TAKE_PHOTO" android:layout_width="68dp" android:layout_height="48dp" android:layout_marginBottom="8dp" android:layout_marginLeft="8dp" android:background="@color/metro_grass" android:text="@string/str_take_photo" android:textColor="@color/metro_white" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@+id/BUTTON_ALBUM" android:layout_marginStart="8dp" android:onClick="takePohto"/> <Button android:id="@+id/BUTTON_ALBUM" android:layout_width="68dp" android:layout_height="48dp" android:layout_marginBottom="8dp" android:layout_marginLeft="8dp" android:background="@color/metro_blue" android:text="@string/str_album" android:textColor="@color/metro_white" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginStart="8dp" android:onClick="pickPhotoFromAlbum" app:layout_constraintLeft_toLeftOf="parent" /> <ScrollView android:layout_width="0dp" android:layout_height="495dp" android:layout_marginRight="8dp" app:layout_constraintRight_toRightOf="parent" android:layout_marginLeft="8dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="8dp" app:layout_constraintHorizontal_bias="0.0" android:layout_marginBottom="8dp" app:layout_constraintBottom_toTopOf="@+id/BUTTON_COMPLETE"> <TableLayout android:id="@+id/TABLE_LAYOUT_TAKE_PHOTO_LIST" android:layout_width="match_parent" android:layout_height="fill_parent" android:layout_gravity="top" android:layout_marginTop="8dp" android:gravity="top" /> </ScrollView></android.support.constraint.ConstraintLayout>
在上面的代码中,可以看到id为“BUTTON_ALBUM”的按钮就对应了图片中的“相册”按钮,在这个按钮的onclick事件中,我触发了一个方法“pickPhotoFromAlbum”,就是这个方法会调起手机的拍照功能。具体实现往下看。
第三步:编写事件触发方法
3.1定义用于Intent回调的请求码
由于呼出系统拍照功能的Intent是采用startActivityForResult的模式来进行,所以需要明确的请求码来标记操作的类型,这样才能够在Intent的回调方法中进行相应的数据处理:
private final int PICK_FROM_ALBUN = 3;//从相册选择实际上,我们还会用到一个裁剪图片的请求码,定义如下:
private final int CROP_PHOTO = 2;//切图操作在后续的步骤中,我们会用到这个请求码
3.2定义被选中的照片的保存路径和文件名
/* * 从相册选择所得到的图像的保存路径 */private Uri imageUri;/* * 从相册选择的照片的文件名 */private String fileName;
3.3编写方法,呼出系统Intent,从相册选择照片
先来看一下选择相册的界面是什么样子的:
/** * 点击按钮从手机相册中获取图片 * @param view */public void pickPhotoFromAlbum(View view){ /* * 用时间戳的方式来命名图片文件,这样可以避免文件名称重复 */ SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); Date date = new Date(System.currentTimeMillis()); this.fileName = "easyassetFromAlbum"+format.format(date); /* * 创建一个File对象,用于存放选到的照片 */ File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); File outputImage = new File(path,this.fileName+".jpg"); /* * 以防万一,看一下这个文件是不是存在,如果存在的话,先删除掉 */ if(outputImage.exists()){ outputImage.delete(); } try { outputImage.createNewFile(); } catch (IOException e) { e.printStackTrace(); } /* * 将File对象转换为Uri对象,以便拍照后保存 */ this.imageUri = Uri.fromFile(outputImage); /* * 启动系统的选择界面 */ Intent intent = new Intent("android.intent.action.GET_CONTENT"); intent.putExtra("scale", true);//设置可以缩放 intent.putExtra("crop", true);//设置可以裁剪 intent.setType("image/*");//设置需要从系统选择的内容:图片 intent.putExtra(MediaStore.EXTRA_OUTPUT, this.imageUri);//设置输出位置 startActivityForResult(intent, this.PICK_FROM_ALBUN);//开始选择}可以看到,在代码的最后,采用startActivityForResult的形式呼出了系统Intent,并且将请求码“PICK_FROM_ALBUM”作为参数发送了过去。因此,我们必须编写onActivityResult方法,来处理回调业务。
3.4编写Intent回调方法
/** * 因为启动系统Intent使用的forResult模式,因此需要onActivityResult方法来接受回调参数 * @param requestCode * @param resultCode * @param data */@Overrideprotected void onActivityResult(int requestCode,int resultCode,Intent data){ super.onActivityResult(requestCode,resultCode,data); if (resultCode != RESULT_OK) { Toast.makeText(this, "获取图片出现错误", Toast.LENGTH_SHORT).show(); } else{ switch(requestCode) { /* * case PICK_FROM_ALBUM 代表从选择相册的intent返回之后 * 完成从相册中选择照片后,就要将图片生成bitmap对象,然后显示在界面上了 */ case PICK_FROM_ALBUN: this.cropPhoto(data.getData()); break; default: break; } }}可以看到,在switch中我们捕获了请求码“PICK_FROM_ALBUM”,然后立即调用了 一个方法“cropPhoto”,实际上这是一个用来裁剪图片的方法。
3.5编写图片裁剪方法
/** * 打开裁剪图片的系统界面 */private void cropPhoto(Uri imageUri){ /* * 准备打开系统自带的裁剪图片的intent */ Intent intent = new Intent("com.android.camera.action.CROP"); //打开系统自带的裁剪图片的intent intent.setDataAndType(imageUri, "image/*"); intent.putExtra("scale", true); /* * 设置裁剪区域的宽高比例 */ intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); /* * 设置裁剪区域的宽度和高度 */ intent.putExtra("outputX", 340); intent.putExtra("outputY", 340); /* * 指定裁剪完成以后的图片所保存的位置 */ intent.putExtra(MediaStore.EXTRA_OUTPUT, this.imageUri); Toast.makeText(this, "剪裁图片", Toast.LENGTH_SHORT).show(); /* * 以广播方式刷新系统相册,以便能够在相册中找到刚刚所拍摄和裁剪的照片 */ Intent intentBc = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intentBc.setData(this.imageUri); this.sendBroadcast(intentBc); /* * 以forResult模式启动系统自带的裁剪图片的intent */ startActivityForResult(intent, CROP_PHOTO); //设置裁剪参数显示图片至ImageView}可以看到,在上述方法的最后,我们启动了系统自带图片裁剪Intent,并且将请求码“CROP_PHOTO”以startActivityForResult的形式传递过去。
手机打开的且图界面是这样的:
3.6在Intent的回调方法中,增加对切图回调的处理
/* * case CROP_PHOTO 代表从裁剪照片的intent返回之后 * 完成裁剪照片后,就要将图片生成bitmap对象,然后显示在界面上面了 */case CROP_PHOTO: try { /* * 将图片转换成Bitmap对象 */ Bitmap bitmap = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(this.imageUri)); Toast.makeText(this, this.imageUri.toString(), Toast.LENGTH_SHORT).show(); /* * 在界面上显示图片 */ this.addPhotoToActivity(bitmap); } catch(FileNotFoundException e) { e.printStackTrace(); } break;所以,整个回调方法看起来是这样的:
@Overrideprotected void onActivityResult(int requestCode,int resultCode,Intent data){ super.onActivityResult(requestCode,resultCode,data); if (resultCode != RESULT_OK) { Toast.makeText(this, "获取图片出现错误", Toast.LENGTH_SHORT).show(); } else{ switch(requestCode) { /* * case CROP_PHOTO 代表从裁剪照片的intent返回之后 * 完成裁剪照片后,就要将图片生成bitmap对象,然后显示在界面上面了 */ case CROP_PHOTO: try { /* * 将图片转换成Bitmap对象 */ Bitmap bitmap = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(this.imageUri)); Toast.makeText(this, this.imageUri.toString(), Toast.LENGTH_SHORT).show(); /* * 在界面上显示图片 */ this.addPhotoToActivity(bitmap); } catch(FileNotFoundException e) { e.printStackTrace(); } break; /* * case PICK_FROM_ALBUM 代表从选择相册的intent返回之后 * 完成从相册中选择照片后,就要将图片生成bitmap对象,然后显示在界面上了 */ case PICK_FROM_ALBUN: this.cropPhoto(data.getData()); break; default: break; } }}可以看到,在完成切图后,直接调用了一个方法“addPhotoToActivity”,来将选择的照片显示在界面上。
3.7显示图片
/** * 将拍照和裁剪后所得到的照片,罗列在界面上 */private void addPhotoToActivity(Bitmap bitMap){ /* * 首先获取到用来显示照片的容器 * 该容易是一个TableLayout */ TableLayout tableLayout = (TableLayout)this.findViewById(R.id.TABLE_LAYOUT_TAKE_PHOTO_LIST); /* * 创建一个TableRow对象 * 每一行TableRow对象都用来存放一张照片,以及该照片的上传情况信息 * 将这个TableRow放入TableLayout中 */ TableRow tableRow = new TableRow(this); tableRow.setPadding(0,0,0,8);//设置每一行的下间距 tableLayout.addView(tableRow); /* * 创建一个ImageView对象 * 将这个对象放入TableRow中 * 并在这个对象上显示刚刚拍照所得到的照片 */ ImageView imageView = new ImageView(this); imageView.setLayoutParams(this.photoParams); imageView.setImageBitmap(bitMap); tableRow.addView(imageView); /* * 创建一个TextView对象 * 为这个对象设置一段“图片正在上传”的提示文字 * 并将这个TextView对象放入TableRow中 */ TextView textView = new TextView(this); textView.setLayoutParams(this.uploadStateMsgParam); textView.setGravity(Gravity.CENTER_VERTICAL); textView.setText("正在上传照片..."); textView.setTextColor(ContextCompat.getColor(this,R.color.metro_blue)); tableRow.addView(textView); }在上述代码中,会用到两个界面组件的样式定义,如下:
/* * 一组界面样式,分别是照片在TableRow中所占的宽度比重和照片上传状态的文字信息在TableRow中所占的宽度比重 */private TableRow.LayoutParams photoParams;private TableRow.LayoutParams uploadStateMsgParam;
/** * 初始化一些界面组件的样式 */private void initLayoutParams(){ /* * 拍照所得到的图片被放置在界面上时,其在TableRow所占的宽度占比 */ this.photoParams = new TableRow.LayoutParams( TableRow.LayoutParams.WRAP_CONTENT, 268, 0.1f ); /* * 照片上传状态的文字信息被放置在界面上时,其在TableRow所占的宽度占比 */ this.uploadStateMsgParam = new TableRow.LayoutParams( TableRow.LayoutParams.WRAP_CONTENT, 268, 0.9f );}
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_easy_asset_take_photo); /* * 调用方法,初始化界面组件的样式 */ this.initLayoutParams();}
至此所有的逻辑就全部实现了。
阅读全文
0 0
- 安卓开发:从系统相册选择照片
- Android开发之从相册选择照片
- 第一行安卓代码——从相册中选择照片8.3.2
- 从相册中选择照片
- 从相册中选择照片
- Android开发如何从手机相册中选择照片
- 从相册中选择照片并返回~
- Android 从相册中选择照片
- Android仿qq从相册选择照片
- Android 从相册选择照片 手机拍照
- android: 从相册中选择照片
- 安卓开发,从相册或者相机中选择一张图片并裁剪,上传和下载。
- android拍摄照片和从相册里选择照片
- 安卓手机拍照,从相册选择,上传头像
- Android开发从相册中选取照片
- Swift-->从相册(摄像头)选择照片,图片选择
- 安卓日记——一个从相册或者相机获取照片的工具类
- swift相册选择照片
- Leetcode 190 Reverse Bits
- AndroidStudio 中 buildSrc/src/main/groovy 的构建
- javaweb中的cookie
- 2017 Java 中== 与 equals 区别 终极见解
- Leetcode 191 Number of 1 Bits
- 安卓开发:从系统相册选择照片
- dwr学习
- Codeforces 359D Pair of Numbers【思维+二分+区间Gcd+区间最小值RMQ】
- 阿里云 CentOS7 安装 TOMCAT丶JDK丶MySQL
- javascript深入理解js闭包
- 毕业,不结束&青春,不散场
- http://www.360doc.com/content/17/0702/16/44981652_668216787.shtml
- Leetcode 204 Count Primes
- git的缺点(1) -- 不能add空文件夹