安卓 通用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裏面有網絡連接,顯示接口返回的數據,做成查看聊天詳情界面等都是可以的。