一.概述

android的 图片拍照 ,相册选图,以及图片剪切功能可以说非常常用. 尤其是图片上传功能,必然用到此功能. 而公司最近的一个项目中正好用到该功能. 记录下来以便以后再次用到,直接拿来使用.

在此之前,我也参考了网上很多代码示例, 写得都不错, 但是有一个问题可能大家都没发现, 当我参考网上示例写完后,发现 小米手机竟然不能使用该功能, 最后查了很多资料依然不能解决,最后猜测要么是 小米手机bug,要么就是 小米把android底层修改的过火了.

但是不管怎么样,必须要解决这个问题,毕竟用小米手机的人不在少数. 最后经人指点,终于搞定.

二.运行效果图点击圆形头像弹出自定义Dialog

代码如下:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); iv= (CircleImageView) findViewById(R.id.iv); iv.setBorderWidth(5); iv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new ActionSheetDialog(MainActivity.this).Builder()
.addSheetItem("拍照", ActionSheetDialog.SheetItemColor.BULE, new ActionSheetDialog.OnSheetItemClickListener() {
@Override
public void onClick(int witch) {
cameraorpic = 1;
openCamera();
}
}).addSheetItem("打开相册",ActionSheetDialog.SheetItemColor.BULE, new ActionSheetDialog.OnSheetItemClickListener() {
@Override
public void onClick(int witch) {
cameraorpic = 0;
openPic();
}
}).show();
}
});
} /**
* 打开相册
*/
private void openPic() {
Intent pickIntent = new Intent(Intent.ACTION_PICK, null);
pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");
startActivityForResult(pickIntent, REQUESTCODE_PICK); } /**
* 打开相机
*/
private void openCamera() {
String state = Environment.getExternalStorageState();
if (state.equals(Environment.MEDIA_MOUNTED)) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File outDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
if (!outDir.exists()) {
outDir.mkdirs();
}
outFile = new File(outDir, System.currentTimeMillis() + ".jpg");
Log.e("outFile",outFile+"");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outFile));
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
startActivityForResult(intent, PHOTO_REQUEST_TAKEPHOTO);
} else {
Log.e("CAMERA", "请确认已经插入SD卡");
}
} @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// 进行判断是那个操作跳转回来的,如果是裁剪跳转回来的这块就要把图片现实到View上,其他两种的话都把数据带入裁剪界面
switch (requestCode) {
//相册
case REQUESTCODE_PICK:
if (data == null || data.getData() == null) {
return;
}
startPhotoZoom(data.getData());
break;
//裁剪
case REQUESTCODE_CUTTING:
if (data != null) {
setPicToView(data);
}
break;
//拍照
case PHOTO_REQUEST_TAKEPHOTO:
Log.e("outFile1",outFile+"");
startPhotoZoom(Uri.fromFile(outFile));
break;
}
super.onActivityResult(requestCode, resultCode, data);
} /**
* 把裁剪好的图片设置到View上或者上传到网络
* @param data
*/
private void setPicToView(Intent data) {
Bundle extras = data.getExtras();
if (extras != null) {
/** 可用于图像上传 */
currentBitmap = extras.getParcelable("data"); iv.setImageBitmap(currentBitmap);
}
} /**
* 调用系统的图片裁剪
* @param data
*/
private void startPhotoZoom(Uri data) {
Log.e("outFile2",outFile+"");
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(data, "image/*");
intent.putExtra("crop", true);
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 300);
intent.putExtra("outputY", 300);
intent.putExtra("scale", true);//黑边
intent.putExtra("scaleUpIfNeeded", true);//黑边
intent.putExtra("return-data", true);
intent.putExtra("noFaceDetection", true);
startActivityForResult(intent, REQUESTCODE_CUTTING); }

上面的CircleImageView 是一个 圆形头像, 可以自定义实现也可以用 第三方库,这里用的是第三方的库

de.hdodenhof.circleimageview.CircleImageView --- github上面有,使用方法非常简单 配置如下所示
 <de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/img_head"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="@dimen/space_xl"
