android 拍照 相册 剪切以及显示功能
一.概述
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 拍照 相册 剪切以及显示功能的更多相关文章
- android——拍照,相册图片剪切其实就这么简单
接触android这么久了.还没有真正的浩浩看看android拍照,相册图片剪切到底是怎么回事,每次都是从别人的代码一扣,就过来了.其实,谷歌提供的API已经很强大.只需要用的好,就那么几句就可以搞定 ...
- Android 实现调用系统拍照相册,剪切功能
1.XML布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andr ...
- Android调用相册拍照控件实现系统控件缩放切割图片
android 下如果做处理图片的软件 可以调用系统的控件 实现缩放切割图片 非常好的效果 今天写了一个demo分享给大家 package cn.m15.test; import java.io.By ...
- android --拍照,从相册获取图片,兼容高版本,兼容小米手机
前几天做项目中选择图片的过程中遇到高版本和小米手机出现无法选择和崩溃的问题,现在记录下来,后面出现同类问题,也好查找 1,定义常量: private static final int TAKE_PIC ...
- [Android实例教程] 教你如何拍照+相册选择图片+剪裁图片完整实现
[Android实例教程] 教你如何拍照+相册选择图片+剪裁图片完整实现 今天做Android项目的时候要用到图片选择,要实现拍照获取图片和从相册获取图片,并且要求在获取完之后可以裁剪,试了很多方法之 ...
- android 拍照和从相册选择组件
android 拍照及从相册选择组件 单独封装到一个 activity 中便于更好的复用 拍照或从相册选择成功后使用 EventBus 发出广播回传图片路径,和调用者充分解耦合 根据传入参数支持裁剪和 ...
- Android拍照和从相册获取照片
1.从相册获取照片 private void openAlumb() { //mRxPermissions:三方权限库 mRxPermissions .request(Manifest.permiss ...
- 彻底解决android拍照后无法显示的问题
这是对上篇"android 图片拍照,相册选图,剪切并显示"的文章之后的 改进 上一篇文章虽然能解决图片的拍照剪切以及显示,但是发现他有一个缺点, 如果该程序单独运行,貌似没有任何 ...
- 真正可用的安卓webview html图片上传限制突破处理(拍照+相册都可以用)
两篇起步使用webview参考文章,第一篇解除限制,但会调用外部浏览器打开链接,第二篇 覆盖shouldOverrideUrlLoading return true https://www.jb51. ...
随机推荐
- 算法与数据结构基础 - 分治法(Divide and Conquer)
分治法基础 分治法(Divide and Conquer)顾名思义,思想核心是将问题拆分为子问题,对子问题求解.最终合并结果,分治法用伪代码表示如下: function f(input x size ...
- Flutter 1.7 正式版发布
今天,我们非常高兴地向大家宣布又一个正式版本的发布 -- Flutter 1.7,这是继上次 I/O 时众多重要功能发布以来的一次小更新.Flutter 1.7 包含了对 AndroidX 的支持,满 ...
- 转载:hive分区(partiton)简介
网上有篇关于hive的partition的使用讲解的比较好,所以转载了.原文https://blog.csdn.net/akon_vm/article/details/37832511 一.背景 1. ...
- JMeter的JTL大文件解析
1.背景 不知大家在使用JMeter工具进行性能测试时,是否遇到过JTL结果文件过大导致GUI页面长时间解析无响应的问题.这种情况往往出现在稳定性测试场景下,此时的JTL文件大小可能已经达到G级别了. ...
- oracle 正则表达的使用
最近遇到有个项目,需要根据文件存储的根目录地址来判断是在云端获取,还是本地获取, 先看下具体有几个不同的根目录: , , 'i') from pmc.designmaterial d 去重关键字:di ...
- 在win10中安装python3.6.6
文章目录: 一.登录到官网下载指定python版本 二.在win10中安装python3.6.6并验证安装结果 三.运行python的三种方 ...
- Sqlserver2012 评估期已过问题
sql server 2012提示评估期已过的解决方法: 第一步:进入SQL2012配置工具中的安装中心. 第二步:再进入左侧维护选项界面,然后选择选择版本升级. 第三步:进入输入产品密钥界面,输入相 ...
- LInux系统@安装CentOS7虚拟机
安装Centos7虚拟机 1.打开VMware,点击创建新的虚拟机(至关重要) 2.选择自定义配置,点击下一步 3.选择虚拟机硬件兼容性<Workstation 12.0>,点击下一步 4 ...
- 设计模式(C#)——03建造者模式
推荐阅读: 我的CSDN 我的博客园 QQ群:704621321 当一个复杂对象由一些子对象构成,并且子对象的变化会导致复杂对象的修改.这时我们需要提供一种"封装机制&qu ...
- 解决npm报错:Module build failed: TypeError: this.getResolve is not a function
1.sass-loader的版本过高导致的编译错误,当前最高版本是8.x,需要退回到7.3.1 运行: npm uninstall sass-loader --save-dev(卸载当前版本) npm ...