创建自定义DatePicker对话框

时间:2015-03-20 18:33:15

标签: datepicker calendar xamarin xamarin.android android-datepicker

要求:当用户点击TextView时,应打开日期选择器。选择的默认日期应为TextView中的日期。如果日期是过去的日期,则应禁用DatePicker对话框的“设置”按钮。如果可单击的TextView为空,则DatePicker中的默认日期应为今天的日期。

1 个答案:

答案 0 :(得分:1)

这是我已经解决并在此分享的方案,以帮助Xamarin社区。代码没有经过优化,仅供参考。

因此,在这种情况下我们真正需要的是访问用户正在更改DatePicker对话框上的日期的事件。只有在自己的Dialog中使用DatePicker才能进行更多控制时,才能执行此操作。在我看来,如果使用默认的DatePickerDialog,则无法访问此事件。因此,我们创建一个扩展DialogFragment类的对话框,然后在其中实现DatePicker。当用户单击TextView时,我们使用show the fragment。让我们开始吧:

这是MainActivity:

using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Java.Util;
using Java.Text;


namespace DatePickerTest
{
    [Activity(Label = "DatePickerTest", MainLauncher = true, Icon = "@drawable/icon", Theme = "@android:style/Theme.Holo.Light")]
    public class MainActivity : Activity
    {
        private string dueDate;

        private TextView dateLabel;
        private DateTime date;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);

            dateLabel = (TextView)FindViewById(Resource.Id.dateLabel);

            dueDate = dateLabel.Text;

            dateLabel.Click += delegate { ShowDialog(); };

        }

        public void ShowDialog()
        {
            var transaction = FragmentManager.BeginTransaction();
            var dialogFragment = new mDialogFragment();
            dialogFragment.Show(transaction, "dialog_fragment");
        }

        //Used for communication with the fragment
        public string GetDueDate()
        {
            return dueDate;
        }

        //Used for communication with the fragment
        public void SetDueDate(DateTime date)
        {
         //Additional check so that date isn't set in the past
            if (date < DateTime.Now.Date)
                Toast.MakeText(this, "Something went wrong! Please try again", ToastLength.Long).Show();
            else
            {
                SimpleDateFormat MdyFormat = new SimpleDateFormat("MM/dd/yyyy");
                dueDate = MdyFormat.Format(Date.Parse(date.ToString()));
                dateLabel.Text = dueDate;
            }
        }

    }
}

Main.axml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <Button
        android:id="@+id/MyButton"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/Hello" />
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:background="#FAFAFA"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/dueDateLabel"
            android:layout_height="45dp"
            android:layout_width="wrap_content"
            android:text="Due Date:"
            android:padding="15dp"
            android:textColor="#2E2E2E" />
        <TextView
            android:id="@+id/dateLabel"
            android:layout_height="45dp"
            android:layout_width="fill_parent"
            android:hint="Some Date"
            android:textColor="#2E2E2E"
            android:text="03/16/2015" />
    </LinearLayout>
</LinearLayout>

MDialogFragment.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using Java.Util;
using Java.Text;

namespace DatePickerTest
{
    public class mDialogFragment : DialogFragment
    {
        DatePicker picker;
        private MainActivity MActivity;
        private int Year, Month, Day;
        private string DueDate;
        private DateTime SelectedDueDate;
        private string tempString = "";

        public override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            //Get the instance of the MainActivity
            MActivity = (MainActivity) this.Activity;

            //Get the currently set due date
            DueDate = MActivity.GetDueDate();

            //Get instance of the Calendar
            Calendar Today = Calendar.Instance;

            //Update the class variables
            Year = Today.Get(Calendar.Year);
            Month = Today.Get(Calendar.Month);
            Day = Today.Get(Calendar.Date);
        }

        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            //Inflating the dialog layout
            var view = inflater.Inflate(Resource.Layout.MDialogLayout, container, false);
            //Finding all the views in it:
            var cancel = (Button)view.FindViewById(Resource.Id.cancel);
            var set = (Button)view.FindViewById(Resource.Id.set);
            picker = (DatePicker)view.FindViewById(Resource.Id.pickerdate);

