1. 程式人生 > >Android 自定義Dialog無法Dismiss

Android 自定義Dialog無法Dismiss

寫在前面:

Android開發碰到了一個很奇怪的問題,同樣的自定義View的Dialog 的Code在一個專案中可以dismiss,在另一個專案中卻如何也無法dismiss,真心不知道問題在什麼地方,查閱了一下網上的資料,找到了自定義Dialog正確且標準的使用方式,在此Mark一下先。

例項程式碼

程式碼so esay,只是用來測試為什麼自定義的dialog的不能dismiss。
1.MainActivity.java

public class MainActivity extends Activity 
{

    private Dialog dialog = null;
    private
Button testBtn = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } public void initView() { testBtn = (Button) this.findViewById(R.id.button1); testBtn.setOnClickListener(new
OnClickListener(){ @Override public void onClick(View arg0) { // TODO Auto-generated method stub showCenterDialog(); } }); } public void showCenterDialog() { //dialog自定義的樣式 dialog = new
Dialog(MainActivity.this,R.style.MyDialog); dialog.setContentView(R.drawable.dialog_layout); dialog.setCancelable(false); View vv = LayoutInflater.from(this).inflate(R.drawable.dialog_layout,null); Button closeBtn = (Button) vv.findViewById(R.id.closeBtn); closeBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub dialog.dismiss(); } }); dialog.show(); } }

2.dialog_layout_xml 測試用佈局檔案

<?xml version = "1.0" encoding="utf-8" ?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/TopRel"
    android:layout_width="200dp"
    android:layout_height="150dp"
    >
    <Button
        android:layout_width="150dp"
        android:layout_height="100dp"
        android:text="測試用按鈕"
        android:textSize="19sp"
        android:id="@+id/closeBtn"
        android:layout_centerInParent="true"
        ></Button>
</RelativeLayout>

3.自定義Dialog採用的樣式 Style
(style.xml中新增自定義的樣式)


    <style name="MyDialog" parent="@android:Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:backgroundDimEnabled">false</item>
        <item name="android:windowBackground">@color/transparent</item><!--背景透明-->


    </style>

問題分析

現象:現在點選 Dialog中出現的 ”測試用按鈕“,dialog就是無法dismiss。
分析:除錯發現,無論你如何點選”測試用按鈕“,就是無法觸發它的點選響應事件,感覺Dialog在呼叫setContentView()後顯示在介面的Button和

View vv = LayoutInflater.from(this).inflate(R.drawable.dialog_layout,null);

        Button closeBtn = (Button) vv.findViewById(R.id.closeBtn);

上面註冊的Button不是同一個Button。
查閱了一下資料,根據有些網友的說法,Dialog在onCreate()的時候,會重新載入佈局檔案,即是呼叫下面的程式碼:


dialog.setContentView(R.drawable.dialog_layout);

重新載入過佈局檔案的Dialog的Button Id跟註冊監聽事件時的Button Id不是同一個Id,因此,不會有按鍵響應。

解決方法

考慮到Dialog在呼叫setContentView()之後,已經重新載入過佈局,則下面的程式碼:

View vv = dialog.getWindow().getDecorView();

可以捕捉到已經載入到Dialog的佈局元素,即是將inflate載入的佈局程式碼替換為上面列出的程式碼,即可解決自定義樣式的Dialog無法Dismiss的問題。

View vv = LayoutInflater.from(this).inflate(R.drawable.dialog_layout,null);

進一步探索

至於為什麼使用getWindow().getDecorView()可以解決這種bug,可以參看老羅的部落格Android應用程式視窗(Activity)的檢視物件(View)的建立過程分析以及decorView和window之間的層級及關係。兩篇部落格比較深入的解析了Activity和View的關係,帶你從原始碼的層次理解Android的View佈局,應該為必看文章,mark一下。