android:layout_marginTop="@dimen/space_xl"
android:src="@mipmap/default_head"
app:civ_border_color="#FFFFFF"
app:civ_border_width="2dp" />

这里的难点是这个自定义的 Dialog如下

public class ActionSheetDialog {

    private Context context;
private Dialog dialog;
private TextView txt_title;
private TextView txt_cancel;
private LinearLayout lLayout_content;
private ScrollView sLayout_content;
private boolean showTitle = false;
private List<SheetItem> sheetItemList;
private Display display; public ActionSheetDialog(Context context){ this.context = context;
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
display = windowManager.getDefaultDisplay(); } public ActionSheetDialog Builder(){
// 获取Dialog布局
View view = LayoutInflater.from(context).inflate(R.layout.view_actionsheet,null); // dialog的最小宽,设置屏幕宽度为 view.setMinimumWidth(display.getWidth()); //获取xml文件中的控件 sLayout_content = (ScrollView) view.findViewById(R.id.sLayout_content);
lLayout_content = (LinearLayout) view.findViewById(R.id.lLayout_content);
txt_title = (TextView) view.findViewById(R.id.txt_title);
txt_cancel = (TextView) view.findViewById(R.id.txt_cancel);
txt_cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss(); }
}); //定义 dialog的布局和参数
dialog = new Dialog(context, R.style.ActionSheetDialogStyle);
dialog.setContentView(view);
Window dialogWindow = dialog.getWindow();
dialogWindow.setGravity(Gravity.LEFT | Gravity.BOTTOM);
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
lp.x = 0;
lp.y = 0;
dialogWindow.setAttributes(lp); return this;
} public ActionSheetDialog setTitle(String title) {
showTitle = true;
txt_title.setVisibility(View.VISIBLE);
txt_title.setText(title);
return this;
} public ActionSheetDialog setCancelable(boolean cancel) {
dialog.setCancelable(cancel);
return this;
} public ActionSheetDialog setCanceledOnTouchOutside(boolean cancel) {
dialog.setCanceledOnTouchOutside(cancel);
return this;
}
public ActionSheetDialog addSheetItem(String itemName,SheetItemColor itemTextColor,OnSheetItemClickListener listener){
if(null == sheetItemList){
sheetItemList = new ArrayList<SheetItem>();
}
sheetItemList.add(new SheetItem(itemName, itemTextColor, listener)); return this;
} public void show(){
setSheetItems();
dialog.show();
} private void setSheetItems() { if (sheetItemList == null || sheetItemList.size() <= 0){
return;
} int size = sheetItemList.size();
// 控制高度
if (size > 5){
LayoutParams params = sLayout_content.getLayoutParams(); params.height = display.getHeight()/2; sLayout_content.setLayoutParams(params);
} for (int i = 1; i <= size; i++) {
final int index = i;
SheetItem sheetItem = sheetItemList.get(i-1); String itemName = sheetItem.name;
SheetItemColor itemTextcolor = sheetItem.color;
final OnSheetItemClickListener listener = sheetItem.listener; TextView textView = new TextView(context);
textView.setText(itemName);
textView.setTextSize(18);
textView.setGravity(Gravity.CENTER); if (size == 1){
if(showTitle){
textView.setBackgroundResource(R.drawable.actionsheet_bottom_selector);
}else{
textView.setBackgroundResource(R.drawable.actionsheet_top_selector);
}
}else {
if (showTitle){
if (i >= 1 && i < size) {
textView.setBackgroundResource(R.drawable.actionsheet_middle_selector);
} else {
textView.setBackgroundResource(R.drawable.actionsheet_bottom_selector);
}
}else {
if (i == 1) {
textView.setBackgroundResource(R.drawable.actionsheet_top_selector);
} else if (i < size) {
textView.setBackgroundResource(R.drawable.actionsheet_middle_selector);
} else {
textView.setBackgroundResource(R.drawable.actionsheet_bottom_selector);
}
}
} //字体颜色
if (null != itemTextcolor){
textView.setTextColor(Color.parseColor(itemTextcolor.getName()));
}else{
textView.setTextColor(Color.parseColor(SheetItemColor.BULE.getName()));
}
//高度
float scale = context.getResources().getDisplayMetrics().density;
int height = (int) (45 * scale + 0.5f);
textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, height)); //点击事件
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onClick(index);
dialog.dismiss();
}
}); lLayout_content.addView(textView); }
} public interface OnSheetItemClickListener{
void onClick(int witch);
} private class SheetItem{
String name;
OnSheetItemClickListener listener;
SheetItemColor color; public SheetItem(String name,SheetItemColor color,OnSheetItemClickListener listener) {
this.name = name;
this.listener = listener;
this.color = color;
}
} public enum SheetItemColor{
BULE("#037BFF"),RED("#FD4A2E"); String name ; private SheetItemColor(String name){
this.name = name;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}
}

