Android 自定义DialogFragment 以及设置宽高

         DialogFragment  的特点是具有dialog 的 效果,同时又可以拥有Fragment 的生命周期,因此我们可以像管理Fragment 一样管理DialogFragment 。在 Android  中我们已经Dialog  类了,为什么还要增加一个DialogFragment 。在使用过程中DialogFragment 有事什么样子的呢,我们通过一个demo  来介绍。

         设计一个从底部弹出的弹出框,同时 弹出框中的包汗tab页。那么我们需要在弹出框布局中加入 Viewpager+ Fragment 的设计。对于复杂的 dialog 我们可以用 DialogFragment 来做。

效果如图:《Android 自定义DialogFragment 以及设置宽高》

    fragment 布局文件

<?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <LinearLayout
            android:id="@+id/contentView"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:orientation="vertical"
            android:layout_marginLeft="10dp"
            android:layout_marginBottom="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginTop="150dp"
            android:background="@drawable/bg_list"
            android:layout_alignParentBottom="true"

            >
            <com.ogaclejapan.smarttablayout.SmartTabLayout
                android:id="@+id/vp_tab"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:layout_gravity="center"
                android:background="@color/transparent"
                app:stl_indicatorAlwaysInCenter="false"
                app:stl_indicatorWithoutPadding="false"
                app:stl_indicatorInFront="false"
                app:stl_indicatorInterpolation="linear"
                app:stl_indicatorGravity="bottom"
                app:stl_indicatorColor="@color/colorAccent"
                app:stl_indicatorThickness="2dp"
                app:stl_indicatorWidth="auto"
                app:stl_indicatorCornerRadius="1px"
                app:stl_overlineColor="#4D000000"
                app:stl_overlineThickness="0dp"
                app:stl_underlineColor="@color/line"
                app:stl_underlineThickness="0dp"
                app:stl_dividerColor="@color/line"
                app:stl_dividerThickness="0dp"
                app:stl_defaultTabBackground="@android:color/transparent"
                app:stl_defaultTabTextAllCaps="false"
                app:stl_defaultTabTextColor="#ffffff"
                app:stl_defaultTabTextSize="12sp"
                app:stl_defaultTabTextMinWidth="0dp"
                app:stl_distributeEvenly="true"
                app:stl_clickable="true"
                app:stl_titleOffset="24dp"
                app:stl_drawDecorationAfterTab="false"
                />
            <TextView
                android:layout_width="match_parent"
                android:layout_height="1px"
                android:background="@color/line"
                />
            <android.support.v4.view.ViewPager
                android:id="@+id/vp"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                />

        </LinearLayout>


    </RelativeLayout>

fragment   Java文件



/**
 * @author by nate_fu on 2018/9/13.
 * @version vision 1.0
 * @Email: fuyonghui@zjhcsoft.com
 */
public class MyDialogFragment extends DialogFragment {
    private View view;
    private ViewPager viewPager;
    private SmartTabLayout vpTab;


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(DialogFragment.STYLE_NO_TITLE, R.style.CustomDialog);
    }



    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_dialog,container,false);
        initViewpage();
        return view;


    }



    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);


    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Window window = getDialog().getWindow();
        getDialog().setCanceledOnTouchOutside(true);
        window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        window.setWindowAnimations(R.style.dialogWindowAnim);
        WindowManager.LayoutParams wlp = window.getAttributes();
        wlp.dimAmount=0f;
        wlp.width = WindowManager.LayoutParams.MATCH_PARENT ;
        wlp.height =WindowManager.LayoutParams.MATCH_PARENT ;
      

        window.setAttributes(wlp);
    }

    private  void  initViewpage(){
        FragmentPagerItemAdapter adapter = new FragmentPagerItemAdapter(
                getChildFragmentManager(), FragmentPagerItems.with(getActivity())
                .add("XX",InfoFragment.class)
                .add("XX",InfoFragment.class)
                .add("XX",InfoFragment.class)
                .add("XX",InfoFragment.class)
                .add("XX",InfoFragment.class)
                .create());

        viewPager =  (ViewPager)view.findViewById(R.id.vp);
        viewPager.setAdapter(adapter);
        vpTab =(SmartTabLayout)view.findViewById(R.id.vp_tab);
        vpTab.setViewPager( viewPager);

    }



    @Override
    public void show(FragmentManager manager, String tag) {
        super.show(manager, tag);
    }

}

