“千变万化”——神奇的Android图片规格调整器(dialog技术解析篇)

1,322 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情,希望大家多多支持,帮忙点个赞,谢谢!

前言

上篇说道,构思这个app时发现了很多平时未注意的问题,其中以Dialog弹窗为第一拦路虎,一方面是自己的技术不够成熟,一方面是自己平时未多多深入阅读。

正篇

本文将对我的dialog代码进行分析,希望可以进一步理解这里面的机制,从而实现自己需要的dialog.

代码风暴

public class PopupDialogFragment extends DialogFragment {

	public static final String ARG_LAYOUT = "arg_layout";
	public static final String ARG_GRAVITY = "arg_gravity";

	int mLayout;
	int mGravity = Gravity.CENTER;

	protected View mView;

	public static DialogFragment newInstance(int layout, int gravity) {
		PopupDialogFragment fragment = new PopupDialogFragment();
		fragment.setArgs(layout, gravity);
		return fragment;
	}

	public void setArgs(int layout, int gravity) {
		Bundle bundle = new Bundle();
		bundle.putInt(ARG_LAYOUT, layout);
		bundle.putInt(ARG_GRAVITY, gravity);
		setArguments(bundle);
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		if (getArguments() != null) {
			Bundle bundle = getArguments();
			mLayout = bundle.getInt(ARG_LAYOUT, 0);
			mGravity = bundle.getInt(ARG_GRAVITY, 0);
		}
	}

	@NonNull
	@Override
	public Dialog onCreateDialog(Bundle savedInstanceState) {
		LayoutInflater inflater = getActivity().getLayoutInflater();
		mView = inflater.inflate(mLayout, null);

		Dialog dialog = new Dialog(getActivity());
		dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);

		dialog.setContentView(mView);
		dialog.setCanceledOnTouchOutside(true);

		Window window = dialog.getWindow();
		if (window != null) {
			window.setBackgroundDrawableResource(R.color.transparent);
			WindowManager.LayoutParams wlp = window.getAttributes();
			wlp.gravity = mGravity;
			wlp.width = WindowManager.LayoutParams.MATCH_PARENT;
			wlp.height = WindowManager.LayoutParams.WRAP_CONTENT;
			window.setAttributes(wlp);
		}
		return dialog;
	}
}

首先,我先用从而构建了PopupDialogFragment类继承了 DialogFragment类,从而构建了PopupDialogFragment此类用于底部弹窗的显示父类,然后我需要一个点击后能出现选择相机和相册的弹窗,所以实现了DialogSelectImage这个具体类:

public class DialogSelectImage extends PopupDialogFragment {

    private AppCompatTextView tvCamera, tvGallery, tvCancel;

    private View.OnClickListener mOnCameraClickListener;
    private View.OnClickListener mOnGalleryClickListener;

    public DialogSelectImage setOnCameraClickListener(View.OnClickListener onCameraClickListener) {
        mOnCameraClickListener = onCameraClickListener;
        return this;
    }

    public DialogSelectImage setOnGalleryClickListener(View.OnClickListener onGalleryClickListener) {
        mOnGalleryClickListener = onGalleryClickListener;
        return this;
    }

    public static DialogSelectImage newInstance() {
        DialogSelectImage fragment = new DialogSelectImage();
        fragment.setArgs(R.layout.layout_page_dialog_select_image, Gravity.BOTTOM);
        return fragment;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog = super.onCreateDialog(savedInstanceState);

        tvCamera = mView.findViewById(R.id.tvCamera);
        tvGallery = mView.findViewById(R.id.tvGallery);
        tvCancel = mView.findViewById(R.id.tvCancel);

        tvCamera.setOnClickListener(new ThrottleClickEventAbstract() {
            @Override
            public void onThrottleClick(View v) {
                if (mOnCameraClickListener != null) {
                    mOnCameraClickListener.onClick(v);
                }
                dismiss();
            }
        });

        tvGallery.setOnClickListener(new ThrottleClickEventAbstract() {
            @Override
            public void onThrottleClick(View v) {
                if (mOnGalleryClickListener != null) {
                    mOnGalleryClickListener.onClick(v);
                }
                dismiss();
            }
        });

        tvCancel.setOnClickListener(new ThrottleClickEventAbstract() {
            @Override
            public void onThrottleClick(View v) {
                dismiss();
            }
        });
        return dialog;
    }
}

其中这个属性决定了在底部显示:fragment.setArgs(R.layout.layout_page_dialog_select_image, Gravity.BOTTOM);

而现在进入相机或相册需要权限允许,所以又设置了openCamera()方法,通过点击事件去跳转征求用户的权限允许:

if (!NetConnectUtil.checkHasValidNet(mFragmentActivity)) {
                    ToastUtil.show(mFragmentActivity, R.string.str_unable_conn_network);
                    return;
                }
                FragmentTransaction fragmentTransaction = mFragmentActivity.getSupportFragmentManager().beginTransaction();
                fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                DialogSelectImage.newInstance()
                        .setOnCameraClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                openCamera();
                            }
                        })
                        .setOnGalleryClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                openGallery();
                            }
                        }).show(fragmentTransaction, "selectAvatar");

goCamera方法实现了拍照后回调,从而获取相关地址,本处代码是外层逻辑,内部逻辑是创建文件去存手机拍照文件,但这里getBitmap方法已经丢弃,需要想新的方法去实现:

private void goCamera(){
        final String path = BizFileUtil.getAccountImgPath(mFragmentActivity, userName) + System.currentTimeMillis() + ".jpg";
        ComponentSysUtil.goCamera((ActivityBase) mFragmentActivity, path, new IOnActivityResult() {
            @Override
            public void onActivityResult(int requestCode, int resultCode, final Intent data) {
                File file = new File(path);
                if (!file.exists()) {
                    XLog.d("onActivityResult: file not exist" + file);
                    return;
                }
                Bitmap bitmap = null;
                try {
                    XLog.d("get Camera bitmap ");
                    bitmap = MediaStore.Images.Media.getBitmap(mFragmentActivity.getContentResolver(), Uri.fromFile(new File(path)));
                } catch (IOException e) {
                    XLog.e("onActivityResult: E");
                    e.printStackTrace();
                }
                if (bitmap == null) {
                    XLog.d("Camera bitmap: null ");
                    return;
                }
            }
        });
    }

这个地方获取图片的地址或者URI,而MediaStore.Images.Media.getBitmap方法容易导致OOM,所以还是推荐使用图片压缩后展示。

小结

本节讲述了相机权限获取和相关弹窗的逻辑代码,下一节将继续分析代码,讲述图片坐标变化的使用,通过坐标更好的缩放bitmap。至此,本APP仅讲述了一小部分逻辑,不过对于用户而言确实重要。