Android 拍照以及相册中选择(适配高版本)————上传多张照片之压缩处理、在线预览可伸缩放大(二)

news2024/11/24 16:17:42

在这里插入图片描述

______ Introduction ______
前言

       上一篇文章刚给大家总结完,关于上传头像的功能。此文章所述 主要是关于上传头像的具体流程以及如何对照片做裁剪处理,回调给控件显示;当然重中之重适配了Android高版本,有兴趣的大家可以去看一下:

       Android 拍照以及相册中选择(适配高版本)————上传头像并裁剪(一)

       本篇将从另一个开发场景,给大家带来关于上传多张照片的需求。

       记得之前拿华为的测试机拍出来的一张照片,就要十几M。在图片量过大的情况下,必须要对图片做压缩处理,减少内存损耗,也尽量避免占用内存;每当图片过大,或是多张图片一起上传的时候总会造成oom

       接下来,通过本篇让我们一起来实现,多张图片上传并做压缩处理之后,可以实现在线预览以及伸缩放大等功能

______ Animation Effect ______
效果

实测android 8、android 9、android 11、android 13、鸿蒙系统均有效;
手机机型分别为OPPO、华为、VIVO手机、小米、小米平板。

  1. VIVO android 13

  1. 华为 鸿蒙系统2.0.1

______ Function ______
功能

  1. 动态申请拍照,读,写权限
  2. 自定义弹出框
  3. 调用系统相机拍照
    3.1 调用系统相机申请拍照权限回调
    3.2 拍照完成回调
    3.3 对图片做压缩处理
  4. 自动获取sdk权限
    4.1 访问相册完成回调
    4.2 对图片做压缩处理
  5. 可在线预览照片
______ Concrete Realization ______
具体实现

(1)动态申请权限

	public static String[] permission = {
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.CAMERA};

	AppUtils.requestPermission(permission);
    
	@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        switch (requestCode) {
            //调用系统相机申请拍照权限回调
            case CAMERA_PERMISSIONS_REQUEST_CODE: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if (AppUtils.hasSdcard()) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                            imageUri = FileProvider.getUriForFile(MainActivity.this, "com.harry.takepicture.provider", cardImage);
                        } else {
                            imageUri = Uri.fromFile(cardImage);
                        }

                        PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_CARD_REQUEST);
                    } else {
                        ToastUtils.showShort(this, "设备没有SD卡!");
                    }
                } else {
                    ToastUtils.showShort(this, "请允许打开相机!!");
                }
                break;
            }
        }
    }
   public class AppUtils {

    /**
     * 申请权限
     *
     * @param permission
     */
    public static void requestPermission(String[] permission) {
        BaseActivity.requestRunTimePermission(permission, new PermissionListener() {
            @Override
            public void onGranted() {
                Log.e("tb", "所有权限授权成功");
            }

            @Override
            public void onGranted(List<String> grantedPermission) {
                Log.e("tb", "授权成功集合权限---" + grantedPermission);
            }

            @Override
            public void onDenied(List<String> deniedPermission) {
                Log.e("tb", "授权失败集合权限---" + deniedPermission);
            }
        });
    }
}

(2)自定义弹出框

本篇主要内容为Camera相关,忽略…

(3.1)调用系统相机拍照

	/**
     * 拍照
     *
     * @param
     */
    private void takePhoto() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
                ToastUtils.showShort(this, "您已经拒绝过一次");
            }
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_PERMISSIONS_REQUEST_CODE);
        } else {//有权限直接调用系统相机拍照
            if (AppUtils.hasSdcard()) {
                cardImage = new File(Environment.getExternalStorageDirectory().getPath(), System.currentTimeMillis() + ".jpg");

                //通过FileProvider创建一个content类型的Uri
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    imageUri = FileProvider.getUriForFile(this, "com.harry.takepicture.provider", cardImage);
                } else {
                    imageUri = Uri.fromFile(cardImage);
                }

                PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_CARD_REQUEST);
            } else {
                ToastUtils.showShort(this, "设备没有SD卡!");
            }
        }
    }

