Alert Dialogs with Custom Views
Tags: layoutparams, overlaylayout, alertdialogs, android
Published: 2017-05-10 22:54:21

---
title: Alert Dialogs with Custom Views
published: true
cover_image: https://s3-us-west-2.amazonaws.com/my-blogresources/my-shots/IMAG1121.jpg
description: Fixing the alert dialog issues 
tags: LayoutParams, OverlayLayout, AlertDialogs, android
---

We have been using *AlertDialogs* to alert the user as any android app does. Alert Dialogs are great and easy way to notify the user about an issue or action that needed to be perform. However there are several times, I find myself looking at lots of duplication of alert dialogs creation and management logic and inconsistent styles across various activities and fragments. To solve the issue, I started a small module using **MVP** design pattern following some good articles from the web. 

On completion the Error Control Module looks like this, 
```
|  
|--- ErrorHandler  
|--- ErrorPresenter   
|--- ErrorPresenterImpl  
|--- ErrorInteractor  
|--- ErrorInteractorImpl  
|--- ErrorCodes  
|--- ErrorResources  
|--- MaterialDialog  
|--- DialogView  
|--- DialogType  
```


*ErrorHandler* is a singleton that handles the management of creating Alert Dialogs. The MVP design pattern is implemented using the *ErrorInteractor*(Model), *DialogView*(View), *ErrorPresenter*(Presenter) interfaces. I am working on creating a android library project based on the **MVP** implementation and I will write another blog about it. 

At the end, the code snippet to create Alert Dialog looks like this, 
```Java
 errorHandlingDialog = errorHandler.createDialog(DialogType.ERROR);
 errorHandlingDialog.setErrorCode(errorCode);        
 errorHandlingDialog.showOkayButton(true, okBtnTxt);
 errorHandlingDialog.setOnConfirmListener(okBtnlistener);        
 errorHandlingDialog.showCancelButton(true, cancelBtnTxt);
 errorHandlingDialog.setOnCancelListener(cancelBtnlistener);
 errorHandlingDialog.show();
```

And the dialog was created as below, 

```Java
 private void createDialog(DialogType dialogType) {
    AlertDialog.Builder builder = new AlertDialog.Builder(mContext, R.style.error_dialog_style);

    View mDialogView = LayoutInflater.from(mContext).inflate(R.layout.material_dialog, null, false);
    mDialogTitleView = (AppCompatTextView) mDialogView.findViewById(R.id.AlertDialogTitle);
    mDialogContentView = (AppCompatTextView) mDialogView.findViewById(R.id.AlertDialogContent);
    mDialogExtraContentView = (AppCompatTextView) mDialogView.findViewById(R.id.AlertDialogExtraContent);

    mDialogCancelBtn = (AppCompatButton) mDialogView.findViewById(R.id.AlertCancelButton);
    mDialogOkayBtn = (AppCompatButton) mDialogView.findViewById(R.id.AlertConfirmButton);

    builder.setView(mDialogView);
    
    switch (dialogType) {
        case ERROR:
            builder.setCancelable(false);
            break;
        case WARNING:
            builder.setCancelable(true);
            break;
        case INFO:
            builder.setCancelable(true);
            break;
    }
    mDialog = builder.create();
    mDialog.getWindow().setLayout(500, WindowManager.LayoutParams.WRAP_CONTENT);
}
```

The layout file looks like this,
```xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@color/dialog_bgcolor"
    android:orientation="vertical"
    android:padding="@dimen/_30dp">
     <android.support.v7.widget.AppCompatTextView
        android:id="@+id/AlertDialogTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <android.support.v7.widget.AppCompatTextView
        android:id="@+idAlertDialogContent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <android.support.v7.widget.AppCompatTextView
        android:id="@+id/AlertDialogExtraContent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <android.support.v7.widget.AppCompatButton
        android:id="@+id/AlertCancelButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/error_handling_cancel_text"/>

    <android.support.v7.widget.AppCompatButton
        android:id="@+id/AlertConfirmButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/error_handling_okay_text"/>


</RelativeLayout>
```

To the obvious eyes, the code snippets do make sense and appear to be working. We thought so and it was working. It passed the Unit testing. However when we started integrating the code to the app and used it to replace the *duplicated* 'alert dialog, we started noticing a strange crash occurring. 

```
java.lang.ClassCastException: android.widget.LinearLayout$LayoutParams cannot be cast to com.android.internal.widget.ActionBarOverlayLayout$LayoutParams
```

The stack trace didn't point to any code in the app, rather to android views. We realized that we were messing up somewhere but it didn't occur to us to review the dialog creation code. 

After goofing around the app code and trying to recreate the issue, one of the developer found out the crash didn't happen until, the dialog was shown. i.e., Until ``errorHandlingDialog.show()`` was called. 

Debugging the code for further, we found out that the below line was causing the crash. 

```Java
mDialog.getWindow().setLayout(500, WindowManager.LayoutParams.WRAP_CONTENT);
```

With some help from *google*, I found out that the issue was related to incorrect usage of layout parameters and positioning. 

>  Links that were helpful: 
> 1. [Layout Parameters for Alert Dialog](http://stackoverflow.com/questions/33171114/what-layoutparams-should-be-used-in-an-alertdialog)
> 2. [Specifying Custom Dialog View Size](http://stackoverflow.com/questions/37514116/how-to-specify-correct-dialog-size-in-xml-layout-file-for-android-dialog)

I updated the code as below, 

```Java
mDialog = dialogBuilder.create();
Window window = mDialog.getWindow();
if (window != null) {
    window.setLayout(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
    window.setGravity(Gravity.CENTER);
}
```

and modified the *layout_width* and *layout_height* from *match_parent* to *wrap_content*

```xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

</RelativeLayout>
```

Now the code made more sense and I thought that I'm done. However I was presented with another surprising and weird(Since I didn't understand the code first) issue. 

```
java.lang.IllegalStateException: ActionBarView can only be used with android:layout_width="match_parent" (or fill_parent)
```

And again stack trace didn't point to the app, but this time I was ready for it. 

I realized the issue is somewhere in setting the width of the view. I wasn't using any style for alert dialogs earlier and I decided to make use of it. 

> Link that was helpful:
> [Provide valid parent theme for Alert Dialogs](https://issuetracker.google.com/issues/36931487)

I created a style as below and applied to alert dialogs. 
```xml
<style name="AppTheme.Dialog" parent="android:Theme.Light">
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowFrame">@null</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:maxWidth">500dp</item>
    <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
</style>

<style name="error_dialog_style" parent="@style/AppTheme.Dialog">

</style>

```

```Java
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext, R.style.error_dialog_style);
```

And that finally fixed the Illegal State Exception crash. Finally our app now has beautiful and uniform alert dialogs with additional benefit of reduced duplication of code. **_Hurray!!_**