一.概述

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. android ——滑动菜单

    一.DrawerLayout是一个拥有两个子控件的布局,第一个子控件是主屏幕中显示的内容,第二个子控件是滑动菜单中显示的内容: <android.support.v4.widget.Drawer ...

  2. python练习题-1

    1.输出正方形 x=input("请输入:") x=int(x) for i in range(0,x): if (i==0) or (i==x-1): print("* ...

  3. IDEA导入spring-boot-plus(二)

    IDEA导入spring-boot-plus 安装lombok插件 !!!请先确保IDEA已安装lombok插件!!! IDEA在线安装lombok插件 IDEA离线下载安装lombok 如果在线安装 ...

  4. SpringBoot 配置 AOP 打印日志

    在项目开发中,日志系统是必不可少的,用AOP在Web的请求做入参和出参的参数打印,同时对异常进行日志打印,避免重复的手写日志,完整案例见文末源码. 一.Spring AOP AOP(Aspect-Or ...

  5. .net必问的面试题系列之面向对象

    上个月离职了,这几天整理了一些常见的面试题,整理成一个系列给大家分享一下,机会是给有准备的人,面试造火箭,工作拧螺丝,不慌,共勉. 1.net必问的面试题系列之基本概念和语法 2.net必问的面试题系 ...

  6. 用Python写了个下载快手视频的小脚本

    最近又重新拾起了,对python的热情. 贴个地址: https://github.com/d1y/lovepack/blob/master/kuaishou.py 前戏说明 因为我近乎癫狂的喜欢一个 ...

  7. React-native 关于 android真机 出现连不上服务器

    我们都知道使用RN开发移动端应用时,我们要在手机端运行程序,可以下载 expo 这个软件进行扫描二维码连接到开发的APP上 有时会有突然连不上之前连上过的应用,出现如下画面 首先保证你的电脑和你的手机 ...

  8. Spring 核心技术(7)

    接上篇:Spring 核心技术(6) version 5.1.8.RELEASE 1.6 定制 Bean 的特性 Spring Framework 提供了许多可用于自定义 bean 特性的接口.本节将 ...

  9. ValueError: Error when checking input: expected input_1 to have 2 dimensions, but got array with shape (100, 100, 100, 3)

    报错 Traceback (most recent call last): File "D:/PyCharm 5.0.3/WorkSpace/3.Keras/1.Sequential与Mod ...

  10. 计蒜客 蓝桥杯模拟 瞬间移动 dp

      在一个 n \times mn×m 中的方格中,每个格子上都有一个分数,现在蒜头君从 (1,1)(1,1) 的格子开始往 (n, m)(n,m) 的格子走.要求从 (x_1,y_1)(x1​,y1 ...