zoukankan      html  css  js  c++  java
  • 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, 那么拿着这个路径就可以上传图片了.

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

  • 相关阅读:
    网络对抗技术-实验四
    网络对抗技术-实验三
    安卓终端-Termux
    linux杂记
    使用pl/sql导入导出oracle
    systemctl 实现开机自启服务
    Java8 Collectors.toMap的坑
    idea使用lombok插件
    解决Lost connection to MySQL server during query错误方法
    java8之lamda
  • 原文地址:https://www.cnblogs.com/android-zcq/p/5440318.html
Copyright © 2011-2022 走看看