安卓 通用BaseDialog封装
一、学习准备
(1).会一点反射知识 可以看看我写的反射
(2).会一点注解知识
(3).大致看下DialogFragment
推荐一个大佬写的Android通用DialogFragment封装 (我是在大佬的基础上进行了一定程度的修改,因为大佬写的布局是确定的,我给换成了RecyclerView)
(4).运行效果
(注解一下,偷懒直接把大佬的给注释了,然后把自己写的添上去)
二、代码部分
(1).注解代码
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用.
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE}) /**用于描述类、接口(包括注解类型) 或enum声明 Class, interface (including annotation type), or enum declaration */
public @interface ActivityFragmentInject {
/**
* 布局Id
*/
int contentViewId() default -1;
/**
* 是否开启EventBus
*/
boolean isOpenEventBus() default false;
}
(2)BaseDialogFragment代码
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.widget.Toolbar;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import com.ycb.basedialog.R;
import com.ycb.basedialog.annotation.ActivityFragmentInject;
import butterknife.ButterKnife;
import butterknife.Unbinder;
/**
* Created by asus on 2019/3/30.
*/
public abstract class BaseDialogFragment extends DialogFragment {
/*
*需要能自定义的功能
* 1.可以设置dialog的宽高
* 2.可以设置dialog的背景透明度
* 3.可以设置dialog的显示位置
* 4.可以设置dialog的外边距
* 5.可以自定义dialog的布局
* 6.可以设置dialog的进出动画
*/
private int mMargin=0; //外边距
private float mDimAmout=0.5f; //背景透明度
private boolean mShowBottomEnable=true;//是否显示底部
private int mWidth,mHeight;//宽高
private int mContentViewId; //布局id
private int mAnimStyle=0; //进出动画
private boolean mOutCancel=true;//点击外部取消
private Context mContext;
private View mView;
private Unbinder unbinder;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mContext=context;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置BaseDialog的样式
setStyle(DialogFragment.STYLE_NO_TITLE, R.style.BaseDialog);
// mContentViewId = getLayoutId(); //获取布局Id
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (null==mView){
//如果是指定类型注解类型则返回true
if (getClass().isAnnotationPresent(ActivityFragmentInject.class)) {
//通过反射获取 反射对象的方法等 返回该类中与参数类型匹配的公有注解对象
ActivityFragmentInject annotation = getClass().getAnnotation(ActivityFragmentInject.class);
//获得布局id
mContentViewId = annotation.contentViewId();
} else {
//这里抛出了运行时异常
throw new RuntimeException("Class must add annotations of ActivityFragmentInitParams.class");
}
mView =inflater.inflate(mContentViewId,container,false);
}
// convertView(BaseHolder,this);
unbinder= ButterKnife.bind(this,mView);
return mView;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initView(mView,savedInstanceState,this);
}
@Override
public void onStart() {
super.onStart();
initParams();//这个方法可以写成抽象方法,在具体的dialog里面进行具体的设置 当然这里写一个通用的也很好
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
//初始化dialog
private void initParams() {
//因为dialogfragment 也是一种特殊的window
//为什么在这里获取可以看一下fragment 的生命周期
Window window = getDialog().getWindow();
if (window!=null){
WindowManager.LayoutParams params = window.getAttributes();
params.dimAmount=mDimAmout;
if (mShowBottomEnable){
params.gravity= Gravity.BOTTOM;
}
//设置width
if (mWidth==0){
params.width=getScreenWidth(mContext)-2*dp2px(mContext,mMargin);
}else {
params.width=dp2px(mContext,mWidth);
}
//设置height
if (mHeight==0){
params.height=WindowManager.LayoutParams.WRAP_CONTENT;
}else {
params.height=dp2px(mContext,mHeight);
}
//设置动画
if (mAnimStyle!=0){
window.setWindowAnimations(mAnimStyle);
}
//设置窗口的属性
window.setAttributes(params);
}
setCancelable(mOutCancel);
}
//操作dialog布局
protected abstract void initView(View mView, Bundle savedInstanceState, BaseDialogFragment dialog);
//float 区间 在0——1
public void setDimAmout(@FloatRange(from = 0 ,to = 1 ) float mDimAmout) {
this.mDimAmout = mDimAmout;
}
public void setShowBottomEnable(boolean mShowBottomEnable) {
this.mShowBottomEnable = mShowBottomEnable;
}
public void setWidth(int mWidth) {
this.mWidth = mWidth;
}
public void setHeight(int mHeight) {
this.mHeight = mHeight;
}
public void setOutCancel(boolean mOutCancel) {
this.mOutCancel = mOutCancel;
}
/**
* 获取屏幕宽度
*
* @param context
* @return
*/
public static int getScreenWidth(Context context) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
return displayMetrics.widthPixels;
}
public static int dp2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
protected void initToolbarMenu(Toolbar toolbar, TextView tvTitle, String title) {
if (tvTitle != null && title != null) {
tvTitle.setText(title);
}
if (toolbar != null) {
toolbar.setTitle("");
toolbar.setNavigationIcon(R.drawable.ic_left);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
}
}
}
(3).rvDialog代码
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import com.ycb.basedialog.R;
import com.ycb.basedialog.annotation.ActivityFragmentInject;
import java.util.ArrayList;
import butterknife.BindView;
/**
* Created by asus on 2019/3/31.
*/
@ActivityFragmentInject(contentViewId = R.layout.rv_dialog)
public class RvDialog extends BaseDialogFragment {
@BindView(R.id.iv_close)
ImageView mIvClose;
@BindView(R.id.recy)
RecyclerView mRecy;
private OnSelectListener<String> mOnSelectListener;
private ArrayList<String> mList = new ArrayList<>();
public static RvDialog newInstance(OnSelectListener<String> listener) {
RvDialog dialog = new RvDialog();
dialog.setOnSelectListener(listener);
return dialog;
}
@Override
protected void initView(View mView, Bundle savedInstanceState, BaseDialogFragment dialog) {
initData();
mIvClose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
mRecy.setAdapter(new SingeLayoutAdapter<String>(getContext(), mList, R.layout.item_affair_sel) {
@Override
protected void onBinds(BaseHolder holder, final String s, int position) {
holder.setText(R.id.tv_sel, s);
holder.getItemView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnSelectListener != null) {
//实际上这个方法OnSelectListener<String> mOnSelectListener;
//是在这里执行的 传出了String值
mOnSelectListener.onSelected(s);
}
dismiss();
}
});
}
});
mRecy.setLayoutManager(new LinearLayoutManager(getContext(),LinearLayoutManager.VERTICAL,false));
}
private void initData() {
for (int i = 0; i < 3; i++) {
mList.add("嘿哈" + i);
}
}
public void setOnSelectListener(OnSelectListener<String> mOnSelectListener) {
this.mOnSelectListener = mOnSelectListener;
}
}
这里还涉及了BaseAdapter的写法 BaseAdapter封装
(4).MainActivity里面的点击方法
public void showFriendClick(View view) {
RvDialog.newInstance(new OnSelectListener<String>() {
@Override
public void onSelected(String select) {
Toast.makeText(MainActivity.this,select,Toast.LENGTH_SHORT).show();
}
}).show(getSupportFragmentManager(),"tag");
}
三、总结部分
可以把BaseDialogFragment写的更加简洁一点,比如那个initParams可以写成抽象方法在具体的dialog里面写,毕竟使用的是RecyclerView,可以通过LayoutManageer设置各种样式,也可以在rvDialog里面有网络连接,显示接口返回的数据,做成查看聊天详情界面等都是可以的。