            //DatePicker flag to make it look like the default DatePicker
            picker.CalendarViewShown = false;

            //Checking to see if current date is in the past, if YES, disable the 'Set' button
            if ((DateTime.Parse(DueDate) < DateTime.Now)) { set.Enabled = false; }

            //Initate the picker with the current due date OR today's date
            picker.Init(GetDefaultYear(), GetDefaultMonth(), GetDefaultDayOfMonth(), new onDateChangedListener((picker1, year, month, day) =>
            {
                //Getting the DatePicker value in a string
                tempString = (month + 1) + "/" + day + "/" + year;

                //Parsing the value into a variable
                SelectedDueDate = (DateTime.Parse(tempString).Date);

                //Setting the MDatePicker dialog's Title
                Dialog.SetTitle(GetDateDetails(SelectedDueDate));

                //Enable/Disalbe 'Set' button depending on the condition
                if (SelectedDueDate >= DateTime.Now.Date)
                    set.Enabled = true;
                else
                    set.Enabled = false;

            }));

            //Setting Dialog Title for the first time when it opens
            Dialog.SetTitle(GetDateDetails(DateTime.Parse(DueDate)));

            //Click function for Cancel button
            cancel.Click += delegate{Dismiss();};

            //Click function for Set button
            set.Click += (object sender, EventArgs e) =>
            {
                SetSelectedDueDate(sender, e);
            };
            return view;
        }

        private string GetDateDetails(DateTime date)
        {
            string DateDetails;
            Calendar cal = Calendar.Instance;
            SimpleDateFormat DayOfWeekFormat = new SimpleDateFormat("EEE");
            SimpleDateFormat MonthFormat = new SimpleDateFormat("MMM");

            DateDetails = DayOfWeekFormat.Format(Date.Parse(date.ToString())) + ", " + date.Day + " " + MonthFormat.Format(Date.Parse(date.ToString())) + " " + date.Year;

            return DateDetails;
        }

        private void SetSelectedDueDate(object sender, EventArgs e)
        {
            MActivity.SetDueDate(SelectedDueDate);
            Dismiss();
        }

        private int GetDefaultMonth()
        {
            //The currently set due date is in the format "MM/DD/YYYY"
            if(MActivity.GetDueDate()==null || MActivity.GetDueDate() == "")
                return Month;

            return Convert.ToInt32(MActivity.GetDueDate().Substring(0, 2)) - 1;


        }

        private int GetDefaultDayOfMonth()
        {
            if (MActivity.GetDueDate() == null || MActivity.GetDueDate() == "")
                return Day;
            return Convert.ToInt32(MActivity.GetDueDate().Substring(3, 2)); 
        }

        private int GetDefaultYear()
        {
            if (MActivity.GetDueDate() == null || MActivity.GetDueDate() == "")
                return Year;
            return Convert.ToInt32(MActivity.GetDueDate().Substring(6, 4));
        }
    }

    //We need this class and interface implementation to create and Init the DatePicker
    class onDateChangedListener : Java.Lang.Object, DatePicker.IOnDateChangedListener
    {

        Action<DatePicker, int, int, int> callback;

        public onDateChangedListener(Action<DatePicker, int, int, int> callback)
        {
            this.callback = callback;
        }

        public void OnDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth)
        {
            callback(view, year, monthOfYear, dayOfMonth);
        }
    }
}

MDialogLayout.axml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">

    <DatePicker
        android:id="@+id/pickerdate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/cancel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Cancel"
            android:layout_weight="1"
            style="?android:attr/buttonBarButtonStyle" />
        <Button
            android:id="@+id/set"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="SET"
            android:layout_weight="1"
            style="?android:attr/buttonBarButtonStyle"
            android:paddingTop="1dp" />
    </LinearLayout>
</LinearLayout>