(3.2)处理拍照回调

 /**
     * 执行回调
     *
     * @param requestCode
     * @param resultCode
     * @param data
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == RESULT_OK) {
            fileCropUri = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");
            switch (requestCode) {
                //拍照完成回调
                case CODE_CAMERA_CARD_REQUEST:
                    cropImageUri = Uri.fromFile(fileCropUri);
                    String img = cardImage.getAbsolutePath();
                    //img就是压缩后的图片
                    String imgPic = BitmapUtil.compressImageUpload(img);
                    Log.e("tb", "paths----------" + imgPic);

                    urlimg.add(0, imgPic);

                    if (null != imgPic) {
                        showPic(imgPic);
                    }
                    break;               
                default:
            }
        }
    }

(3.3)对图片做压缩处理

BitmapUtil.compressImageUpload(img);
/**
 * @author 拉莫帅
 * @date 2021/9/9
 * @address
 * @Desc BitmapUtil
 */
public class BitmapUtil {

    /**
     * 质量压缩方法
     *
     * @param image
     * @return
     */
    private static Bitmap compressImage(Bitmap image) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int options = 100;
        while (baos.toByteArray().length / 1024 > 100) {
            baos.reset();
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);
            options -= 10;
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
        return bitmap;
    }

    /**
     * 图片按比例大小压缩方法(根据路径获取图片并压缩)
     *
     * @param srcPath
     * @return
     */
    private static Bitmap getImage(String srcPath) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        newOpts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);// 此时返回bm为空

        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;// 设置缩放比例
        // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
        bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
        return compressImage(bitmap);// 压缩好比例大小后再进行质量压缩
    }

    /**
     * 将压缩的bitmap保存到SDCard卡临时文件夹,用于上传
     *
     * @param filename
     * @param bit
     * @return
     */
    private static String saveMyBitmap(String filename, Bitmap bit) {
        String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/laopai/";
        String filePath = baseDir + filename;
        File dir = new File(baseDir);
        if (!dir.exists()) {
            dir.mkdir();
        }

        File f = new File(filePath);
        try {
            f.createNewFile();
            FileOutputStream fOut = null;
            fOut = new FileOutputStream(f);
            bit.compress(Bitmap.CompressFormat.PNG, 100, fOut);
            fOut.flush();
            fOut.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }

        return filePath;
    }

    /**
     * 压缩上传路径
     *
     * @param path
     * @return
     */
    public static String compressImageUpload(String path) {
        String filename = path.substring(path.lastIndexOf("/") + 1);
        Bitmap image = getImage(path);
        return saveMyBitmap(filename, image);
    }


    /**
     * 清除缓存文件
     */
    public static void deleteCacheFile() {
        File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/laopai/");
        RecursionDeleteFile(file);
    }

    /**
     * 递归删除
     */
    private static void RecursionDeleteFile(File file) {
        if (file.isFile()) {
            file.delete();
            return;
        }
        if (file.isDirectory()) {
            File[] childFile = file.listFiles();
            if (childFile == null || childFile.length == 0) {
                file.delete();
                return;
            }
            for (File f : childFile) {
                RecursionDeleteFile(f);
            }
            file.delete();
        }
    }
}

(4)自动获取SDK权限

	/**
     * 自动获取sdk权限
     */
    private void autoObtainStoragePermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSIONS_REQUEST_CODE);
        } else {
            PhotoUtils.openPic(this, CODE_GALLERY_CARD_REQUEST);
        }
    }

