android自定義Dialog實(shí)現(xiàn)底部彈窗
拿到這個(gè)需求,很多人都是直接想用popWindow 實(shí)現(xiàn)薄嫡,但是這樣的效果我們完全可以根據(jù)系統(tǒng)的Dialog 自定義一個(gè)。
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle("SSS");
builder.show();
這樣就直接顯示出一個(gè)對(duì)話框,但是替蔬,這個(gè)對(duì)話框在屏幕的中間厨幻,然后相嵌,我們?nèi)ゲ榭磀ialog的源碼:
看dialog.show()里面判斷了是否正在顯示中,并沒有和根布局有關(guān)系克胳,看這個(gè)類的父類平绩。里面的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();
}
這個(gè)調(diào)用addView 進(jìn)去,我們Dialog就是這樣加進(jìn)去的漠另;
可以看到Dialog的源碼中的方法捏雌,也有onCreate( ) 他也是初始化 對(duì)話框的
/**
* 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 的實(shí)現(xiàn)類。里面有個(gè)日期彈窗的實(shí)現(xiàn)類笆搓,效果如下性湿,更多時(shí)間篩選的對(duì)話框可以看我的另一個(gè)自定義的 文章:
系統(tǒng)的效果如下:
[圖片上傳失敗...(image-ceb45e-1511342382391)]
自定義Dialog實(shí)現(xiàn)
1.創(chuàng)建一個(gè)自定義類繼承dialog類,創(chuàng)建布局满败,當(dāng)成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="自定義風(fēng)格彈窗"
/>
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
點(diǎn)擊事件調(diào)用:
SmartDialog smartDialog = new SmartDialog(DialogShowActivity.this);
smartDialog.setTitle("我是Title");
smartDialog.show();
設(shè)置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);
}
更改布局,添加數(shù)據(jù)
這里我們簡單做一個(gè)ListView
.顯示效果你會(huì)發(fā)現(xiàn)沒有完全填充算墨,這個(gè)時(shí)候宵荒,再去看我們調(diào)用Dialog 默認(rèn)的構(gòu)造函數(shù),
查看源碼净嘀。更改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;
}
如果走默認(rèn)的構(gòu)造就不顯示报咳,去SDK中找到 R.attr.dialogTheme 先找到自己對(duì)應(yīng)版本的SDK 到自己項(xiàng)目 的build.gradle 中找到
進(jìn)到自己的安裝目錄下找對(duì)于的 dialogTheme 發(fā)現(xiàn)只是定義了 類型,并沒具體定義挖藏。然后去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>
因?yàn)椴]有找到具體的定義屬性暑刃,再去搜索 Theme.Dialog 去 style 中找下 沒找到,發(fā)現(xiàn)這個(gè)文件就在 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>
我們重點(diǎn)看這個(gè)屬性: <item name="windowBackground">@drawable/panel_background</item>
在資源文件中搜索這個(gè)panel_background,打開你會(huì)發(fā)現(xiàn)是一張 .9圖片如下:
我們自己在項(xiàng)目中實(shí)現(xiàn)一個(gè)style 去重寫這個(gè)background 屬性膜眠,去覆蓋
<!--自定義對(duì)話框-->
<style name="MtStyle" parent="@style/Theme.AppCompat.Dialog">
<!-- Customize your theme here. -->
<item name="android:windowBackground">@android:color/white</item>
</style>
然后在代碼中去使用就直接多傳遞一個(gè)參數(shù)去設(shè)置:
public Smartdialog(@NonNull Context context) {
super(context,R.style.MtStyle);
}
這樣就實(shí)現(xiàn)我們要的效果岩臣,和PopWindow 一樣溜嗜,但是注意了,在一些新的版本上該效果還是有間隙架谎,這個(gè)就要去研究對(duì)應(yīng)SDK的剛才那個(gè)屬性 中的參數(shù)影響了炸宵。試了兩個(gè)版本都不行。狐树。焙压。。只有在老版本上可以抑钟,不過也給大家提供了一個(gè)思路涯曲!