RHS.Dev
RHS.Dev

Reputation: 452

How to add custom button to material date range picker android?

How can I add a custom button to material date range picker?

I'm trying to get view of the dialog so that I can add button programmatically, but I can't get any view from the picker.

        MaterialDatePicker.Builder<Pair<Long,Long>> builder = MaterialDatePicker.Builder.dateRangePicker();
        MaterialDatePicker<Pair<Long,Long>> materialDatePicker = builder
            .setTitleText("Select Dates")
            .build();
        dateRangeTV.setOnClickListener(v -> {
            materialDatePicker.show(getSupportFragmentManager(), "DATE_PICKER");
            View root = materialDatePicker.requireView();
        });

But I'm getting error saying.

java.lang.IllegalStateException: Fragment MaterialDatePicker{e52ecfc} (40593b4f-a55a-4d6c-aa3b-2b778e721149 tag=DATE_PICKER) did not return a View from onCreateView() or this was called before onCreateView().

Upvotes: 2

Views: 2596

Answers (2)

MariosP
MariosP

Reputation: 9113

This error occurred because the materialDatePicker.show() is an asynchronous call and the MaterialDatePicker (DialogFragment) was not created yet to be able to access its root View. To avoid this error you have to listen for the DialogFragment Lifecycle using the materialDatePicker.getLifecycle() by adding a DefaultLifecycleObserver and use the override method void onStart(@NonNull LifecycleOwner owner) to access the MaterialDatePicker root View from there.

Change your code to be like the below:

MaterialDatePicker.Builder<Pair<Long,Long>> builder = MaterialDatePicker.Builder.dateRangePicker();
MaterialDatePicker<Pair<Long,Long>> materialDatePicker = builder
        .setTitleText("Select Dates")
        .build();
materialDatePicker.getLifecycle().addObserver(new DefaultLifecycleObserver()
{
    @Override
    public void onCreate(@NonNull LifecycleOwner owner) {}

    @Override
    public void onStart(@NonNull LifecycleOwner owner) {
        //in onStart of DialogFragment the View has been created so you can access the materialDatePicker.requireView()
        View root = materialDatePicker.requireView();
        //from root find the View you are interested to add your custom button
    }

    @Override
    public void onResume(@NonNull LifecycleOwner owner) {}

    @Override
    public void onDestroy(@NonNull LifecycleOwner owner) {
        //remove Lifecycle Observer
        materialDatePicker.getLifecycle().removeObserver(this);
    }
});
materialDatePicker.show(getSupportFragmentManager(), "DATE_PICKER");

Upvotes: 2

Ole Pannier
Ole Pannier

Reputation: 3683

In this example I created a class MainActivity.java and it's layout that open a custom Dialog from a Button like this:

The MainActivity.java:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private Button openDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        openDialog = findViewById(R.id.open_dialog);
        openDialog.setOnClickListener(v -> {
            Log.d(TAG, "onClick: opening dialog.");
            MyCustomDialog dialog = new MyCustomDialog();
            dialog.show(getSupportFragmentManager(), "MyCustomDialog");
        });
    }
}

Layout with the Button activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="MainActivity">

    <Button
        android:id="@+id/open_dialog"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="20sp"
        android:text="open dialog" />

</RelativeLayout>

And the MyCustomDialog.java class extends the DialogFragment to have a custom View to store the DatePicker and also other Widgets in it. (e.g. TextView):

public class MyCustomDialog extends DialogFragment {

    private static final String TAG = "MyCustomDialog";

    private TextView mActionOk, mActionCancel;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.dialog_my_custom, container, false);
        mActionCancel = view.findViewById(R.id.action_cancel);
        mActionOk = view.findViewById(R.id.action_ok);

        mActionCancel.setOnClickListener(v -> {
            Log.d(TAG, "onClick: closing dialog");
            getDialog().dismiss();
        });

        mActionOk.setOnClickListener(v -> {
            Log.d(TAG, "onClick: capturing input");
            getDialog().dismiss();
        });

        return view;
    }
}

Last but not least the XML file dialog_my_custom.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="550dp"
        android:padding="10dp">

        <TextView
            android:id="@+id/heading"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="20dp"
            android:text="This is your custom View with DatePicker"
            android:textAlignment="center"
            android:textColor="#000"
            android:textSize="18sp" />

        <DatePicker
            android:id="@+id/date_picker"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/heading"
            android:layout_centerHorizontal="true" />

        <RelativeLayout
            android:id="@+id/frame"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/date_picker">

            <TextView
                android:id="@+id/action_ok"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_alignParentBottom="true"
                android:layout_marginRight="20dp"
                android:text="OK"
                android:textColor="#33bbff"
                android:textSize="18sp" />

            <TextView
                android:id="@+id/action_cancel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentBottom="true"
                android:layout_marginRight="20dp"
                android:text="CANCEL"
                android:textColor="#33bbff"
                android:textSize="18sp" />
        </RelativeLayout>
    </RelativeLayout>
</RelativeLayout>

Don't forget to add the dependency of the support library:

implementation  "com.android.support:appcompat-v7:$supportLibVersion"

RESULT:

DataPicker in a custom View

Upvotes: 0

Related Questions