Create a general class for custom Dialog in java Android

46,591

Solution 1

First create an Base DialogFragment to keep hold of the instance of the Activity. So when the Dialog is attached to the Activity , you will know the instance of the Activity which created it.

public abstract class BaseDialogFragment<T> extends DialogFragment {
        private T mActivityInstance;

        public final T getActivityInstance() {
                return mActivityInstance;
        }

        @Override
        public void onAttach(Activity activity) {
                mActivityInstance = (T) activity;
            super.onAttach(activity);
        }

        @Override
        public void onDetach() {
                super.onDetach();
                mActivityInstance = null;
        }
}

Then, create a GeneralDialogFragment which extends the BaseDialogFragment

public class GeneralDialogFragment extends BaseDialogFragment<GeneralDialogFragment.OnDialogFragmentClickListener> {

        // interface to handle the dialog click back to the Activity
        public interface OnDialogFragmentClickListener {
            public void onOkClicked(GeneralDialogFragment dialog);
            public void onCancelClicked(GeneralDialogFragment dialog);
        }

        // Create an instance of the Dialog with the input
        public static GeneralDialogFragment newInstance(String title, String message) {
            GeneralDialogFragment frag = new GeneralDialogFragment();
            Bundle args = new Bundle();
            args.putString("title", title);
            args.putString("msg", message);
            frag.setArguments(args);
            return frag;
        }
        // Create a Dialog using default AlertDialog builder , if not inflate custom view in onCreateView
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {

            return new AlertDialog.Builder(getActivity())
                .setTitle(getArguments().getString("title"))
                .setMessage(getArguments().getString("message"))
                .setCancelable(false)
                .setPositiveButton("OK",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            // Positive button clicked
                            getActivityInstance().onOkClicked(GeneralDialogFragment.this);
                        }
                    }
                )
                .setNegativeButton("Cancel",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            // negative button clicked
                            getActivityInstance().onCancelClicked(GeneralDialogFragment.this);
                        }
                    }
                )
                .create();
        }

    }

If you need to use your own custom layout for dialog,then inflate a layout in onCreateView and remove onCreateDialog . But Add the click listeners in onCreateView like i explained in onCreateDialog

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.activity_dialog, container, false);
    return view;
}

Then , In your Activity need to implement an interface to handle the action in dialog

public class TryMeActivity extends 
    FragmentActivity implements GeneralDialogFragment.OnDialogFragmentClickListener {

    @Override
        public void onOkClicked(GeneralDialogFragment dialog) {
                // do your stuff
        }

        @Override
        public void onCancelClicked(GeneralDialogFragment dialog) {
                // do your stuff
        }
}

Finally, Show the Dialog from your Activity when required, like this

    GeneralDialogFragment generalDialogFragment =
        GeneralDialogFragment.newInstance("title", "message");
    generalDialogFragment.show(getSupportFragmentManager(),"dialog");

Hope this helps. I am sure this approach is one of the optimized way, but there could be also different approaches .

Solution 2

I faced a problem like you. And all in stackoverflow does not meet what I want. So I create my own Dialog Class and it can use like AlertDialog.Builder class.

In my dialogxml.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="@drawable/drconner">

    <LinearLayout
        android:id="@+id/under"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    <TextView
        android:id="@+id/malertTitle"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:padding="5dp"
        android:textSize="25sp"
        android:textColor="#ffffff"
        android:drawablePadding="2dp"
        android:background="@color/colorPrimaryDark"
        />

    <TextView
        android:id="@+id/aleartMessage"
        android:layout_width="match_parent"
        android:layout_height="75dp"
        android:padding="5dp"
        android:textSize="18sp"
        android:textColor="@color/colorAccent"/>
    </LinearLayout>

    <LinearLayout
        android:layout_below="@+id/under"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="1dp"
        android:orientation="horizontal">

        <Button
            android:id="@+id/aleartYes"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            />

        <Button
            android:id="@+id/aleartNo"
            android:layout_marginLeft="30dp"
            android:layout_marginStart="30dp"
            android:layout_marginRight="3dp"
            android:layout_marginEnd="3dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />


    </LinearLayout>


</RelativeLayout>

For Dialog Shape I create just simple shape xml - drconner.xml

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">

    <corners android:radius="5dp"/>
    <stroke android:color="@color/colorPrimaryDark" android:width="2dp"/>


</shape>

For custom Alert I create Alear.java as follow

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;



/**
 * Created by sanyatihan on 27-Dec-16.
 */

public class Alert extends Dialog {