(4.1)访问相册完成回调

 /**
     * 执行回调
     *
     * @param requestCode
     * @param resultCode
     * @param data
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == RESULT_OK) {
            fileCropUri = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");
            switch (requestCode) {
                //访问相册完成回调
                case CODE_GALLERY_CARD_REQUEST:
                    if (AppUtils.hasSdcard()) {
                        cropImageUri = Uri.fromFile(fileCropUri);
                        String path = GetPathFromUri.getPath(this, data.getData());
                        //imgPath就是压缩后的图片
                        String imgPath = BitmapUtil.compressImageUpload(path);
                        Log.e("tb", "paths----------" + imgPath);
                        urlimg.add(0, imgPath);

                        if (null != imgPath) {
                            showPic(imgPath);
                        }
                    } else {
                        ToastUtils.showShort(this, "设备没有SD卡!");
                    }
                    break;
                default:
            }
        }
    }

(4.2)对图片做压缩处理 —> (3.3)

BitmapUtil.compressImageUpload(path);

(5)可在线预览照片

	// 显示图片
	List<String> pic = new ArrayList<>();
	
	/**
     * 展示
     *
     * @param imgPic
     */
    private void showPic(String imgPic) {
        pic.add(0, imgPic);
        picAdapter.notifyDataSetChanged();
    }
    // 进入预览界面
 	Intent intent = new Intent(MainActivity.this, ShowImgActivity.class);
 	intent.putExtra("image_path", pic.get(position));
 	startActivity(intent);

对于预览图片,单点/多点触摸来进行图片缩放
采用的是开源PhotoView控件

implementation 'com.github.chrisbanes:PhotoView:1.2.6'

此项目个人采用的是jar的方式,依赖方式至上。

______ Full Implementation ______
完整实现

/**
 * @author 拉莫帅
 * @date 2023/4/01
 * @address
 * @Desc TakePicture 上传多张照片并压缩处理
 */
public class MainActivity extends BaseActivity implements View.OnClickListener {
    public static String[] permission = {
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.CAMERA};

    private RecyclerView recycle;
    private Intent intent;
    private View view;
    private List<String> pic; // 显示图片
    private List<String> urlimg; // 上传图片路径

    private Uri cropImageUri;
    private File cardImage;
    private File fileCropUri;//裁剪的照片
    private Uri imageUri;//拍照所得到的图像的保存路径
    private static final int CAMERA_PERMISSIONS_REQUEST_CODE = 0x03;
    private static final int STORAGE_PERMISSIONS_REQUEST_CODE = 0x04;

    private static final int CODE_GALLERY_CARD_REQUEST = 0xa5;
    private static final int CODE_CAMERA_CARD_REQUEST = 0xa6;
    private PicAdapter picAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStatusBg(1);
        AppUtils.requestPermission(permission);

