Merge pull request #15 from dotnet/datepicker
Implement basic DatePicker properties
This commit is contained in:
Коммит
3d81b8fcdc
|
@ -93,15 +93,15 @@ Here you find a list of all controls with their (public) APIs and their status.
|
|||
| ----|:-------:|:---:|:-----:|
|
||||
| BackgroundColor | ✅ | ✅ | ✅ |
|
||||
| CharacterSpacing | ⚠️ | ⚠️ | ⚠️ |
|
||||
| Date | ⚠️ | ⚠️ | ⚠️ |
|
||||
| Date | ✅ | ✅ | ✅ |
|
||||
| DateSelected | ⚠️ | ⚠️ | ⚠️ |
|
||||
| FontAttributes | ⚠️ | ⚠️ | ⚠️ |
|
||||
| FontFamily | ⚠️ | ⚠️ | ⚠️ |
|
||||
| FontSize | ⚠️ | ⚠️ | ⚠️ |
|
||||
| Format | ⚠️ | ⚠️ | ⚠️ |
|
||||
| MaximumDate | ⚠️ | ⚠️ | ⚠️ |
|
||||
| MinimumDate | ⚠️ | ⚠️ | ⚠️ |
|
||||
| TextColor | ⚠️ | ⚠️ | ⚠️ |
|
||||
| MaximumDate | ✅ | ✅ | ✅ |
|
||||
| MinimumDate | ✅ | ✅ | ✅ |
|
||||
| TextColor | ✅ | ✅ | ✅ |
|
||||
|
||||
**Features**
|
||||
| Feature | Description |
|
||||
|
|
|
@ -46,7 +46,10 @@
|
|||
VisualType="Cupertino"
|
||||
Text="CheckBox"/>
|
||||
<graphics:DatePicker
|
||||
VisualType="Cupertino"/>
|
||||
VisualType="Cupertino"
|
||||
MinimumDate="01/01/2021"
|
||||
MaximumDate="12/31/2021"
|
||||
Date="01/02/2021"/>
|
||||
<graphics:Editor
|
||||
VisualType="Cupertino"
|
||||
Placeholder="Placeholder"/>
|
||||
|
@ -90,7 +93,10 @@
|
|||
IsChecked="True"
|
||||
Text="CheckBox"/>
|
||||
<graphics:DatePicker
|
||||
VisualType="Fluent"/>
|
||||
VisualType="Fluent"
|
||||
MinimumDate="01/01/2021"
|
||||
MaximumDate="12/31/2021"
|
||||
Date="01/02/2021"/>
|
||||
<graphics:Editor
|
||||
VisualType="Fluent"
|
||||
Placeholder="Placeholder"/>
|
||||
|
@ -132,7 +138,10 @@
|
|||
<graphics:CheckBox
|
||||
VisualType="Material"/>
|
||||
<graphics:DatePicker
|
||||
VisualType="Material"/>
|
||||
VisualType="Material"
|
||||
MinimumDate="01/01/2021"
|
||||
MaximumDate="12/31/2021"
|
||||
Date="01/02/2021"/>
|
||||
<graphics:Editor
|
||||
VisualType="Material"
|
||||
Placeholder="Placeholder"/>
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace GraphicsControls
|
|||
{
|
||||
canvas.SaveState();
|
||||
|
||||
canvas.FontColor = ColorHelper.GetGraphicsColor(Material.Color.Black, Material.Color.White);
|
||||
canvas.FontColor = TextColor.ToGraphicsColor(Material.Color.Black, Material.Color.White);
|
||||
canvas.FontSize = 14f;
|
||||
|
||||
float margin = 8f;
|
||||
|
@ -57,7 +57,7 @@ namespace GraphicsControls
|
|||
var height = dirtyRect.Height;
|
||||
var width = dirtyRect.Width;
|
||||
|
||||
canvas.DrawString(Date.ToShortDateString(), x, 0, width - margin, height, HorizontalAlignment.Left, VerticalAlignment.Center);
|
||||
canvas.DrawString(GetDate().ToShortDateString(), x, 0, width - margin, height, HorizontalAlignment.Left, VerticalAlignment.Center);
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
|
|
|
@ -82,9 +82,9 @@ namespace GraphicsControls
|
|||
canvas.SaveState();
|
||||
|
||||
if (IsEnabled)
|
||||
canvas.FontColor = ColorHelper.GetGraphicsColor(Fluent.Color.Foreground.Black, Fluent.Color.Foreground.White);
|
||||
canvas.FontColor = TextColor.ToGraphicsColor(Fluent.Color.Foreground.Black, Fluent.Color.Foreground.White);
|
||||
else
|
||||
canvas.FontColor = ColorHelper.GetGraphicsColor(Fluent.Color.Foreground.NeutralTertiary, Fluent.Color.Foreground.White);
|
||||
canvas.FontColor = TextColor.ToGraphicsColor(Fluent.Color.Foreground.NeutralTertiary, Fluent.Color.Foreground.White);
|
||||
|
||||
canvas.FontSize = 14f;
|
||||
|
||||
|
@ -95,7 +95,7 @@ namespace GraphicsControls
|
|||
var height = FluentDatePickerHeight;
|
||||
var width = dirtyRect.Width;
|
||||
|
||||
canvas.DrawString(Date.ToShortDateString(), x, 0, width - margin, height, HorizontalAlignment.Left, VerticalAlignment.Center);
|
||||
canvas.DrawString(GetDate().ToShortDateString(), x, 0, width - margin, height, HorizontalAlignment.Left, VerticalAlignment.Center);
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace GraphicsControls
|
|||
{
|
||||
canvas.SaveState();
|
||||
|
||||
canvas.FontColor = ColorHelper.GetGraphicsColor(Material.Color.Dark, Material.Color.Light);
|
||||
canvas.FontColor = TextColor.ToGraphicsColor(Material.Color.Dark, Material.Color.Light);
|
||||
canvas.FontSize = 16f;
|
||||
|
||||
float margin = 12f;
|
||||
|
@ -99,7 +99,7 @@ namespace GraphicsControls
|
|||
var height = dirtyRect.Height;
|
||||
var width = dirtyRect.Width;
|
||||
|
||||
canvas.DrawString(Date.ToShortDateString(), x, 22f, width - margin, height, horizontalAlignment, VerticalAlignment.Top);
|
||||
canvas.DrawString(GetDate().ToShortDateString(), x, 22f, width - margin, height, horizontalAlignment, VerticalAlignment.Top);
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Graphics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using GraphicsControls.Effects;
|
||||
using Xamarin.Forms;
|
||||
using XColor = Xamarin.Forms.Color;
|
||||
|
||||
namespace GraphicsControls
|
||||
{
|
||||
public partial class DatePicker : GraphicsVisualView
|
||||
{
|
||||
DatePickerDialogRoutingEffect _datePickerEffect;
|
||||
|
||||
public static class Layers
|
||||
{
|
||||
public const string Background = "DatePicker.Layers.Background";
|
||||
|
@ -30,6 +35,9 @@ namespace GraphicsControls
|
|||
BindableProperty.Create(nameof(MaximumDate), typeof(DateTime), typeof(DatePicker), new DateTime(2100, 12, 31),
|
||||
validateValue: ValidateMaximumDate, coerceValue: CoerceMaximumDate);
|
||||
|
||||
public static readonly BindableProperty TextColorProperty =
|
||||
BindableProperty.Create(nameof(TextColor), typeof(XColor), typeof(TimePicker), XColor.Default);
|
||||
|
||||
static object CoerceDate(BindableObject bindable, object value)
|
||||
{
|
||||
var picker = (DatePicker)bindable;
|
||||
|
@ -98,6 +106,12 @@ namespace GraphicsControls
|
|||
set { SetValue(MinimumDateProperty, value); }
|
||||
}
|
||||
|
||||
public XColor TextColor
|
||||
{
|
||||
get { return (XColor)GetValue(TextColorProperty); }
|
||||
set { SetValue(TextColorProperty, value); }
|
||||
}
|
||||
|
||||
public List<string> DatePickerLayers = new List<string>
|
||||
{
|
||||
Layers.Background,
|
||||
|
@ -126,6 +140,18 @@ namespace GraphicsControls
|
|||
HeightRequest = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
_datePickerEffect = new DatePickerDialogRoutingEffect();
|
||||
|
||||
Effects.Add(_datePickerEffect);
|
||||
|
||||
UpdateMaximumDate();
|
||||
UpdateMinimumDate();
|
||||
}
|
||||
|
||||
public override void Unload()
|
||||
{
|
||||
Effects.Remove(_datePickerEffect);
|
||||
}
|
||||
|
||||
public override List<string> GraphicsLayers =>
|
||||
|
@ -153,6 +179,16 @@ namespace GraphicsControls
|
|||
}
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
base.OnPropertyChanged(propertyName);
|
||||
|
||||
if (propertyName == MaximumDateProperty.PropertyName)
|
||||
UpdateMaximumDate();
|
||||
else if (propertyName == MinimumDateProperty.PropertyName)
|
||||
UpdateMinimumDate();
|
||||
}
|
||||
|
||||
protected virtual void DrawDatePickerBackground(ICanvas canvas, RectangleF dirtyRect)
|
||||
{
|
||||
switch (VisualType)
|
||||
|
@ -223,5 +259,25 @@ namespace GraphicsControls
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateMaximumDate()
|
||||
{
|
||||
DatePickerDialog.SetMaximumDate(this, MaximumDate);
|
||||
}
|
||||
|
||||
void UpdateMinimumDate()
|
||||
{
|
||||
DatePickerDialog.SetMinimumDate(this, MinimumDate);
|
||||
}
|
||||
|
||||
DateTime GetDate()
|
||||
{
|
||||
var date = DatePickerDialog.GetDate(this);
|
||||
|
||||
if (date == default)
|
||||
return MinimumDate;
|
||||
|
||||
return date;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using Android.Views;
|
||||
using GraphicsControls.Effects;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using static Android.Views.View;
|
||||
using ADatePickerDialog = Android.App.DatePickerDialog;
|
||||
using AView = Android.Views.View;
|
||||
|
||||
[assembly: ExportEffect(typeof(DatePickerDialogPlatformEffect), nameof(DatePickerDialog))]
|
||||
namespace GraphicsControls.Effects
|
||||
{
|
||||
public class DatePickerDialogPlatformEffect : PlatformEffect
|
||||
{
|
||||
AView _view;
|
||||
ADatePickerDialog _dialog;
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
_view = Control ?? Container;
|
||||
|
||||
_view.Touch += OnTouch;
|
||||
}
|
||||
|
||||
protected override void OnDetached()
|
||||
{
|
||||
var renderer = Container as IVisualElementRenderer;
|
||||
|
||||
if (_view != null)
|
||||
_view.Touch -= OnTouch;
|
||||
|
||||
if (_dialog != null)
|
||||
{
|
||||
_dialog.Dispose();
|
||||
_dialog = null;
|
||||
}
|
||||
_view = null;
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(e);
|
||||
|
||||
if (e.PropertyName == DatePickerDialog.MaximumDateProperty.PropertyName)
|
||||
UpdateMaximumDate();
|
||||
else if (e.PropertyName == DatePickerDialog.MinimumDateProperty.PropertyName)
|
||||
UpdateMinimumDate();
|
||||
}
|
||||
|
||||
void OnTouch(object sender, TouchEventArgs e)
|
||||
{
|
||||
if (e.Event.Action != MotionEventActions.Up)
|
||||
return;
|
||||
|
||||
if (_dialog != null)
|
||||
_dialog.Dispose();
|
||||
|
||||
CreateDialog();
|
||||
UpdateMinimumDate();
|
||||
UpdateMaximumDate();
|
||||
|
||||
_dialog.CancelEvent += OnCancelButtonClicked;
|
||||
|
||||
_dialog.Show();
|
||||
}
|
||||
|
||||
void CreateDialog()
|
||||
{
|
||||
var date = DatePickerDialog.GetDate(Element);
|
||||
|
||||
_dialog = new ADatePickerDialog(_view.Context, (o, e) =>
|
||||
{
|
||||
DatePickerDialog.SetDate(Element, e.Date);
|
||||
_view.ClearFocus();
|
||||
_dialog.CancelEvent -= OnCancelButtonClicked;
|
||||
|
||||
_dialog = null;
|
||||
}, date.Year, date.Month - 1, date.Day);
|
||||
|
||||
_dialog.SetCanceledOnTouchOutside(true);
|
||||
}
|
||||
|
||||
void OnCancelButtonClicked(object sender, EventArgs e)
|
||||
{
|
||||
_view.ClearFocus();
|
||||
}
|
||||
|
||||
void UpdateMaximumDate()
|
||||
{
|
||||
if (_dialog != null)
|
||||
_dialog.DatePicker.MaxDate = (long)DatePickerDialog.GetMaximumDate(Element).ToUniversalTime().Subtract(DateTime.MinValue.AddYears(1969)).TotalMilliseconds;
|
||||
}
|
||||
|
||||
void UpdateMinimumDate()
|
||||
{
|
||||
if (_dialog != null)
|
||||
_dialog.DatePicker.MinDate = (long)DatePickerDialog.GetMinimumDate(Element).ToUniversalTime().Subtract(DateTime.MinValue.AddYears(1969)).TotalMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
using System.ComponentModel;
|
||||
using CoreGraphics;
|
||||
using Foundation;
|
||||
using GraphicsControls.Effects;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportEffect(typeof(DatePickerDialogPlatformEffect), nameof(DatePickerDialog))]
|
||||
namespace GraphicsControls.Effects
|
||||
{
|
||||
public class DatePickerDialogPlatformEffect : PlatformEffect
|
||||
{
|
||||
UIView _view;
|
||||
UIDatePicker _picker;
|
||||
NoCaretField _entry;
|
||||
NSDate _preSelectedDate;
|
||||
|
||||
protected override void OnAttached()
|
||||
{
|
||||
_view = Control ?? Container;
|
||||
|
||||
CreatePicker();
|
||||
UpdateDate();
|
||||
UpdateMaximumDate();
|
||||
UpdateMinimumDate();
|
||||
}
|
||||
|
||||
protected override void OnDetached()
|
||||
{
|
||||
_entry.RemoveFromSuperview();
|
||||
_entry.Dispose();
|
||||
_picker.Dispose();
|
||||
_preSelectedDate.Dispose();
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(e);
|
||||
|
||||
if (e.PropertyName == DatePickerDialog.DateProperty.PropertyName)
|
||||
UpdateDate();
|
||||
else if (e.PropertyName == DatePickerDialog.MaximumDateProperty.PropertyName)
|
||||
UpdateMaximumDate();
|
||||
else if (e.PropertyName == DatePickerDialog.MinimumDateProperty.PropertyName)
|
||||
UpdateMinimumDate();
|
||||
}
|
||||
|
||||
void CreatePicker()
|
||||
{
|
||||
_entry = new NoCaretField
|
||||
{
|
||||
BorderStyle = UITextBorderStyle.None,
|
||||
BackgroundColor = UIColor.Clear
|
||||
};
|
||||
|
||||
_view.AddSubview(_entry);
|
||||
|
||||
_entry.TranslatesAutoresizingMaskIntoConstraints = false;
|
||||
|
||||
_entry.TopAnchor.ConstraintEqualTo(_view.TopAnchor).Active = true;
|
||||
_entry.LeftAnchor.ConstraintEqualTo(_view.LeftAnchor).Active = true;
|
||||
_entry.BottomAnchor.ConstraintEqualTo(_view.BottomAnchor).Active = true;
|
||||
_entry.RightAnchor.ConstraintEqualTo(_view.RightAnchor).Active = true;
|
||||
_entry.WidthAnchor.ConstraintEqualTo(_view.WidthAnchor).Active = true;
|
||||
_entry.HeightAnchor.ConstraintEqualTo(_view.HeightAnchor).Active = true;
|
||||
|
||||
_view.UserInteractionEnabled = true;
|
||||
_view.SendSubviewToBack(_entry);
|
||||
|
||||
_picker = new UIDatePicker { Mode = UIDatePickerMode.Date, TimeZone = new Foundation.NSTimeZone("UTC") };
|
||||
|
||||
if (UIDevice.CurrentDevice.CheckSystemVersion(14, 0))
|
||||
{
|
||||
_picker.PreferredDatePickerStyle = UIDatePickerStyle.Wheels;
|
||||
}
|
||||
|
||||
var width = UIScreen.MainScreen.Bounds.Width;
|
||||
var toolbar = new UIToolbar(new CGRect(0, 0, (float)width, 44)) { BarStyle = UIBarStyle.Default, Translucent = true };
|
||||
|
||||
var cancelButton = new UIBarButtonItem(UIBarButtonSystemItem.Cancel, (o, e) =>
|
||||
{
|
||||
_entry.ResignFirstResponder();
|
||||
_picker.Date = _preSelectedDate;
|
||||
});
|
||||
|
||||
var spacer = new UIBarButtonItem(UIBarButtonSystemItem.FlexibleSpace);
|
||||
|
||||
var doneButton = new UIBarButtonItem(UIBarButtonSystemItem.Done, (o, a) =>
|
||||
{
|
||||
_entry.ResignFirstResponder();
|
||||
Done();
|
||||
});
|
||||
|
||||
toolbar.SetItems(new[] { cancelButton, spacer, doneButton }, false);
|
||||
|
||||
_entry.InputView = _picker;
|
||||
_entry.InputAccessoryView = toolbar;
|
||||
}
|
||||
|
||||
void UpdateDate()
|
||||
{
|
||||
var date = DatePickerDialog.GetDate(Element).ToNSDate();
|
||||
_picker.SetDate(date, false);
|
||||
_preSelectedDate = date;
|
||||
}
|
||||
|
||||
void UpdateMaximumDate()
|
||||
{
|
||||
_picker.MaximumDate = DatePickerDialog.GetMaximumDate(Element).ToNSDate();
|
||||
}
|
||||
|
||||
void UpdateMinimumDate()
|
||||
{
|
||||
_picker.MinimumDate = DatePickerDialog.GetMinimumDate(Element).ToNSDate();
|
||||
}
|
||||
|
||||
void Done()
|
||||
{
|
||||
var date = _picker.Date.ToDateTime().Date;
|
||||
DatePickerDialog.SetDate(Element, date);
|
||||
_preSelectedDate = _picker.Date;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace GraphicsControls.Effects
|
||||
{
|
||||
public class DatePickerDialog
|
||||
{
|
||||
public static readonly BindableProperty DateProperty =
|
||||
BindableProperty.CreateAttached("Date", typeof(DateTime), typeof(DatePickerDialog), default(DateTime), defaultBindingMode: BindingMode.TwoWay);
|
||||
|
||||
public static void SetDate(BindableObject view, DateTime value)
|
||||
{
|
||||
view.SetValue(DateProperty, value);
|
||||
}
|
||||
|
||||
public static DateTime GetDate(BindableObject view)
|
||||
{
|
||||
return (DateTime)view.GetValue(DateProperty);
|
||||
}
|
||||
|
||||
public static readonly BindableProperty MaximumDateProperty =
|
||||
BindableProperty.CreateAttached("MaximumDate", typeof(DateTime), typeof(DatePickerDialog), new DateTime(2100, 12, 31));
|
||||
|
||||
|
||||
public static void SetMaximumDate(BindableObject view, DateTime value)
|
||||
{
|
||||
view.SetValue(MaximumDateProperty, value);
|
||||
}
|
||||
|
||||
public static DateTime GetMaximumDate(BindableObject view)
|
||||
{
|
||||
return (DateTime)view.GetValue(MaximumDateProperty);
|
||||
}
|
||||
|
||||
public static readonly BindableProperty MinimumDateProperty =
|
||||
BindableProperty.CreateAttached("MinimumDate", typeof(DateTime), typeof(DatePickerDialog), new DateTime(1900, 1, 1));
|
||||
|
||||
public static void SetMinimumDate(BindableObject view, DateTime value)
|
||||
{
|
||||
view.SetValue(MinimumDateProperty, value);
|
||||
}
|
||||
|
||||
public static DateTime GetMinimumDate(BindableObject view)
|
||||
{
|
||||
return (DateTime)view.GetValue(MinimumDateProperty);
|
||||
}
|
||||
}
|
||||
|
||||
internal class DatePickerDialogRoutingEffect : RoutingEffect
|
||||
{
|
||||
public DatePickerDialogRoutingEffect() : base("GraphicsControls." + nameof(DatePickerDialog))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ using ATimePickerDialog = Android.App.TimePickerDialog;
|
|||
using AView = Android.Views.View;
|
||||
|
||||
[assembly: ResolutionGroupName("GraphicsControls")]
|
||||
[assembly: ExportEffect(typeof(TimePickerDialogPlatformEffect), nameof(GraphicsControls.Effects.TimePickerDialog))]
|
||||
[assembly: ExportEffect(typeof(TimePickerDialogPlatformEffect), nameof(TimePickerDialog))]
|
||||
namespace GraphicsControls.Effects
|
||||
{
|
||||
public class TimePickerDialogPlatformEffect : PlatformEffect
|
Загрузка…
Ссылка в новой задаче