Friday, September 18, 2015

How to get date from DatePickerDialog to a fragment

Recently I had a need to use a DatePickerDialog. Of course there are many posts on this topic and many stack overflow questions. But the problem was most of them are using Activity to call to a DialogFragment which create a new DatePickerDialog. What i need was a fragment to call a DialogFragment and get the selected date back to the calling fragment. I spend several hours on this topic and found some interesting things which i would like to share. (I'm using the minimum code for simplicity)

First I created a MainActivity which will hold the fragment.

1. MainActivity.java
 public class MainActivity extends Activity {  
   @Override  
   protected void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.activity_main);  
   }  
 }  


Here is the layout of MainActivity.(activity_main.xml)

 <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">  
   <fragment  
     android:id="@+id/childFragment"  
     android:name="com.primesoft.layouttestingapp.BlankFragment"  
     android:layout_height="fill_parent"  
     android:layout_width="match_parent" />  
 </RelativeLayout>  

Then I created a fragment which will call DatePickerFragment. From now on I used comments to explain the code.

2. BlankFragment.java
 public class BlankFragment extends Fragment implements DatePickerDialog.OnDateSetListener{ // implementing OnDateSetListener  
                                           // This will listen for a date set event  
   ImageButton selectDate;  
   TextView dateToActivate;  
   public BlankFragment() {  
     // Required empty public constructor  
   }  
   @Override  
   public void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
   }  
   @Override  
   public View onCreateView(LayoutInflater inflater, ViewGroup container,  
                Bundle savedInstanceState) {  
     View view;  
     view = inflater.inflate(R.layout.fragment_blank, container, false); // inflating the layout  
     selectDate = (ImageButton)view.findViewById(R.id.SelectDate); // getting the image button in fragment_blank.xml  
     dateToActivate = (TextView) view.findViewById(R.id.selectedDate); // getting the TextView in fragment_blank.xml  
     selectDate.setOnClickListener(new View.OnClickListener() {  // setting listener for user click event  
       @Override  
       public void onClick(View v) {  
         DialogFragment newFragment = new DatePickerFragment(); // creating DialogFragment which creates DatePickerDialog  
         newFragment.setTargetFragment(BlankFragment.this,0);  // Passing this fragment DatePickerFragment.  
         // As i figured out this is the best way to keep the reference to calling activity when using FRAGMENT.  
         newFragment.show(getActivity().getFragmentManager(), "datePicker");  
       }  
     });  
     return view;  
   }  
   @Override  
   public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { // what should be done when a date is selected  
     StringBuilder sb = new StringBuilder().append(dayOfMonth).append("/").append(monthOfYear + 1);  
     String formattedDate = sb.toString();  
     dateToActivate.setText(formattedDate);  
   }  
 }  
Here is the layout for BlankFragment. (fragment_blank.xml)
 <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="com.primesoft.layouttestingapp.BlankFragment"  
   android:background="@android:color/darker_gray"  
   >  
   <ImageButton  
     android:id="@+id/SelectDate"  
     android:layout_marginTop="10dp"  
     android:layout_marginLeft="10dp"  
     android:layout_width="100dp"  
     android:layout_height="100dp"  
     android:scaleType="fitCenter"  
     android:src="@drawable/date_picker" /> <!--Use your own image here-->     
    <TextView  
     android:id="@+id/selectedDate"  
     android:layout_toRightOf="@id/SelectDate"  
     android:layout_width="120dp"  
     android:layout_height="40dp"  
     android:layout_marginLeft="10dp"  
     android:layout_marginTop="35dp"/>  
 </RelativeLayout>  
And finally here is the DialogFragment which creates DatePickerDialog.

3. DatePickerFragment.java
 public class DatePickerFragment extends DialogFragment{  
   private DatePickerDialog.OnDateSetListener dateSetListener; // listener object to get calling fragment listener  
   DatePickerDialog myDatePicker;  
   @Override  
   public Dialog onCreateDialog(Bundle savedInstanceState) {  
     // Use the current date as the default date in the picker  
     final Calendar c = Calendar.getInstance();  
     int year = c.get(Calendar.YEAR);  
     int month = c.get(Calendar.MONTH);  
     int day = c.get(Calendar.DAY_OF_MONTH);  
     dateSetListener = (DatePickerDialog.OnDateSetListener)getTargetFragment(); // getting passed fragment  
     myDatePicker = new DatePickerDialog(getActivity(), dateSetListener, year, month, day); // DatePickerDialog gets callBack listener as 2nd parameter  
     // Create a new instance of DatePickerDialog and return it  
     return myDatePicker;  
   }  
 }  

Well that's it. I have attached some screen captures here. Hope this helps someone. :-)