        initView();
        initData();
    }

    @Override
    protected View addContentLayout() {
        view = getLayoutInflater().inflate(R.layout.activity_main, contentLayout, false);
        return view;
    }

    private void initView() {
        recycle = findViewById(R.id.recycle);

        // 初始化数据
        urlimg = new ArrayList<>();
        pic = new ArrayList<>();
        pic.add(this.getResources().getResourceName(R.drawable.add_pic_icon));
    }

    private void initData() {
        // 初始化适配器
        picAdapter = new PicAdapter(this, pic);
        recycle.setLayoutManager(new GridLayoutManager(this, 3));
        recycle.setAdapter(picAdapter);
        //添加ItemDecoration,item之间的间隔
        int leftRight = AppUtils.dip2px(15, this);
        int topBottom = AppUtils.dip2px(15, this);
        recycle.addItemDecoration(new SpacesItemDecoration(leftRight, topBottom));
        picAdapter.setOnItemClickListener(new PicAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                if (pic.size() > 2 && pic.get(position).equals(MainActivity.this.getResources().getResourceName(R.drawable.add_pic_icon))) {
                    ToastUtils.showShort(MainActivity.this, "最多只能上传2张图片");
                } else {
                    if (pic.get(position).equals(MainActivity.this.getResources().getResourceName(R.drawable.add_pic_icon))) {
                        select();
                    } else {
                        intent = new Intent(MainActivity.this, ShowImgActivity.class);
                        intent.putExtra("image_path", pic.get(position));
                        startActivity(intent);
                    }
                }
            }
        });

        picAdapter.setOnClickDelete(new PicAdapter.OnClickDelete() {
            @Override
            public void myClickDelete(int pos) {
                if (pic.get(pos).equals(MainActivity.this.getResources().getResourceName(R.drawable.add_pic_icon))) {
                    return;
                }
                if (pic.size() > 0) {
                    pic.remove(pos);
                    picAdapter.notifyDataSetChanged();
                }
            }
        });
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.userinfo_iv_head:
                select();
                break;
            case R.id.rl_head_camera:
                takePhoto();
                AppUtils.dismiss();
                break;
            case R.id.rl_head_photo:
                autoObtainStoragePermission();
                AppUtils.dismiss();
                break;
            case R.id.rl_head_cancel:
                AppUtils.dismiss();
                break;
        }
    }

    private void select() {
        AppUtils.selectPhoto(MainActivity.this, R.layout.dialog_head, R.layout.activity_main, this);
    }

    /**
     * 拍照
     *
     * @param
     */
    private void takePhoto() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
                ToastUtils.showShort(this, "您已经拒绝过一次");
            }
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, CAMERA_PERMISSIONS_REQUEST_CODE);
        } else {//有权限直接调用系统相机拍照
            if (AppUtils.hasSdcard()) {
                cardImage = new File(Environment.getExternalStorageDirectory().getPath(), System.currentTimeMillis() + ".jpg");

                //通过FileProvider创建一个content类型的Uri
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    imageUri = FileProvider.getUriForFile(this, "com.harry.takepicture.provider", cardImage);
                } else {
                    imageUri = Uri.fromFile(cardImage);
                }

                PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_CARD_REQUEST);
            } else {
                ToastUtils.showShort(this, "设备没有SD卡!");
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        switch (requestCode) {
            //调用系统相机申请拍照权限回调
            case CAMERA_PERMISSIONS_REQUEST_CODE: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if (AppUtils.hasSdcard()) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                            imageUri = FileProvider.getUriForFile(MainActivity.this, "com.harry.takepicture.provider", cardImage);
                        } else {
                            imageUri = Uri.fromFile(cardImage);
                        }

                        PhotoUtils.takePicture(this, imageUri, CODE_CAMERA_CARD_REQUEST);
                    } else {
                        ToastUtils.showShort(this, "设备没有SD卡!");
                    }
                } else {
                    ToastUtils.showShort(this, "请允许打开相机!!");
                }
                break;
            }
        }
    }

    /**
     * 自动获取sdk权限
     */
    private void autoObtainStoragePermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSIONS_REQUEST_CODE);
        } else {
            PhotoUtils.openPic(this, CODE_GALLERY_CARD_REQUEST);
        }
    }

    /**
     * 执行回调
     *
     * @param requestCode
     * @param resultCode
     * @param data
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == RESULT_OK) {
            fileCropUri = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".jpg");
            switch (requestCode) {
                //拍照完成回调
                case CODE_CAMERA_CARD_REQUEST:
                    cropImageUri = Uri.fromFile(fileCropUri);
                    String img = cardImage.getAbsolutePath();
                    //img就是压缩后的图片
                    String imgPic = BitmapUtil.compressImageUpload(img);
                    Log.e("tb", "paths----------" + imgPic);

                    urlimg.add(0, imgPic);

                    if (null != imgPic) {
                        showPic(imgPic);
                    }
                    break;
                //访问相册完成回调
                case CODE_GALLERY_CARD_REQUEST:
                    if (AppUtils.hasSdcard()) {
                        cropImageUri = Uri.fromFile(fileCropUri);
                        String path = GetPathFromUri.getPath(this, data.getData());
                        //imgPath就是压缩后的图片
                        String imgPath = BitmapUtil.compressImageUpload(path);
                        Log.e("tb", "paths----------" + imgPath);
                        urlimg.add(0, imgPath);

                        if (null != imgPath) {
                            showPic(imgPath);
                        }
                    } else {
                        ToastUtils.showShort(this, "设备没有SD卡!");
                    }
                    break;
                default:
            }
        }
    }

    /**
     * 展示
     *
     * @param imgPic
     */
    private void showPic(String imgPic) {
        pic.add(0, imgPic);
        picAdapter.notifyDataSetChanged();
    }
}
/**
 * @author 拉莫帅 
 * @date 2023/4/01
 * @address
 * @Desc PicAdapter适配器
 */
