Android拍照模块整理

                

 

主界面

去除标题栏

Manifests.xml中设置andriod:theme

android:theme="@style/Theme.AppCompat.Light.NoActionBar"

如果想去除顶部状态栏,可以在单个activity中的setContentView之前增加:

/**
     * 通过设置全屏,设置状态栏透明
     *
     * @param activity
     */
    private void fullScreen(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                //5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色
                Window window = activity.getWindow();
                View decorView = window.getDecorView();
                //两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间
                int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
                decorView.setSystemUiVisibility(option);
                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
                window.setStatusBarColor(Color.TRANSPARENT);
                //导航栏颜色也可以正常设置
//                window.setNavigationBarColor(Color.TRANSPARENT);
            } else {
                Window window = activity.getWindow();
                WindowManager.LayoutParams attributes = window.getAttributes();
                int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
                attributes.flags |= flagTranslucentStatus;
//                attributes.flags |= flagTranslucentNavigation;
                window.setAttributes(attributes);
            }
        }
    }

dialog的创建:

private void showBottomDialog(){
    //1、使用Dialog、设置style
    final Dialog dialog = new Dialog(this,R.style.DialogTheme);
    //2、设置布局
    View view = View.inflate(this,R.layout.dialog_buttom,null);
    dialog.setContentView(view);

    Window window = dialog.getWindow();
    //设置弹出位置
    window.setGravity(Gravity.BOTTOM);
    //设置弹出动画
    window.setWindowAnimations(R.style.main_menu_animStyle);
    //设置对话框大小
    window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
    dialog.show();

    dialog.findViewById(R.id.tv_take_photo).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            dialog.dismiss();
        }
    });

    dialog.findViewById(R.id.tv_take_pic).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            dialog.dismiss();
        }
    });

    dialog.findViewById(R.id.tv_cancel).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            dialog.dismiss();
        }
    });

}

dialog主题设置(styles.xml中):

<style name="DialogTheme" parent="@android:style/Theme.Dialog">
    <!-- 边框 -->
    <item name="android:windowFrame">@null</item>
    <!-- 是否浮现在activity之上 -->
    <item name="android:windowIsFloating">true</item>
    <!-- 半透明 -->
    <item name="android:windowIsTranslucent">true</item>
    <!-- 无标题 -->
    <item name="android:windowNoTitle">true</item>
    <item name="android:background">@android:color/transparent</item>
    <!-- 背景透明 -->
    <item name="android:windowBackground">@android:color/transparent</item>
    <!-- 模糊 -->
    <item name="android:backgroundDimEnabled">true</item>
    <!-- 遮罩层 -->
    <item name="android:backgroundDimAmount">0.5</item>
</style>

dialog的xml布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff">

    <TextView
        android:id="@+id/tv_take_photo"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="take photo"
        android:gravity="center"
        android:textSize="16sp"
        android:background="?android:attr/selectableItemBackground"
        android:textColor="@android:color/background_dark"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/colorbghomebg"/>

    <TextView
        android:id="@+id/tv_take_pic"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="select from album"
        android:gravity="center"
        android:textSize="16sp"
        android:background="?android:attr/selectableItemBackground"
        android:textColor="@android:color/background_dark"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="3dp"
        android:background="@color/colorbghomebg"/>

    <TextView
        android:id="@+id/tv_cancel"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="cancel"
        android:gravity="center"
        android:textSize="16sp"
        android:textColor="@android:color/background_dark"/>

</LinearLayout>

弹出动画设置(style.xml中增加一个名为main_menu_animStyle的样式):

    <!-- dialog的动画 -->
    <style name="main_menu_animStyle">
        <item name="android:windowEnterAnimation">@anim/dialog_in_anim</item>
        <item name="android:windowExitAnimation">@anim/dialog_out_anim</item>
    </style>

anmi文件的新建:

在res文件夹右击,new->android resource file->resource type选为animator(如果你需要文件夹名称为anim而不是animator,可以修改directory name为anim,然后在下面选择root element选择动画类型即可):

in_amin.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="500"
        android:fromXDelta="0"
        android:fromYDelta="1000"
        android:toXDelta="0"
        android:toYDelta="0" />
</set>

out.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="500"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="0"
        android:toYDelta="1000" />
</set>

参考了https://blog.csdn.net/xiaozhang0414/article/details/79382316这篇文章

水波纹效果可以参考一下https://www.jianshu.com/p/b8101b96246a

感谢你们的无私分享,省了很多事儿,嘿嘿^V^

 

接下来是实现拍照模块:

申请动态权限:

 //获取系统版本
        int currentapiVersion = android.os.Build.VERSION.SDK_INT;
        // 激活相机
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // 判断存储卡是否可以用,可用进行存储
        if (hasSdcard()) {
            filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + timeInMillis + ".jpg";
            tempFile = new File(filePath);
            if (currentapiVersion < 24) {
                // 从文件中创建uri
                imageUri = Uri.fromFile(tempFile);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            } else {
                //兼容android7.0 使用共享文件的形式
                ContentValues contentValues = new ContentValues(1);
                contentValues.put(MediaStore.Images.Media.DATA, tempFile.getAbsolutePath());
                //检查是否有存储权限,以免崩溃
                if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                        != PackageManager.PERMISSION_GRANTED) {
                    //申请WRITE_EXTERNAL_STORAGE权限
                    Toast.makeText(this, "请开启存储权限", Toast.LENGTH_SHORT).show();
                    return;
                }
                imageUri = activity.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            }
        }
        // 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_CAREMA
        startActivityForResult(intent, PHOTO_REQUEST_CAREMA);

