h1.DateSpinner component - Functional and Design Specification
Define any potentially unfamiliar terms and acronyms.
a href="DateSpinner">DateSpinner - Date selection control for choosing one specific moment in time, utilizing one or more a href="SpinnerList">SpinnerList controls that the user can manipulate to select a date/time
DateField __- Text field containing content that represents a specific moment in time, e.g. "December 15th, 2010"
DateChooser __- Date selection control that supports choosing a specific date in time (e.g. "December 15th, 2010") or a range or set of dates (e.g. "March 8th - March 12th, 2011"). In general, this control is visualized as a grid of dates, i.e. month view.
date __- The numeric date in the month, e.g. the 31 in "May 31st".
day __- The day of the week, e.g. "Tuesday," which may be represented as an integer from 0 to 6.
meridian __- The am or pm value representing hours before or after noon; not used in 24-hour mode.
DateTimeFormatter - Class which provides functionality for properly formatting a Date object into a presentable String while taking into account localization issues. For the purposes of this feature, references to DateTimeFormatter will refer to the Flex DateTimeFormatter (spark.formatters._DateTimeFormatter) rather than the Flash flash.globalization.DateTimeFormatter._
The DateSpinner component is a tightly focused component utilizing one or more SpinnerLists to present a UI for choosing a particular point in time, whether that be a specific date, a specific time of day, or a time and date. It will function very similarly to the Date Spinner component available on iOS.
The DateSpinner control is a heavily requested feature that will provide immediate usefulness to Flex customers, especially with mobile applications. Currently, Flex customers who wish to present an interface for selecting a date or time to the user have to choose between either using the desktop DateChooser component or building their own. The DateChooser is not optimized for mobile in either performance or user-interface aspects, and additionally only supports choosing a date, not a time, and building a DateSpinner interface similar to the ones provided natively on mobile devices is not trivial since it involves building the core Spinner component before even getting to the complications associated with the DateSpinner, e.g. column ordering, localization concerns, invalid dates, 24 hour vs. 12 hour times, etc.
Developer Dan is building a mobile task list application and wants to present to the user the ability to set a due date and an alarm time for tasks. Dan creates an "add due date" button which when clicked puts the DateSpinner control on the screen with the date fields (year, month, date) present. The user uses touch gestures (e.g. touch, drag, throw) to spin the various wheels until the desired date is highlighted by the selection bar which is drawn horizontally across the center of all the wheels. The selected date is updated in Dan's UI every time the wheels come to a stop, so no explicit "commit" is required, although Dan could opt to present "Save \| Cancel" buttons so the user could opt to undo their change.
Because of the localization code built into the [DateSpinner], the control will present the spinners in the correct order for the user's locale, e.g. month ](%20date%20%5C%7C%20year%20for%20US%20users%2C%20date%20%5C%7C%20month%20%5C%7C%20year%20for%20European%20users%2C%20or%20year%20%5C%7C%20month%20%5C%7C%20date%20for%20Japanese%20users.%20Additionally%2C%20the%20labels%20on%20the%20wheels%20will%20be%20localized%2C%20e.g.%20the%20month%20names%20will%20be%20translated%2C%20and%20any%20appropriate%20label%20characters%20will%20be%20added.%26amp%3Bnbsp%3BDan%20can%20override%20this%20behavior%20in%20the%20%5BDateSpinner).
The DateSpinner will present a number of SpinnerLists arranged horizontally. The SpinnerLists can be manipulated via touch or mouse individually. Along the vertical center of the component will run a "selection bar" indicating the currently selected fields. The SpinnerLists will be framed by a border/frame which group the SpinnerLists into one cohesive component.
The UI will be similar to (but not exactly like) the iOS UIDatePicker component
To integrate cleanly into the DateField and DateChooser components which are being developed in parallel, the DateSpinner will implement a common interface through which the DateField can interact with the DateChooser and DateSpinner components in a generalized manner:
Note that the DateField and DateChooser projects are not yet finalized and are subject to change. For the purposes of the DateSpinner, only the relevant related classes and functionality will be implemented; unimplemented classes (i.e. classes intended for a future release) are grayed out in the above diagram.
Initially spark.components.calendarClasses will only contain the DateSelectorDisplayMode class, but there are roughly 8 additional classes planned for inclusion in this package for supporting the DateChooser component -- thus the creation of this package instead of simply using spark.components.supportClasses.
The DateSpinner will handle localization issues for the developer. For example, if the application is running in the en_US locale, by default dates will be shown with the month spinner first, followed by the date and year spinner. However, if the application is running in the ja_JP locale, the default DateSpinner will instead list the year first, followed by the month and then date spinners. Furthermore, any locale-specific labels will be applied as appropriate. For example, in the ja_JP locale, years should be appended with the year character, e.g. "2011年".
The developer will be able to override the default localization behavior by setting the locale style.
-The developer can choose to display TIME mode using the 24-hour clock.- The locale may dictate that the time should be shown using the 24 hour clock. In this situation, the meridian SpinnerList is not shown, and the hour SpinnerList shows hours from 0 to 23, inclusive.
As the name indicates, the DateSpinner will specifically use SpinnerLists as the interface for users to select date/time components. The developer will be able to customize the look of the DateSpinner by providing their own skin in place of the default DateSpinnerSkin. The DateSpinner will provide the logic for handling the currently selected date and setting those properties on the skin parts (i.e. the SpinnerLists). The skin will provide the factories for creating the SpinnerLists; the DateSpinner, however, will manage the creation/destruction of the different SpinnerLists depending on the mode (e.g. only hour and minute spinners for TIME mode). The logic for determining the order of the SpinnerLists will similarly be retained in the DateSpinner component. Thus, the core logic of the DateSpinner will be retained if the developer chooses to reskin the component.
The DateSpinnerSkin will be responsible for the container that contains the SpinnerLists (e.g. SpinnerListContainer) and the chrome, border, colors, etc. of the overall component.
The DateSpinner will support three different modes:
These modes will determine which date fields are visible and editable; the non-visible fields will retain any values that were previously there but will be not updatable. For example, if the Date object for "June 13th, 2011, 2:57pm GMT" is set as the selectedDate for a DateSpinner in DATE mode and the user changes the month, date, and year, the time "2:57pm GMT" will still be retained.
For the date "June 13th, 2011, 2:57pm GMT", the following examples indicate what would be visible in the DateSpinner (column separators denoted by "\|\|"):
Mode
Fields Shown
Format Notes
DATE
*\
\
June *\ \
13 *\ \
2011 *\ \
The month will be displayed in long form, e.g. "January"
TIME
*\
\
2 *\ \
57 *\ \
PM *\ \
DATE_AND_TIME
*\
\
Mon Jun 13 *\ \
2 *\ \
57 *\ \
PM *\ \
The month will be displayed in short form, e.g. "Jan". The day, month, and date will be listed on one SpinnerList. In place of the current day/month/date, the String "Today" (localized) will be shown.
The DateSpinner will utilize a number of the features of the underlying SpinnerLists in its user interactions, e.g.
Additionally, basic date restrictions will be automatically supported. For example, the date spinner will always show dates 1 to 31, but for the currently selected month only valid dates will be selectable (e.g. February 30th will never be selectable).
When the selected date is changed programmatically, the selected values will be animated into view. However, if the distance to animate is considered to be too large, the a href="DateSpinner">DateSpinner will change to a direct selection change, i.e. the a href="SpinnerList">SpinnerList will be immediately changed without animating through the intermediate values.
When the selected date is changed programmatically, the selected values are snapped into view.
The DateSpinner will dispatch a CHANGE event when the selected date has changed.
Additions to MXML Language and ActionScript Object Model
package spark.components { //-------------------------------------- // Events //-------------------------------------- /** * Dispatched after the selected date has been changed by the user. * * @eventType flash.events.Event.CHANGE * * @langversion 3.0 * @playerversion AIR 3 * @productversion Flex 4.6 */ <a href="Event%28name%3D%26quot%3Bchange%26quot%3B%2C%20type%3D%26quot%3Bflash.events.Event%26quot%3B%29">Event(name="change", type="flash.events.Event")</a> /** * Dispatched after the selected date has been changed, either * by the user (i.e. interactively) or programmatically. * * @eventType mx.events.FlexEvent.VALUE_COMMIT * * @langversion 3.0 * @playerversion AIR 3 * @productversion Flex 4.6 */ <a href="Event%28name%3D%26quot%3BvalueCommit%26quot%3B%2C%20type%3D%26quot%3Bmx.events.FlexEvent%26quot%3B%29">Event(name="valueCommit", type="mx.events.FlexEvent")</a> /** * The locale of the component. Controls how dates are formatted, e.g. in what order the fields * are listed and what additional date-related characters are shown, if any. Uses standard locale * identifiers as described in Unicode Technical Standard #35. For example "en", "en_US" and "en-US" * are all English, "ja" is Japanese. If the specified locale is not supported on the platform, "en_US" * will be used. To determine if a locale is supported, use * <code>DateTimeFormatter.getAvailableLocaleIDNames()</code> * * <p>The default value is undefined. This property inherits its value from an ancestor; if still * undefined, it inherits from the global <code>locale</code> style.</p> * * <p>When using the Spark formatters and globalization classes, you can set this style on the root * application to the value of the <code>LocaleID.DEFAULT</code> constant. * Those classes will then use the client operating system's international preferences.</p> * * @langversion 3.0 * @playerversion AIR 3 * @productversion Flex 4.6 */ <a href="Style%28name%3D%26quot%3Blocale%26quot%3B%2C%20type%3D%26quot%3BString%26quot%3B%2C%20inherit%3D%26quot%3Byes%26quot%3B%29">Style(name="locale", type="String", inherit="yes")</a> /** * Color applied for the date items that match today's date. * For example, if this is set to "0x0000FF" and today's date is 1/1/2011, then the month * "January", the date "1", and the year "2011" will be in blue text on the spinners. This color * is not applied to time items. * * <p>The default value is inherited from the global styles; see the framework defaults.css for * the specific value.</p> * * @langversion 3.0 * @playerversion AIR 3 * @productversion Flex 4.6 */ <a href="Style%28name%3D%26quot%3BaccentColor%26quot%3B%2C%20type%3D%26quot%3Buint%26quot%3B%2C%20format%3D%26quot%3BColor%26quot%3B%2C%20inherit%3D%26quot%3Byes%26quot%3B%29">Style(name="accentColor", type="uint", format="Color", inherit="yes")</a> /** * The DateSpinner control presents an interface for picking a particular date or time. * * <p>The DateSpinner control can display the date, the time, or the date and time, based on the * value of the <code>displayMode</code> property.</p> * * <p>The UI for the control is made up of a series of SpinnerList controls wrapped inside * a SpinnerListContainer that show the * currently-selected date. Through touch or mouse interaction, users * can adjust the selected date.</p> * * <p>The DateSpinnerSkin only defines some sizing properties. * To change the appearance of the DateSpinner control, you typically reskin the underlying * SpinnerListSkin or SpinnerListContainerSkin.</p> * * @mxml <p>The <code><s:DateSpinner></code> tag inherits all of the tag * attributes of its superclass and adds the following tag attributes:</p> * * <pre> * <s:DateSpinner * <strong>Properties</strong> * displayMode="date|time|dateAndTime" * maxDate="null" * minDate="null" * minuteStepSize="1" * selectedDate="" * * <strong>Styles</strong> * accentColor="0x0099FF" * /> * </pre> * * @see spark.components.SpinnerList * * @langversion 3.0 * @playerversion AIR 3 * @productversion Flex 4.6 */ public class DateSpinner extends SkinnableComponent implements IDateSelector { //-------------------------------------------------------------------------- // // Class constants // //-------------------------------------------------------------------------- protected static const YEAR_ITEM:String = "yearItem"; protected static const MONTH_ITEM:String = "monthItem"; protected static const DATE_ITEM:String = "dateItem"; protected static const HOUR_ITEM:String = "hourItem"; protected static const MINUTE_ITEM:String = "minuteItem"; protected static const MERIDIAN_ITEM:String = "meridianItem"; /** * Constructor * */ public function DateSpinner() {} //-------------------------------------------------------------------------- // // Skin parts // //-------------------------------------------------------------------------- <a href="SkinPart%28required%3D%26quot%3Btrue%26quot%3B%29">SkinPart(required="true")</a> /** * The default factory for creating SpinnerList interfaces for all fields. * This is used by createDateItemList(). */ public var dateItemList:IFactory; <a href="SkinPart%28required%3D%26quot%3Btrue%26quot%3B%29">SkinPart(required="true")</a> /** * The container for the date part lists */ public var listContainer:IVisualElementContainer; //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- /** * Instance variables holding the lists that comprise the various date items to be * shown and manipulated */ protected var yearList:SpinnerList; protected var monthList:SpinnerList; protected var dateList:SpinnerList; protected var hourList:SpinnerList; protected var minuteList:SpinnerList; protected var meridianList:SpinnerList; <a href="Bindable%28event%3D%26quot%3BvalueCommit%26quot%3B%29">Bindable(event="valueCommit")</a> /** * Date that is currently selected in the DateSpinner control. * * @default the current Date at the moment the DateSpinner was created * */ public function get selectedDate():Date {} public function set selectedDate(value:Date):void {} /** * Mode the DateSpinner is used in. * * @default DateSelectorMode.DATE * */ public function get mode():String {} public function set mode(value:String):void {} /** * Minimum selectable date; only dates after this date are selectable. * * @default If minDate is null, the value defaults to January 1st, 1601. * minDate's year should be greater than or equal to 1601 since * DateTimeFormatter only supports the range from 1601 to 30827 */ public function get minDate():Date {} public function set minDate(value:Date):void {} /** * Maximum selectable date; only dates before this date are selectable. * * @default If maxDate is null, the value defaults to Dec 31st, 9999. */ public function get maxDate():Date {} public function set maxDate(value:Date):void {} /** * Minute interval to be used when displaying minutes. Only * applicable in TIME and DATE_AND_TIME modes. Valid values must * be evenly divisible into 60; invalid values will revert to * the default interval of 1. For example, a value of "15" will show * the values 0, 15, 30, 45. * * @default 1 * */ public function get minuteStepSize():int {} public function set minuteStepSize(value:int):void {} //-------------------------------------------------------------------------- // // Functions // //-------------------------------------------------------------------------- /** * Create a list object for the specified date part. * * @param datePart use date part constants, e.g. YEAR_ITEM * @param itemIndex index of the date part in the overall list * @param itemCount number of date parts being shown * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 * */ protected function createDateItemList(datePart:String, itemIndex:int, itemCount:int):SpinnerList {} } }
\
package spark.skins.mobile { /** * Default skin for the DateSpinner. * * @author tkraikit * */ public class DateSpinnerSkin extends MobileSkin { public var hostComponent:DateSpinner; public function DateSpinnerSkin() {} //-------------------------------------------------------------------------- // // Skin parts // //-------------------------------------------------------------------------- public var dateItemList:IFactory; public var listContainer:IVisualElementContainer; } }
\
package spark.components.calendarClasses { /** * The DateSelectorMode class defines the valid constant values for the * <code>mode</code> property of the Spark DateChooser and DateSpinner controls. * * <p>Use the constants in ActionsScript, as the following example shows: </p> * <pre> * myDateChooser.mode = DateSelectorMode.DATE_AND_TIME; * </pre> * * <p>In MXML, use the String value of the constants, * as the following example shows:</p> * <pre> * <s:DataChooser id="myChooser" * mode="dateAndTime"> * ... * </s:DataChooser> * </pre> * * @see spark.components.DateChooser#mode * * @langversion 3.0 * @playerversion AIR 3.0 * @productversion Flex 4.6 */ public final class DateSelectorDisplayMode { /** * Show selection options for date */ public static const DATE:String = "date"; /** * Show selection options for time */ public static const TIME:String = "time"; /** * Show selection options for both date and time */ public static const DATE_AND_TIME:String = "dateAndTime"; } }
The following features have been deferred for this release.
This simple example shows a DateSpinner configured to show the years 1980 to 2020, allow any selectable date between those two years inclusive, and show both date and time selection spinners. When the DateSpinner's selected date is adjusted, the Label above the DateSpinner shows the new selected date.
<?xml version="1.0" encoding="utf-8"?> <s:View xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" title="DateSpinnerExample" creationComplete="view1_creationCompleteHandler(event)"> <fx:Script> <![CDATA[ import mx.events.FlexEvent; import spark.components.calendarClasses.DateSelectorDisplayMode; import spark.formatters.DateTimeFormatter; private var dtf:DateTimeFormatter = new DateTimeFormatter(); protected function view1_creationCompleteHandler(event:FlexEvent):void { ds.addEventListener(Event.CHANGE, function(evt:Event):void { currentDate.text = dtf.format(ds.selectedDate); }); } ]]> </fx:Script> <fx:Declarations> <!-- Place non-visual elements (e.g., services, value objects) here --> </fx:Declarations> <s:layout> <s:VerticalLayout paddingLeft="20" paddingTop="20"/> </s:layout> <s:Label id="currentDate" /> <s:DateSpinner id="ds" displayMode="{DateSelectorDisplayMode.DATE_AND_TIME}" minDate="{new Date(1980, 0)}" maxDate="{new Date(2020, 11, 31)}" /> </s:View>
No additional implementation details.
There are no expected compiler change requirements.
This feature is intended mainly for mobiel use but should function across all form factors with no special work required.
This feature is intended to function uniformly across platforms.
There should be no syntax changes affecting backwards compatibility for this feature.
There are no expected changes in behavior for existing MXML components and tags.
No deprecations or new warnings are expected.
The DateSpinner component is mainly geared towards touch and mouse interaction; there may be accessibility considerations for those who are unable to utilize those input methods, as well as for the visually impaired.
Given that the DateSpinner is expected to be used heavily on mobile and tablet platforms, performance is a critical consideration. Initial skinning will be implemented in ActionScript to improve performance.
Note: Flex bug SDK-29884 notes that on Mac OS X the DateTimeFormatter performance is significantly slower than on Windows, and leads to noticeable performance degradation with large numbers of formatting operations. On the one hand, our expected use cases shouldn't have nearly as many formatting operations to populate the dataProviders of the SpinnerLists (e.g. 12 months, 31 dates, and 100 years), but on the other hand any performance degradation could be magnified by the slower performance available on mobile platforms. We need to make sure this aspect is included in testing.
All components that deal with text will need to be globalization-aware. This means that text in any supported language can be used with the component.
The component must use the Unicode character set (mostly comes for free from Flash Player) and must interoperate with IME's (Input Method Editors) for foreign languages (also mostly supported via Flash Player).
Globalization also includes issues with date/time formatting and currency formatting for specific locales.
European (French, German, etc.) and Asian (Japanese, Korean, Chinese) languages are of particular concern.
Components should look and behave correctly when mirrored by setting layoutDirection to rtl.
Note any specific globalization issues or challenges here.
The following three requirements have been identified and communicated to the globalization team:
The string "Today" may be shown in DATE_AND_TIME mode; this String will need to be localized.
The fields of the SpinnerLists will need date localization.
Existing localized month and day names will be drawn from the current spark.formatters.-DateTimeFormatter- extended DateTimeFormatter classes provided by the globalization team.
Open
Resolved