public class PicAdapter extends RecyclerView.Adapter<PicAdapter.MyViewHolder> {

    private Context context;
    private OnItemClickListener onItemClickListener;
    private OnClickDelete onClickDelete;
    private List<String> ml;

    public PicAdapter(Context ctx, List<String> ml) {
        this.context = ctx;
        this.ml = ml;
    }

    public interface OnItemClickListener{
        void onItemClick(View view, int position);
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener){
        this.onItemClickListener = onItemClickListener;
    }

    public interface OnClickDelete{
        void myClickDelete(int pos);
    }
    public void setOnClickDelete(OnClickDelete onClickDelete) {
        this.onClickDelete = onClickDelete;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_photo, parent, false));
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {

        if(ml.get(position).equals(context.getResources().getResourceName(R.drawable.add_pic_icon))){
            ImageUtils.ImageIntDefault(context,context.getResources().getDrawable(R.drawable.add_pic_icon),holder.iv_image);
        }else{
            ImageUtils.ImageDefault(context,ml.get(position),holder.iv_image);
        }

        if(onItemClickListener!=null){
            holder.iv_image.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int position = holder.getLayoutPosition();
                    onItemClickListener.onItemClick(holder.iv_image, position);
                }
            });
        }

        if(onClickDelete!=null){
            holder.iv_delete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Log.e("tb","身份证删除-----------------------------------");
                    int position = holder.getLayoutPosition();
                    onClickDelete.myClickDelete(position);
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return (ml.size() == 0 || ml == null) ? 0 : ml.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {

        private ImageView iv_image,iv_delete;

        public MyViewHolder(View itemView) {
            super(itemView);
            iv_image = itemView.findViewById(R.id.iv_image);
            iv_delete = itemView.findViewById(R.id.iv_delete);
        }
    }
}

item_photo.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="100dp">

    <ImageView
        android:scaleType="centerCrop"
        android:id="@+id/iv_image"
        android:src="@drawable/add_pic_icon"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ImageView
        android:scaleType="fitXY"
        android:layout_gravity="right"
        android:id="@+id/iv_delete"
        android:layout_width="30dp"
        android:layout_height="28dp"
        android:src="@drawable/delete_icon" />

</FrameLayout>
/**
 * @author 拉莫帅
 * @date 2023/4/01
 * @address
 * @Desc 预览照片
 */
public class ShowImgActivity extends BaseActivity {

    private View view;
    private TextView title;
    private PhotoView iv_show;
    private String image_path;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStatusBg(1);

        title = findViewById(R.id.title);
        title.setText("预览照片");
        iv_show = findViewById(R.id.iv_show);
        image_path = getIntent().getStringExtra("image_path");
        ImageUtils.ImageDefault(this, image_path, iv_show);
    }

    @Override
    protected View addContentLayout() {
        view = getLayoutInflater().inflate(R.layout.activity_show_img, contentLayout, false);
        return view;
    }
}

activity_show_img.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white">

    <uk.co.senab.photoview.PhotoView
        android:id="@+id/iv_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />
</RelativeLayout>
______ Ending ______
结尾

关于Camera系列文章到这里就已经结束了!
节后赶紧来给大家更新了,本来五一之前就应该把连载篇,分享给大家。
基本上,关于相机也就这些东西;这里把它分享给大家,欢迎大家共同学习、留言探讨!

最后的最后,大家想要完整版的源代码,欢迎来start !
完整版源码下载地址:Android + <调用相机拍照 & 选择相册> + 数码相机

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/490682.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PyQt5桌面应用开发(6):文件对话框

本文目录 PyQt5桌面应用系列介绍QFileDialog的静态接口QFileDialog的对象接口 示例结论后记 PyQt5桌面应用系列 PyQt5桌面应用开发&#xff08;1&#xff09;&#xff1a;需求分析 PyQt5桌面应用开发&#xff08;2&#xff09;&#xff1a;事件循环 PyQt5桌面应用开发&#xff…