判断是否有sd卡

 public static boolean hasSdcard () {
        return Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED);
    }

activity接受返回的图片结果

 switch (requestCode) {
            //打开相机后返回
            case PHOTO_REQUEST_CAREMA:
                if (resultCode == RESULT_OK) {
                    /**
                     * 这种方法是通过内存卡的路径进行读取图片,所以的到的图片是拍摄的原图
                     */
                    displayImage(tempFile.getPath());
                    Log.i("tag", "拍照图片路径>>>>" + tempFile.getAbsolutePath());
                }
                break;    //打开相册后返回
            case SELECT_PHOTO:
                if (resultCode == RESULT_OK) {
                    //判断手机系统版本号
                    if (Build.VERSION.SDK_INT > 19) {
                        //4.4及以上系统使用这个方法处理图片
                        handleImgeOnKitKat(data);
                    } else {
                        handleImageBeforeKitKat(data);
                    }
                }
                break;
        }

图片的处理以及展示:

 /**
     * 拍完照和从相册获取玩图片都要执行的方法(根据图片路径显示图片)
     */
    private void displayImage (String imagePath) {
        allImagePaths.add(imagePath);
        if (!TextUtils.isEmpty(imagePath)) {
            //orc_bitmap = BitmapFactory.decodeFile(imagePath);//获取图片
            orc_bitmap = comp(BitmapFactory.decodeFile(imagePath)); //压缩图片
            ImgUpdateDirection(imagePath);//显示图片,并且判断图片显示的方向,如果不正就放正
        } else {
            Toast.makeText(this, "图片获取失败", Toast.LENGTH_LONG).show();
        }
    }

图片压缩:

 ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        if (baos.toByteArray().length / 1024 > 1024) {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
            baos.reset();//重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, 50, baos);//这里压缩50%,把压缩后的数据存放到baos中
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        //开始读入图片,此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        //现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
        float hh = 800f;//这里设置高度为800f
        float ww = 480f;//这里设置宽度为480f
        //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        int be = 1;//be=1表示不缩放
        if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0)
            be = 1;
        newOpts.inSampleSize = be;//设置缩放比例
        newOpts.inPreferredConfig = Bitmap.Config.RGB_565;//降低图片从ARGB888到RGB565
        //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
        isBm = new ByteArrayInputStream(baos.toByteArray());
        bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);

修饰图片:

int digree = 0;//图片旋转的角度
        //根据图片的URI获取图片的绝对路径
        Log.i("tag", ">>>>>>>>>>>>>开始");
        //String filepath = ImgUriDoString.getRealFilePath(getApplicationContext(), uri);
        Log.i("tag", "》》》》》》》》》》》》》》》" + filepath);
        //根据图片的filepath获取到一个ExifInterface的对象
        ExifInterface exif = null;
        try {
            exif = new ExifInterface(filepath);
            Log.i("tag", "exif》》》》》》》》》》》》》》》" + exif);
            if (exif != null) {

                // 读取图片中相机方向信息
                int ori = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);

                // 计算旋转角度
                switch (ori) {
                    case ExifInterface.ORIENTATION_ROTATE_90:
                        digree = 90;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_180:
                        digree = 180;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_270:
                        digree = 270;
                        break;
                    default:
                        digree = 0;
                        break;
                }
            }
            //如果图片不为0
            if (digree != 0) {
                // 旋转图片
                Matrix m = new Matrix();
                m.postRotate(digree);
                orc_bitmap = Bitmap.createBitmap(orc_bitmap, 0, 0, orc_bitmap.getWidth(),
                        orc_bitmap.getHeight(), m, true);
            }
            if (orc_bitmap != null) {
                bitmapList.add(orc_bitmap);
                if(bitmapList.size()>0){
                    gridPhotoAdapter = new PhotoAdapter(this,bitmapList);
                    rcvPhoto.setLayoutManager(new GridLayoutManager(this,3));
                    rcvPhoto.setAdapter(gridPhotoAdapter);
                }
//                ivAddImage.setImageBitmap(orc_bitmap);
            }
        } catch (IOException e) {
            e.printStackTrace();
            exif = null;
        }

展示图片的RecyclerView

public class PhotoAdapter extends RecyclerView.Adapter<PhotoAdapter.VH> {
    private Context context;
    private List<Bitmap> bitmapList = new ArrayList<>();        //添加图片

    public PhotoAdapter (Context context, List<Bitmap> bitmapList) {
        this.context = context;
        this.bitmapList = bitmapList;
    }

    @NonNull
    @Override
    public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_photo,parent,false);
        return new VH(v);
    }

    @Override
    public void onBindViewHolder(@NonNull VH holder, int position) {
        holder.imageView.setImageBitmap(bitmapList.get(position));
    }

    @Override
    public int getItemCount() {
        return bitmapList.size();
    }

    public class VH extends RecyclerView.ViewHolder {
        private ImageView imageView;
        public VH(View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.iv_item_photo);
        }
    }
}

item_photo.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center">
    <ImageView
        android:id="@+id/iv_item_photo"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_centerInParent="true"/>
</RelativeLayout>

嗯 大概到这里就是结束了,这是一篇很详细的介绍,也是给自己备忘,老是丢三落四,嘿嘿^V^

如果你喜欢或者有什么想法,可以评论或者微信哦~

点个赞给个关注再走吧 Thanks♪(・ω・)ノ

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShineMan-

走过路过不要错过,一分钱也是爱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值