自定义Dialog对应布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp" > <TextView
android:id="@+id/txt_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/actionsheet_top_normal"
android:gravity="center"
android:minHeight="45dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:textColor="@color/actionsheet_gray"
android:textSize="13sp"
android:visibility="gone"
/> <ScrollView
android:id="@+id/sLayout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fadingEdge="none"
> <LinearLayout
android:id="@+id/lLayout_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</ScrollView> <TextView
android:id="@+id/txt_cancel"
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_marginTop="8dp"
android:background="@drawable/actionsheet_single_selector"
android:gravity="center"
android:text="取消"
android:textColor="@color/actionsheet_blue"
android:textSize="18sp"
/> </LinearLayout>

自定义Dialog 弹出和收回动画

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:fromYDelta="100%"
android:toYDelta="0" />
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:fromYDelta="0"
android:toYDelta="100%" />

自定义Dialog 条目的 点击背景selector就不给出了, 很简单点击一下背景变成浅灰色

以上就是所有代码了, 当然如果觉得自定义dialog麻烦, 完全可以用 popupwindow来代替, 事实上网上很多 类似代码都是用的 popupwindow做的.

需要注意的一点是: 如果要做图片上传操作, 需要加入sd卡 的读写权限.

顺便说2句文件上传吧 . 我在项目中采用的是 按照图片路径方式进行上传的, 因为接口写不出来 以流的方式上传,所以 安卓端 也只能按照路径上传了.但是由于我们最终剪切的图片转成了一个Bitmap对象,所以要想获取这个Bitmap对象所在的路径是不容易获取到的, 因为拍照路径我们存到了outFile中, 而从相册选择的路径位于 content://media/external/images/media "媒体库"中, 他们路径是不同的, 这就为上传带来麻烦了.  为什么相册选择图片位于这里呢, 这就是前面我说到的为了适应小米手机.

我的最终解决办法是:  把这个最终的 Bitmap对象 转成流存入到 sd卡中比如: Environment.getxxxsdpath+"/temp","temp.jpg"  这样无论是 拍照还是 相册选择的 ,最终他们的路径都变成了sd路径下的temp.jpg, 那么拿着这个路径就可以上传图片了.

尽管有点麻烦,但是解决了问题.