linux安装node_exporter

下载 Download | Prometheus 解压 tar xvzf node_exporter-1.5.0.darwin-amd64.tar.gz 解压后有三个文件&#xff0c;分别是LICENSE、node_exporter、NOTICE 将node_exporter移动到/etc下 mv mode_exporter /etc/systemd/system 创建node_exporter.service文件 touch node_exp…

基于matlab模拟雷达接收机测试信号

一、前言 本例展示了如何模拟单基地脉冲雷达的接收信号以估计目标范围。单基地雷达将发射器与接收器并置。发射器产生一个脉冲&#xff0c;该脉冲击中目标并产生接收器接收的回波。通过测量回波在时间上的位置&#xff0c;我们可以估计目标的范围。 本示例重点介绍脉冲雷达系统…

【线程安全】死锁问题及解决方案

1. 什么是死锁 比如上一次讲到 synchronized 的时候&#xff0c;一个线程&#xff0c;对同一个对象连续加锁两次&#xff0c;如果出现阻塞等待&#xff0c;代表这个锁是不可重入锁&#xff0c;这样的线程&#xff0c;也就称为死锁&#xff01; 一旦程序进入死锁了就会导致线程僵…

低代码开发重要工具:JVS列表页字段样式配置说明

列表页中&#xff0c;通常存在各种各样的样式控制&#xff0c;例如字段宽度需要可调、字段的颜色根据内容变化等&#xff0c;那么我们接下来介绍下字段的样式控制的内容以及对应的效果。 1、字段样式控制配置位置 进入列表页的 数据配置界面&#xff0c;每个字段可以有独立的配…

在外远程控制我的世界服务器 - MCSM面板【端口映射】

文章目录 概述1.MCSManager 安装2.内网穿透2.1 安装cpolar内网穿透 3. 访问公网地址4.固定公网地址4.1 保留一个二级子域名4.2 配置固定二级域名4.3 访问固定公网地址 5. 设置节点公网地址6. 固定节点公网地址6.1 保留一个固定tcp地址6.2 配置固定TCP地址 转载自远程穿透文章&a…

从零开始学习Linux运维,成为IT领域翘楚(七)

文章目录 &#x1f525;Linux下常用软件安装_JDK和Tomcat安装&#x1f525;Linux下常用软件安装_MySQL安装&#x1f525;Linux下常用软件安装_MySQL卸载 &#x1f525;Linux下常用软件安装_JDK和Tomcat安装 Jdk 安装 解压jdk安装包 tar -zxvf jdk-8u201-linux-x64.tar.gz -C/…

中国核心生态区类型及土地利用数据有哪些,如何进行获取

全国生态功能区划是在全国生态调查的基础上&#xff0c;分析区域生态特征、生态系统服务功能与生态敏感性空间分异规律&#xff0c;确定不同地域单元的主导生态功能&#xff0c;制定全国生态功能区划&#xff0c;对贯彻落实科学发展观&#xff0c;牢固树立生态文明观念&#xf…

顺序存储二叉树线索化二叉树

顺序存储二叉树&线索化二叉树 文章目录 顺序存储二叉树&线索化二叉树顺序存储二叉树介绍代码实现 线索化二叉树介绍代码实现 顺序存储二叉树 介绍 背景&#xff1a;从数据存储来看&#xff0c;数组存储方式和树的存储方式可以相互转换&#xff0c;即数组可以转换成树…

我把大厂起诉了,协商拿了2N,整理点经验心得给大家,关于离职时如何让自己利益最大化!...

离职时&#xff0c;如何让自己的利益最大化&#xff1f; 一位跟大厂仲裁&#xff0c;并通过协商拿到2n的网友分享了自己的经验心得&#xff0c;干货满满&#xff0c;下面是要点总结&#xff1a; 1.大部分裁员都是违法裁员&#xff0c;应该给2n&#xff0c;但公司不会承认&#…

排序算法 — 归并排序