在MyDialogFragment 类中。我们在onCreate()方法中 执行了setStyle()方法 来设置dialog 的样式。为什么要在这里执行这个方法。我们可以从DialogFragment 的源码中找找原因

setStyle(DialogFragment.STYLE_NO_TITLE, R.style.CustomDialog);
 @Override
    public LayoutInflater onGetLayoutInflater(Bundle savedInstanceState) {
        if (!mShowsDialog) {
            return super.onGetLayoutInflater(savedInstanceState);
        }

        mDialog = onCreateDialog(savedInstanceState);

        if (mDialog != null) {
            setupDialog(mDialog, mStyle);

            return (LayoutInflater) mDialog.getContext().getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE);
        }
        return (LayoutInflater) mHost.getContext().getSystemService(
                Context.LAYOUT_INFLATER_SERVICE);
    }

在 DialogFragmet 类中有一个 onGetLayoutInflater()方法。其中 创建了Dialog 对象,同时 在setupDiaglog中设置了 style  

所以我们必须在 onGetLayoutInflater()方法前设置style  。 

  f.mContainer = container;
                            f.mView = f.performCreateView(f.performGetLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);

这是在FragmentManager 类中找到的代码,可以看到  getLayoutInflater 在 CreateView  之前,所以我们不能再 onCreateView()中设置是style  而在Fragment的生命周期 中 onCreate()在 onCreateView()之前调用。

接下来我们就是要设置我们要的dialog 的宽高 了。默认创建的 dialog  会在中间位置,两边会留边。而我们习惯在 onCreateView() 中 

Window window = getDialog().getWindow();
getDialog().setCanceledOnTouchOutside(true);
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
window.setWindowAnimations(R.style.dialogWindowAnim);
WindowManager.LayoutParams wlp = window.getAttributes();
wlp.dimAmount=0f;
wlp.width = WindowManager.LayoutParams.MATCH_PARENT ;
wlp.height =WindowManager.LayoutParams.MATCH_PARENT ;
window.setAttributes(wlp);

直接给window  设置宽高。因为在我们自定义 Dialog 是 ,new  Dialog()之后我们就是这么操作的,发现在Dialog 的时候没什么问题,可是到了这里却没有效果了,这是为什么呢。我们还是继续去源码中查看

 public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        if (!mShowsDialog) {
            return;
        }

        View view = getView();
        if (view != null) {
            if (view.getParent() != null) {
                throw new IllegalStateException(
                        "DialogFragment can not be attached to a container view");
            }
            mDialog.setContentView(view);
        }

在DialogFragment 中的 onActivityCreated  中 我们发现, mDialog.setContentView 这行代码,我们知道Android 中实现window 这个类的就是PhoneWindow 类。而 我们平时在onCreate 方法中调用的setContentView 最终调用的是 PhoneWindow 中的setContentView 方法

PhoneWindow.java 

  @Override    
public void setContentView(int layoutResID) {        
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        mLayoutInflater.inflate(layoutResID, mContentParent);
        final Callback cb = getCallback();
        if (cb != null) {
            cb.onContentChanged();
        }
    }

我们看到了 其中执行了installDecor();

private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }
       
}

这里我们看到当mDecor为null  的时候 则调用generateDecor方法完成DecorView的初始化。

而我们在结合Dialog 类来看。 

 @Override
    public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
        if (mDecor != null) {
            mWindowManager.updateViewLayout(mDecor, params);
        }
    }

当我们 给window设置Attributes 时候会回调 onWindowAttributesChanged 方法,而 在这个方法中,如果 mDecor 为null 的话是不会update我们的参数的。所以从上面我们知道 在 DialogFragment 中,dialog 窗口 被创建是在 onActivityCreate中,在此DecorView才被实例化。而我们要设置宽高的参数,必须在 DecorView实例化之后,不然是没有效果的。

以上是我的分析,如果有其他见解欢迎留言讨论。

demo 下载地址

https://download.csdn.net/download/u010324235/10698524

https://github.com/fyhsgsgssg/DialogFragment

    原文作者:Nate-fu
    原文地址: https://blog.csdn.net/u010324235/article/details/82912934
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