美文网首页自定义控件
android自定义Dialog实现底部弹窗

android自定义Dialog实现底部弹窗

作者: gogoingmonkey | 来源:发表于2017-11-22 17:19 被阅读285次

    android自定义Dialog实现底部弹窗

    拿到这个需求,很多人都是直接想用popWindow 实现,但是这样的效果我们完全可以根据系统的Dialog 自定义一个。

    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
    builder.setTitle("SSS");
    builder.show();
    

    这样就直接显示出一个对话框,但是,这个对话框在屏幕的中间,然后,我们去查看dialog的源码:
    看dialog.show()里面判断了是否正在显示中,并没有和根布局有关系,看这个类的父类。里面的show()中:

    public void show() {
        if (mShowing) {
            if (mDecor != null) {
                if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                    mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
                }
                mDecor.setVisibility(View.VISIBLE);
            }
            return;
        }
    
        mCanceled = false;
    
        if (!mCreated) {
            dispatchOnCreate(null);
        } else {
            // Fill the DecorView in on any configuration changes that
            // may have occured while it was removed from the WindowManager.
            final Configuration config = mContext.getResources().getConfiguration();
            mWindow.getDecorView().dispatchConfigurationChanged(config);
        }
    
        onStart();
        mDecor = mWindow.getDecorView();
    
        if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
            final ApplicationInfo info = mContext.getApplicationInfo();
            mWindow.setDefaultIcon(info.icon);
            mWindow.setDefaultLogo(info.logo);
            mActionBar = new WindowDecorActionBar(this);
        }
    
        WindowManager.LayoutParams l = mWindow.getAttributes();
        if ((l.softInputMode
                & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
            WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
            nl.copyFrom(l);
            nl.softInputMode |=
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
            l = nl;
        }
    
        mWindowManager.addView(mDecor, l);
        mShowing = true;
    
        sendShowMessage();
    }
    

    这个调用addView 进去,我们Dialog就是这样加进去的;
    可以看到Dialog的源码中的方法,也有onCreate( ) 他也是初始化 对话框的

    /**
     * Similar to {@link Activity#onCreate}, you should initialize your dialog
     * in this method, including calling {@link #setContentView}.
     * @param savedInstanceState If this dialog is being reinitialized after a
     *     the hosting activity was previously shut down, holds the result from
     *     the most recent call to {@link #onSaveInstanceState}, or null if this
     *     is the first time.
     */
    protected void onCreate(Bundle savedInstanceState) {
    }
    

    看Dialog 的实现类。里面有个日期弹窗的实现类,效果如下,更多时间筛选的对话框可以看我的另一个自定义的 文章:

    系统的效果如下:
    [图片上传失败...(image-ceb45e-1511342382391)]

    自定义Dialog实现

    1.创建一个自定义类继承dialog类,创建布局,当成Activity 重写onCreate()看效果

    public class SmartDialog extends Dialog {
        public SmartDialog(@NonNull Context context) {
            super(context);
        }
    
        public SmartDialog(@NonNull Context context, @StyleRes int themeResId) {
            super(context, themeResId);
        }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.smartlayout);
    }
    
    }
    

    布局文件:

    <?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="match_parent"
        android:orientation="vertical">
        <TextView
          android:layout_width="match_parent"
          android:layout_margin="10dp"
          android:layout_height="wrap_content"
          android:id="@+id/title"
          android:text="自定义风格弹窗"
            />
        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </LinearLayout>
    
    

    点击事件调用:

    SmartDialog smartDialog = new SmartDialog(DialogShowActivity.this);
    smartDialog.setTitle("我是Title");
    smartDialog.show();
    
    image.png

    设置View的 属性,让弹窗到底部

    requestWindowFeature(Window.FEATURE_NO_TITLE);//事情定需不需要加
    setContentView(R.layout.smartlayout);
    WindowManager.LayoutParams params = getWindow().getAttributes();
    if(params!=null){
        //获取属性可能失败 为空
        params.gravity= Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
        getWindow().setAttributes(params);
    }
    
    image.png

    更改布局,添加数据

    这里我们简单做一个ListView


    image.png

    .显示效果你会发现没有完全填充,这个时候,再去看我们调用Dialog 默认的构造函数,

    查看源码。更改style

    public Dialog(@NonNull Context context) {
        this(context, 0, true);
    }
    if (createContextThemeWrapper) {
        if (themeResId == 0) {
            final TypedValue outValue = new TypedValue();
            context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
            themeResId = outValue.resourceId;
        }
        mContext = new ContextThemeWrapper(context, themeResId);
    } else {
        mContext = context;
    }
    

    如果走默认的构造就不显示,去SDK中找到 R.attr.dialogTheme 先找到自己对应版本的SDK 到自己项目 的build.gradle 中找到
    进到自己的安装目录下找对于的 dialogTheme 发现只是定义了 类型,并没具体定义。然后去themes 里面找到:

     <!-- Dialog attributes -->
            <item name="dialogTheme">@style/Theme.Dialog</item>
            <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons</item>
            <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title</item>
            <item name="dialogTitleDecorLayout">@layout/dialog_title</item>
            <item name="dialogPreferredPadding">@dimen/dialog_padding</item>
    

    因为并没有找到具体的定义属性,再去搜索 Theme.Dialog 去 style 中找下 没找到,发现这个文件就在 themes 中,如下:

    
      <style name="Theme.Dialog">
            <item name="windowFrame">@null</item>
            <item name="windowTitleStyle">@style/DialogWindowTitle</item>
            <item name="windowBackground">@drawable/panel_background</item>
            <item name="windowIsFloating">true</item>
            <item name="windowContentOverlay">@null</item>
            <item name="windowAnimationStyle">@style/Animation.Dialog</item>
            <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
            <item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
            <item name="windowActionModeOverlay">true</item>
    
            <item name="colorBackgroundCacheHint">@null</item>
    
            <item name="textAppearance">@style/TextAppearance</item>
            <item name="textAppearanceInverse">@style/TextAppearance.Inverse</item>
    
            <item name="textColorPrimary">@color/primary_text_dark</item>
            <item name="textColorSecondary">@color/secondary_text_dark</item>
            <item name="textColorTertiary">@color/tertiary_text_dark</item>
            <item name="textColorPrimaryInverse">@color/primary_text_light</item>
            <item name="textColorSecondaryInverse">@color/secondary_text_light</item>
            <item name="textColorTertiaryInverse">@color/tertiary_text_light</item>
            <item name="textColorPrimaryDisableOnly">@color/primary_text_dark_disable_only</item>
            <item name="textColorPrimaryInverseDisableOnly">@color/primary_text_light_disable_only</item>
            <item name="textColorPrimaryNoDisable">@color/primary_text_dark_nodisable</item>
            <item name="textColorSecondaryNoDisable">@color/secondary_text_dark_nodisable</item>
            <item name="textColorPrimaryInverseNoDisable">@color/primary_text_light_nodisable</item>
            <item name="textColorSecondaryInverseNoDisable">@color/secondary_text_light_nodisable</item>
            <item name="textColorHint">@color/hint_foreground_dark</item>
            <item name="textColorHintInverse">@color/hint_foreground_light</item>
            <item name="textColorSearchUrl">@color/search_url_text</item>
    
            <item name="textAppearanceLarge">@style/TextAppearance.Large</item>
            <item name="textAppearanceMedium">@style/TextAppearance.Medium</item>
            <item name="textAppearanceSmall">@style/TextAppearance.Small</item>
            <item name="textAppearanceLargeInverse">@style/TextAppearance.Large.Inverse</item>
            <item name="textAppearanceMediumInverse">@style/TextAppearance.Medium.Inverse</item>
            <item name="textAppearanceSmallInverse">@style/TextAppearance.Small.Inverse</item>
    
            <item name="listPreferredItemPaddingLeft">10dip</item>
            <item name="listPreferredItemPaddingRight">10dip</item>
            <item name="listPreferredItemPaddingStart">10dip</item>
            <item name="listPreferredItemPaddingEnd">10dip</item>
    
            <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
        </style>
    

    我们重点看这个属性: <item name="windowBackground">@drawable/panel_background</item>
    在资源文件中搜索这个panel_background,打开你会发现是一张 .9图片如下:


    image.png

    我们自己在项目中实现一个style 去重写这个background 属性,去覆盖

        <!--自定义对话框-->
        <style name="MtStyle" parent="@style/Theme.AppCompat.Dialog">
            <!-- Customize your theme here. -->
            <item name="android:windowBackground">@android:color/white</item>
        </style>
    

    然后在代码中去使用就直接多传递一个参数去设置:

     public Smartdialog(@NonNull Context context) {
            super(context,R.style.MtStyle);
        }
    

    这样就实现我们要的效果,和PopWindow 一样,但是注意了,在一些新的版本上该效果还是有间隙,这个就要去研究对应SDK的刚才那个属性 中的参数影响了。试了两个版本都不行。。。。只有在老版本上可以,不过也给大家提供了一个思路!

    相关文章

      网友评论

        本文标题:android自定义Dialog实现底部弹窗

        本文链接:https://www.haomeiwen.com/subject/zkdovxtx.html