正篇
本文将对我的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仅讲述了一小部分逻辑,不过对于用户而言确实重要。