    private String message;
    private String title;
    private String btYesText;
    private String btNoText;
    private int icon=0;
    private View.OnClickListener btYesListener=null;
    private View.OnClickListener btNoListener=null;

    public Alert(Context context) {
        super(context);
    }

    public Alert(Context context, int themeResId) {
        super(context, themeResId);
    }

    protected Alert(Context context, boolean cancelable, OnCancelListener cancelListener) {
        super(context, cancelable, cancelListener);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.dialogxml);
        TextView tv = (TextView) findViewById(R.id.malertTitle);
        tv.setCompoundDrawablesWithIntrinsicBounds(icon,0,0,0);
        tv.setText(getTitle());
        TextView tvmessage = (TextView) findViewById(R.id.aleartMessage);
        tvmessage.setText(getMessage());
        Button btYes = (Button) findViewById(R.id.aleartYes);
        Button btNo = (Button) findViewById(R.id.aleartNo);
        btYes.setText(btYesText);
        btNo.setText(btNoText);
        btYes.setOnClickListener(btYesListener);
        btNo.setOnClickListener(btNoListener);

    }



       public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public void setIcon(int icon) {
        this.icon = icon;
    }

    public int getIcon() {
        return icon;
    }

    public void setPositveButton(String yes, View.OnClickListener onClickListener) {
        dismiss();
        this.btYesText = yes;
        this.btYesListener = onClickListener;


    }

    public void setNegativeButton(String no, View.OnClickListener onClickListener) {
        dismiss();
        this.btNoText = no;
        this.btNoListener = onClickListener;


    }
}

To use this Alert class, just simple as the use of AlertDialog.Builder class

for example :

final Alert mAlert = new Alert(this);
        mAlert.setTitle("This is Error Warning");
        mAlert.setIcon(android.R.drawable.ic_dialog_alert);
        mAlert.setMessage("Do you want to delete?");
        mAlert.setPositveButton("Yes", new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mAlert.dismiss();
                //Do want you want
            }
        });

        mAlert.setNegativeButton("No", new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mAlert.dismiss();
                //Do want you want
            }
        });

        mAlert.show();

The main thing is you should call dismiss() function in your onClick. I hope this may help to you. And let me know if this is what you want or not. You can change the layout as you want in dialogxml.xml.

Solution 3

I have been using this for some time. Calling the alert dialog inside an activity, where alertDialog is a static function in a class called Misc:

    Misc.alertDlg(this, "Confirm", "Delete the file?", "Yes", null, "Cancel",
                    (DialogInterface dialog, int which) -> {
                        if(which == Misc.BTN_POS)
                            deleteYourFile()
                    });
}