文章目录 归并排序介绍从下往上的归并排序从上往下的归并排序 归并排序实现从上往下的归并排序从下往上的归并排序 归并排序的时间复杂度和稳定性归并排序时间复杂度归并排序稳定性 代码实现核心&总结 每日一道算法&#xff0c;提高脑力。第五天(时隔7天&#xff0c;终于回…

mac下用git客户端生成ssh秘钥并配置到souretree进行使用

一、使用git 生成 ssh 密钥 1、Mac 安装 git 客户端 打开终端&#xff0c;执行命令&#xff1a; $ brew install git2、执行命令 $ git config --global user.name "xxx" 你自己的名字 $ git config --global user.email "xxxxxx.com&q…

Educational-Codeforces-Round-147-Rated-for-Div-2

title: Educational Codeforces Round 147 (Rated for Div. 2) date: 2023-04-21 15:47:29 categories: AlgorithmCodeforces tags:codeforcesdiv2 Educational Codeforces Round 147 (Rated for Div. 2) A. Matching 题目大意 给你一个字符串&#xff0c;里面包含数字和?,…

Redis缓存穿透和雪崩

Redis缓存穿透和雪崩 Redis缓存的使用&#xff0c;极大的提升了应用程序的性能和效率&#xff0c;特别是数据查询方面。但同时&#xff0c;它也带来了一些问题。其中&#xff0c;最要害的问题&#xff0c;就是数据的一致性问题&#xff0c;从严格意义上讲&#xff0c;这个问题…

AI 工具合辑盘点(七)持续更新 之 AI 音频生成工具

AI 音频生成工具 想要不亲自录制&#xff0c;快速将文本转换为语音&#xff1f;AI 音频生成工具为你提供数千种语音选择&#xff0c;从“普通人”的声音到模仿演员、政治家或电影角色的合成声音&#xff0c;各种声音应有尽有 &#x1f5e3; AI 音频生成工具可用于创建商业用途…

模糊PID模糊控制(清晰化方法梯形图实现)

模糊PID的模糊化请参看下面的博客文章: 博途PLC模糊PID三角隶属度函数指令(含Matlab仿真)_plc 模糊pid_RXXW_Dor的博客-CSDN博客三角隶属度函数FC,我们采用兼容C99标准的函数返回值写法,在FB里调用会更加直观,下面给大家具体讲解代码。常规写法的隶属度函数FC可以参看下…

Python小姿势 - Python中的列表推导式

Python中的列表推导式 Python中的列表推导式是一种很好的创建列表的方式。它允许你将一个操作应用于列表中的每个元素&#xff0c;并将结果放入一个新的列表中。 例如&#xff0c;假设你有一个包含数字的列表&#xff0c;但是你想将每个数字都乘以2&#xff0c;并将结果放入一个…

第三十二章 Unity Mecanim动画系统(上)

在上一章节中&#xff0c;我们介绍了Unity的旧版动画系统&#xff0c;本章节来介绍新版的Mecanim动画系统。新版的Mecanim动画系统实际是对旧版动画系统的升级。新版的Mecanim动画系统仍然是建立在动画片段的基础上的&#xff0c;只不过它给我们提供了一个可视化的窗口来编辑动…

服务攻防-数据库安全-服务应用的安全问题以及测试流程-MysqlHadoop未授权访问RCE-漏洞复现

目录 一、服务应用的安全问题 1、配置不当——未授权访问 2、安全机制——特定安全漏洞 3、安全机制——弱口令爆破攻击 二、服务应用的安全测试思路 1、判断服务是否开放 2、判断服务类型 3、判断利用方式 三、Mysql-未授权访问-CVE-2012-2122 利用 1、漏洞概述 2、…

Detours HOOK

参考文本 如何使用Detours库进行DLL注入&#xff0c;拦截API - 知乎 (zhihu.com) 解决‘nmake‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。_nmake 不是内部或外部命令,也不是可运行的程序 或批处理文件。_AI浩的博客-CSDN博客 Detours使用方法&#xff0c;简单…