android 拍照 相册 剪切以及显示功能的更多相关文章

  1. android——拍照,相册图片剪切其实就这么简单

    接触android这么久了.还没有真正的浩浩看看android拍照,相册图片剪切到底是怎么回事,每次都是从别人的代码一扣,就过来了.其实,谷歌提供的API已经很强大.只需要用的好,就那么几句就可以搞定 ...

  2. Android 实现调用系统拍照相册,剪切功能

    1.XML布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andr ...

  3. Android调用相册拍照控件实现系统控件缩放切割图片

    android 下如果做处理图片的软件 可以调用系统的控件 实现缩放切割图片 非常好的效果 今天写了一个demo分享给大家 package cn.m15.test; import java.io.By ...

  4. android --拍照,从相册获取图片,兼容高版本,兼容小米手机

    前几天做项目中选择图片的过程中遇到高版本和小米手机出现无法选择和崩溃的问题,现在记录下来,后面出现同类问题,也好查找 1,定义常量: private static final int TAKE_PIC ...

  5. [Android实例教程] 教你如何拍照+相册选择图片+剪裁图片完整实现

    [Android实例教程] 教你如何拍照+相册选择图片+剪裁图片完整实现 今天做Android项目的时候要用到图片选择,要实现拍照获取图片和从相册获取图片,并且要求在获取完之后可以裁剪,试了很多方法之 ...

  6. android 拍照和从相册选择组件

    android 拍照及从相册选择组件 单独封装到一个 activity 中便于更好的复用 拍照或从相册选择成功后使用 EventBus 发出广播回传图片路径,和调用者充分解耦合 根据传入参数支持裁剪和 ...

  7. Android拍照和从相册获取照片

    1.从相册获取照片 private void openAlumb() { //mRxPermissions:三方权限库 mRxPermissions .request(Manifest.permiss ...

  8. 彻底解决android拍照后无法显示的问题

    这是对上篇"android 图片拍照,相册选图,剪切并显示"的文章之后的 改进 上一篇文章虽然能解决图片的拍照剪切以及显示,但是发现他有一个缺点, 如果该程序单独运行,貌似没有任何 ...

  9. 真正可用的安卓webview html图片上传限制突破处理(拍照+相册都可以用)

    两篇起步使用webview参考文章,第一篇解除限制,但会调用外部浏览器打开链接,第二篇 覆盖shouldOverrideUrlLoading return true https://www.jb51. ...

随机推荐

  1. hadoop hdfs 分布式存储

    1.克隆前的工作 1.配置好网络nat  需要设置静态ip并能通过主机上网 ssh   和  rsync  是必须下载的 2.yum install vim wget  rsync  ssh   并配 ...

  2. Spark 系列(十)—— Spark SQL 外部数据源

    一.简介 1.1 多数据源支持 Spark 支持以下六个核心数据源,同时 Spark 社区还提供了多达上百种数据源的读取方式,能够满足绝大部分使用场景. CSV JSON Parquet ORC JD ...

  3. testlink搭建教程

    1,下载testlink安装包   请加QQ群299524235,在群文件中下载     2.配置Apache环境和PHP环境   解压testlink文件到Apache中, 通过127.0.0.1/ ...

  4. 洛谷 P1631 序列合并

    题意简述 有两个长度都是N的序列A和B,在A和B中各取一个数相加可以得到N^2个和,求这N^2个和中最小的N个. 题解思路 大根堆,先存入n个和,再比较大小,改变堆中元素. 代码 #include & ...

  5. 「雕爷学编程」Arduino动手做(10)——敲击传感器模块

    37款传感器和模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器与模块,依照实践出真知(动手试试)的理念,以学习和交流为目的,这里准备 ...

  6. CAD2015 C#二次开发 字体变形

    开发环境:VS2012问题描述:一个简单的WinForm窗口,一个群组控件和一个Label,都是微软雅黑12pxCAD2015下,看起来却不一样,一个明显细得多. CAD2014下,无此问题.实验了C ...

  7. 右键新建 .md

    右键新建 .md 文件 声明:虽然我成功了,并且右键出来了两个,但是在添加 .html 的过程中又失败了,找不到解决办法. win + r --> regedit --> enter 点击 ...

  8. Oracle cursor学习笔记

    目录 一.oracle库缓存 1.1.库缓存简介 1.2.相关概念 1.3.库缓存结构 1.4.sql执行过程简介 二.oracle cursor 2.1.cursor分类 2.2.shared cu ...

  9. HBase 系列(四)—— HBase 集群环境配置

    一.集群规划 这里搭建一个 3 节点的 HBase 集群,其中三台主机上均为 Regin Server.同时为了保证高可用,除了在 hadoop001 上部署主 Master 服务外,还在 hadoo ...

  10. poium测试库之JavaScript API封装原理

    poium一直我在维护的一个开源项目,它的定位是以极简的方式在自动化项目中Page Objects设计模式.我在之前的文章中也有介绍. 本篇文章主要介绍一个JavaScript元素操作的封装原理. 为 ...