And the alert dialog function (a static function in a class called Misc:

static public void alertDlg(Context context, String title, String msg, String btnPos, String btnNeutral, String btnNeg, DialogInterface.OnClickListener ocListener) {
    Builder db = new AlertDialog.Builder(context);
    db.setTitle(title);
    db.setMessage(msg);
    if (btnPos != null) db.setPositiveButton(btnPos, ocListener);
    if (btnNeutral != null) db.setNeutralButton(btnNeutral, ocListener);
    if (btnNeg != null) db.setNegativeButton(btnNeg, ocListener);
    db.setIcon(android.R.drawable.ic_dialog_alert);
    db.show();
}

But I have just recently converted it to kotlin. Calling the alert dialog (in Kotlin):

    Misc.alertDlg(this, "Confirm", "Delete the file?", "Yes", null, "Cancel"){
        which-> if(which == Misc.BTN_POS) deleteYourFile()
    }

And the alert dialog function (a function in an object called Misc):

fun alertDlg(context: Context, title: String, msg: String, btnNeg: String?, btnNeutral: String?, btnPos: String?,
             onClickCallback: (which: Int) -> Unit) {
    val ocListener = DialogInterface.OnClickListener() {dialog, which ->
        onClickCallback(which)
    }
    val db = AlertDialog.Builder(context)
    db.setTitle(title)
    db.setMessage(msg)
    if (btnPos != null) db.setPositiveButton(btnPos, ocListener)
    if (btnNeutral != null) db.setNeutralButton(btnNeutral, ocListener)
    if (btnNeg != null) db.setNegativeButton(btnNeg, ocListener)
    db.setIcon(android.R.drawable.ic_dialog_alert)
    db.show()
}

I have also been using a similar method to show a text input dialog.

Share:
46,591

Related videos on Youtube

danigonlinea
Author by

danigonlinea

The first idea is what matters to you. Do less. Think smarter involving today. --- Frontend Developer

Updated on August 23, 2020

Comments

  • danigonlinea
    danigonlinea over 3 years

    My app shows many custom dialog like Yes/No or Accept/Cancel decissions and, while I was coding, I realized that there are so much code repeated, following the same schema.

    I want to build a general class but I don't know how to do it or, more exactly, the correct way that I have to do it(interfaces, abstract classes, inheritance, static classes, ...)

    This is my current class:

    public class DialogTwoOptions extends Dialog {
    
    TextView title_tv;
    // Button yes_btn, no_btn;
    
    public DialogTwoOptions(Context context) 
    {
        super(context);     
        setContentView(R.layout.dialogo_sino); // a simple layout with a TextView and Two Buttons
    
        title_tv = (TextView) findViewById(R.id.dialogo_titulo_sino);
        // yes_btn = (Button) findViewById(R.id.dialogo_aceptar); 
        // no_btn = (Button) findViewById(R.id.dialogo_cancelar);
    
        View v = getWindow().getDecorView();
        v.setBackgroundResource(android.R.color.transparent);
    }
    
     public void quitDialog(View v) {
         if (isShowing()) dismiss();
     }
    
     public void setTitle(String title) {
         title_tv.setText(title);
     }
    

    }

    And this is what I am doing when I need to use this class:

    final DialogTwoOptions dialog = new DialogTwoOptions(this);
    
        Button yes = (Button) dialog.findViewById(R.id.dialog_yes_btn);
        Button no = (Button) dialog.findViewById(R.id.dialog_no_btn);
    
        yes.setOnClickListener(new Button.OnClickListener() 
        {
            public void onClick(View v)     {
                dialog.dismiss();
                // Do something 
            }
        });
    
        no.setOnClickListener(new Button.OnClickListener() 
        {
            public void onClick(View v)     {
                dialog.dismiss();
                // Do something
            }
        });
    
        dialog.show();
    

    I am sure that it is improvable, but how could you do this?

    Thanks

    • danigonlinea
      danigonlinea about 10 years
      why anyone has voted -1? this is a reasonable question.
  • danigonlinea
    danigonlinea about 10 years
    but it is not a custom dialog with a custom layout. The default theme of AlertDialog is really ugly.
  • danigonlinea
    danigonlinea about 10 years
    Libin, it is really good idea but it is not general. I mean that onClick events of setPositiveButton and setNegativeButton can change. Imagine that I have 10 dialogs thats looks the same but, depends where activity/screen are, when I click "yes" it is gonna be different in all of this activities.
  • Libin
    Libin about 10 years
    Ok. I will update the answer. Are you fine with Dialog Fragment ?
  • danigonlinea
    danigonlinea about 10 years
    it is the same idea like Libin. The Onclick events can not be changed. I want to be able to change the funcionality of yes or no events, but I want the same dialog in all of them. It is like to override the onclick functions and have abstract funcionts in the class... but i don't know how to get it.
  • danigonlinea
    danigonlinea about 10 years
    Well, I would like to work < 3.0 android versions but, I thing it is gonna be ok with Dialog Fragment. I mean, sooner or later, we will have to think on > 4.0 android versions.
  • danigonlinea
    danigonlinea about 10 years
    Sorry I needed some time to eat it, it is a little hard when I saw it first time... Anyway it is a great approach that I was looking for, general code. The key is to link the onClick events to interfaces functions and have a base dialog... very wise. I don't check it yet but I will accepted it as a real answer. Thanks
  • peterh
    peterh over 8 years
    Although the code is appreciated, it should always have an accompanying explanation. This doesn't have to be long, but it is expected.
  • Cliff
    Cliff almost 8 years
    @Libin how i use it on Fragment?
  • Jainam Jhaveri
    Jainam Jhaveri over 6 years
    Oh great. This also handles the case of multiple dialogs in the same activity. Thanks:)
  • Faisal Mohammad
    Faisal Mohammad over 5 years
    the interface are not working in fragment .please any body tell me how use in fragment
  • Rafael Baptista
    Rafael Baptista almost 5 years
    This was exactly what I needed... thank you so much!
  • Abigail La'Fay
    Abigail La'Fay over 4 years
    This is what I wanted: How to push OnClickListener as parameter. Thank you!
  • AlexS
    AlexS over 4 years
    Anybody can please tell me about why or where i should use activityInstance of BaseDialog?
  • steveOS
    steveOS about 4 years
    This Worked for me, but I had to remove requestWindowFeature(Window.FEATURE_NO_TITLE); because it was producing an error
  • nikhil123
    nikhil123 about 4 years
    thanks, but there is a minor mistake in code it sould be .setMessage(getArguments().getString("msg")) instead of .setMessage(getArguments().getString("message"))