底部弹出式菜单,可以使用PopupWindow 来做,也可以用自定义View来做。当然这里采用DialogFragment来做。

DialogFragment是3.0之后引入的,使用DialogFragment,我们不用管理其生命周期,并且可以作为组件重用。比如当屏幕旋转的时候,如果PopupWindow没有dismiss掉,会抛出异常。AlertDialog则会消失,DialogFragment创建的对话框则不受影响。

概述

使用DialogFragment,需要重写onCreateView或者onCreateDialog方法,前者是通过layout下的自定义布局来创建对话框,后者则是用AlertDialog或者Dialog创建出Dialog,适用于创建简单的对话框。

如果同时复写onCreateView和onCreateDialog会报如下异常,

AndroidRuntimeException: requestFeature() must be called before adding content

通过查看DialogFragment的源码,我们发现会有下面的注释

     * This method will be called after {@link #onCreate(Bundle)} and     * before {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.  The     * default implementation simply instantiates and returns a {@link Dialog}     * class.

那这句异常的意思是什么呢?具体可以参见stackoverflow:
http://stackoverflow.com/questions/13257038/custom-layout-for-dialogfragment-oncreateview-vs-oncreatedialog/15602648#15602648
http://stackoverflow.com/questions/27045451/dialog-fragment-is-crashing

You can override both (in fact the DialogFragment says so), the problem comes when you try to inflate the view after having already creating the dialog view. You can still do other things in onCreateView, like use the savedInstanceState, without causing the exception.

可以看出onCreateDialog优先于onCreateView执行,但是我们依然可以在onCreateView中做状态保存的操作。

onCreateDialog

这个回调方法是DialogFragment独有的,通过它返回的是一个Dialog对象,这个对象就会被显示到屏幕上。

AlertDialog.Builder builder = new AlertDialog.Builder(this);                builder.setView(R.layout.dialog_fragment_item);                builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                        dialog.dismiss();                    }                });                builder.show();

在Activity中我们通过show() 或者commit()方法都可以将对话框展示出来

 BottomDialogFragment bottomDialogFragment = (BottomDialogFragment) Fragment.instantiate(this, BottomDialogFragment.class.getName());                getSupportFragmentManager().beginTransaction().add(bottomDialogFragment, "bottomDialogFragment").commitAllowingStateLoss();                break;

或者:

BottomDialogFragment dialog = new BottomDialogFragment();          dialog.show(getSupportFragmentManager(), "dialog");

onCreateView

通过onCreateView自定义布局展示对话框。生命周期同Fragment,可以通过show() 或者commit()方法将其展示出来。

布局文件:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:orientation="horizontal">    <ImageView  android:id="@android:id/icon" android:layout_width="50dp" android:layout_height="match_parent" android:adjustViewBounds="true" android:padding="5dp" android:src="@mipmap/ic_launcher" />    <TextView  android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="marquee" android:padding="10dp" android:singleLine="true" android:text="@string/image_content" android:textSize="15sp" /></LinearLayout>

java代码,继承DialogFragment,重写onCreateView方法

@Nullable    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        if (null == fragmentRoot) {            fragmentRoot = inflater.inflate(R.layout.dialog_fragment_item, container, false);        }        if (null != fragmentRoot) {            ViewGroup parent = (ViewGroup) fragmentRoot.getParent();            if (null != parent)                parent.removeAllViews();        }        return fragmentRoot;    }

去标题

  • getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);

  • 在style.xml中使用NoActionBar属性。

 <item name="windowActionBar">false</item>        <item name="windowNoTitle">true</item>

位置控制

像很多UI都采用底部弹出的效果,比如展示菜单,分享等操作,我们都知道Dialog是展示在屏幕中央,而且宽度是没有填充屏幕的,其实我们只要给dialog设置一个LayoutParams 即可。

ps:

 @NonNull    @Override    public Dialog onCreateDialog(Bundle savedInstanceState) {        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.BottomDialog);        LayoutInflater inflater = getActivity().getLayoutInflater();        View view = inflater.inflate(R.layout.dialog_fragment_layout, null);        initView(view);        builder.setView(view);        dialog = builder.create();        dialog.setCanceledOnTouchOutside(true);        // 设置宽度为屏宽、靠近屏幕底部。        Window window = dialog.getWindow();        WindowManager.LayoutParams wlp = window.getAttributes();        wlp.gravity = Gravity.BOTTOM;        wlp.width = WindowManager.LayoutParams.MATCH_PARENT;        window.setAttributes(wlp);        return dialog;    }

这里涉及到了一个theme,主要是设置动画的,dialog自下而上的弹出来

<!--屏幕底部的dialog-->    <style name="BottomDialog" parent="AppTheme"> <item name="android:windowNoTitle">true</item> <item name="android:windowIsFloating">true</item> <!-- Dialog进入及退出动画 --> <item name="android:windowAnimationStyle">@style/BottomToTopAnim</item> </style>
<style name="BottomToTopAnim" parent="android:Animation"> <item name="@android:windowEnterAnimation">@anim/bottomview_anim_enter</item> <item name="@android:windowExitAnimation">@anim/bottomview_anim_exit</item> </style>

enter动画:

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" >    <translate  android:duration="500" android:fromYDelta="100%p" /></set>

exit动画:

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" >    <translate  android:duration="500" android:toYDelta="100%p" /></set>

LayoutParams

上面是通过设置了Gravity.BOTTOM来实现在屏幕下方显示。默认情况下DialogFragment是现实在屏幕中间的,我们如果想要改变其现实位置,同理,也可以用此方法。

比如,在屏幕中间靠上显示,可以这样设置。

Window window = dialog.getWindow();        WindowManager.LayoutParams wlp = window.getAttributes();        wlp.gravity = Gravity.TOP;        // 这里是坐标值,即离屏幕上方距离是100        wlp.y = 100;        wlp.width = WindowManager.LayoutParams.MATCH_PARENT;        window.setAttributes(wlp);

实例demo:
BottomDialogFragment @[Github]

更多相关文章

  1. Android中service的使用
  2. view中显示部分区域
  3. adb 5037 端口占用解决
  4. Android的警示对话框AlertDialog简单使用实例(附Demo)
  5. Android(安卓)2.3 CTS测试修改测试结果和调试方法
  6. android 唯一识别码笔记
  7. Activity和Fragment之间的数据通信
  8. Android中两种设置全屏或者无标题的方法
  9. *.android.com上不去的解决方法

随机推荐

  1. android 电容屏(二):驱动调试之基本概念篇
  2. Android(安卓)SDK 2.2 和ADT插件下载
  3. 自定义ListView中的分割线
  4. android 的各种manager
  5. android 开发 解码gif图片,获取每帧bitmap
  6. Android中显示在线PDF
  7. Android中shape的使用
  8. android listviewListview中的button点击
  9. 转载:android 各种xml资源的引用方式
  10. android:layout_alignParentRight