前言:
万丈高楼平底起,万事起于微末。不知不觉距离上篇博文已近四个月,2015年12月17日下午发了第一篇博文,现在是2016年4月6日。时间间隔长的过分啊,我自己都看不下去了。原因呢?当然是自己的原因,其实是有很多时间来些博客的,但是这些时间都花在DOTA上了(还是太年轻啊)。请原谅我的过错…….
一、概述:
现在几乎应用都会用到上传图片的功能,而要上传图片,首先得选择图片,本文不针对如何上传图片到服务器(每个项目与服务器交互的方式不同,因此不写上传图片到服务器相关代码),只是对选择图片做简单的介绍,没有涉及到对图片的圆角处理与剪裁。本文主要涉及以下几个简单的知识点:
- 简单的调用系统拍照和系统相册选择图片
- 通过GridView实现动态添加图片的效果
- Adapter使用的小技巧
- Fragment中调用系统拍照该怎么获取数据(接口回调)
二、实现:
我们先来看项目目录:
一个Adapter、两个Activity,一个Fragment、一个工具类,一目了然。有人在这里有疑问了,为什么是两个Activity?不是三个吗?没错,理论上ChooseActivity、ChooseFragmentActivity、BaseActivity加起来是三个,不过在这里BaseActivity是模拟实际项目抽离Activity中公共的代码,不做为视图,所以我不把BaseActivity算进去。
ChooseActivity是模拟Activity中调用系统拍照和系统相册选择图片,ChooseFragmentActivity中放入ChooseFragment模拟Fragment中调用系统拍照和系统相册选择图片(在这里我定死了一个Fragment模拟项目实际情况,实际情况一个Activity中会有多个Fragment),ImageUtils做一些简单的图片处理。SelectPicPopupWindow一个简单的PopupWindow,UploadImageAdapter动态选择图片上传的适配器。
先来点效果图吧:
图中展示的效果:点击默认图片弹出PopupWindow让用户选择拍照还是从相册选择图片(模拟器中不便使用拍照功能,本人在几台手机上试过没有问题,请到真机上测试),选择好图片后已选择好的图片可长按删除,这里控制了最多选择6张图片。
简单的调用系统拍照和系统相册选择图片
我们先来看是怎么调用系统拍照和从相册选择图片的:
申明组件与变量:
1 2 3 4 5 6 7 8 9 10 11 12 |
/** * 选择图片的返回码 */ public final static int SELECT_IMAGE_RESULT_CODE = 200; /** * 当前选择的图片的路径 */ public String mImagePath; /** * 自定义的PopupWindow */ private SelectPicPopupWindow menuWindow; |
弹出PopupWindow:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/** * 拍照或从图库选择图片(PopupWindow形式) */ public void showPicturePopupWindow(){ menuWindow = new SelectPicPopupWindow(this, new OnClickListener() { @Override public void onClick(View v) { // 隐藏弹出窗口 menuWindow.dismiss(); switch (v.getId()) { case R.id.takePhotoBtn:// 拍照 takePhoto(); break; case R.id.pickPhotoBtn:// 相册选择图片 pickPhoto(); break; case R.id.cancelBtn:// 取消 break; default: break; } } }); menuWindow.showAtLocation(findViewById(R.id.choose_layout), Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 0); } |
其中最重要的就是拍照相关的takephoto方法了了,部分机型拍完照后没有数据返回,只能通过指定拍完照获得图片的存储路径来解决这个问题了。注释写的很详细,这里不再多解释了。但是注意一点指定路径的时候可能会出现拍完照后无法点确定返回,有的手机甚至会点击后挂掉,这个时候会报不是有效路径的错误。我遇到错误是在获取到的与应用相关联的路径后面再创建一个文件/xxxx,至于为什么不行,我也不知道原理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
private void takePhoto() { // 执行拍照前,应该先判断SD卡是否存在 String SDState = Environment.getExternalStorageState(); if (SDState.equals(Environment.MEDIA_MOUNTED)) { /** * 通过指定图片存储路径,解决部分机型onActivityResult回调 data返回为null的情况 */ //获取与应用相关联的路径 String imageFilePath = getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath(); SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA); //根据当前时间生成图片的名称 String timestamp = "/"+formatter.format(new Date())+".jpg"; File imageFile = new File(imageFilePath,timestamp);// 通过路径创建保存文件 mImagePath = imageFile.getAbsolutePath(); Uri imageFileUri = Uri.fromFile(imageFile);// 获取文件的Uri Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT,imageFileUri);// 告诉相机拍摄完毕输出图片到指定的Uri startActivityForResult(intent, SELECT_IMAGE_RESULT_CODE); } else { Toast.makeText(this, "内存卡不存在!", Toast.LENGTH_LONG).show(); } } |
通过GridView实现动态添加图片的效果
其实你们更关心GridView动态增加item,item删除等效果:
申明组件和变量:
1 2 3 4 5 6 7 8 9 10 11 12 |
/** * 需要上传的图片路径 控制默认图片在最后面需要用LinkedList */ private LinkedList dataList = new LinkedList(); /** * 图片上传GridView */ private GridView uploadGridView; /** * 图片上传Adapter */ private UploadImageAdapter adapter; |
初始化GridView和Adapter:
1 2 3 4 5 6 |
uploadGridView = (GridView) findViewById(R.id.grid_upload_pictures); dataList.addLast(null);// 初始化第一个添加按钮数据 adapter = new UploadImageAdapter(this, dataList); uploadGridView.setAdapter(adapter); uploadGridView.setOnItemClickListener(mItemClick); uploadGridView.setOnItemLongClickListener(mItemLongClick); |
GridView的item点击监听和长按监听:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/** * 上传图片GridView Item单击监听 */ private OnItemClickListener mItemClick = new OnItemClickListener(){ @Override public void onItemClick(AdapterView> parent, View view, int position, long id) { if(parent.getItemAtPosition(position) == null){ // 添加图片 //showPictureDailog();//Dialog形式 showPicturePopupWindow();//PopupWindow形式 } } }; /** * 上传图片GridView Item长按监听 */ private OnItemLongClickListener mItemLongClick = new OnItemLongClickListener(){ @Override public boolean onItemLongClick(AdapterView> parent, View view, int position, long id) { if(parent.getItemAtPosition(position) != null){ // 长按删除 dataList.remove(parent.getItemAtPosition(position)); adapter.update(dataList); // 刷新图片 } return true; } }; |
对于onActivityResult的回调如下:
1 2 3 4 5 6 |