From 790f2732e4570bcbb74cd39aa6dfac83aaa67027 Mon Sep 17 00:00:00 2001 From: Woochan <48237284+lwc0917@users.noreply.github.com> Date: Wed, 31 Mar 2021 16:16:46 +0900 Subject: [PATCH] [NUI] Introduce NUI Picker (#2769) Co-authored-by: Woochanlee Co-authored-by: Jiyun Yang --- src/Tizen.NUI.Components/Controls/Picker.cs | 586 +++++++++++++++++++++ src/Tizen.NUI.Components/Style/PickerStyle.cs | 82 +++ src/Tizen.NUI.Components/Theme/DefaultTheme.cs | 7 + .../Theme/DefaultThemeCommon.cs | 26 + .../Tizen.NUI.Samples/Samples/PickerSample.cs | 48 ++ 5 files changed, 749 insertions(+) create mode 100755 src/Tizen.NUI.Components/Controls/Picker.cs create mode 100755 src/Tizen.NUI.Components/Style/PickerStyle.cs create mode 100755 test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/PickerSample.cs diff --git a/src/Tizen.NUI.Components/Controls/Picker.cs b/src/Tizen.NUI.Components/Controls/Picker.cs new file mode 100755 index 0000000..08da631 --- /dev/null +++ b/src/Tizen.NUI.Components/Controls/Picker.cs @@ -0,0 +1,586 @@ +/* Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +using System; +using Tizen.NUI; +using Tizen.NUI.BaseComponents; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; + +namespace Tizen.NUI.Components +{ + /// + /// ValueChangedEventArgs is a class to notify changed Picker value argument which will sent to user. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class ValueChangedEventArgs : EventArgs + { + /// + /// ValueChangedEventArgs default constructor. + /// value of Picker. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public ValueChangedEventArgs(int value) + { + Value = value; + } + + /// + /// ValueChangedEventArgs default constructor. + /// The current value of Picker. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int Value { get; } + + } + + /// + /// Picker is a class which provides a function that allows the user to select + /// a value through a scrolling motion by expressing the specified value as a list. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class Picker : Control + { + //Tizen 6.5 base components Picker guide visible scroll item is 5. + private const int scrollVisibleItems = 5; + //Dummy item count for loop feature. Max value of scrolling distance in + //RPI target is bigger than 20 items height. it can adjust depends on the internal logic and device env. + private const int dummyItemsForLoop = 20; + private int startScrollOffset; + private int itemHeight; + private int startScrollY; + private int startY; + private int pageSize; + private int currentValue; + private int maxValue; + private int minValue; + private int lastScrollPosion; + private bool onAnimation; //Scroller on animation check. + private bool displayedValuesUpdate; //User sets displayed value check. + private bool needItemUpdate; //min, max or display value updated check. + private bool loopEnabled; + private ReadOnlyCollection displayedValues; + private PickerScroller pickerScroller; + private View upLine; + private View downLine; + private IList itemList; + private PickerStyle pickerStyle => ViewStyle as PickerStyle; + + /// + /// Creates a new instance of Picker. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Picker() + { + Initialize(); + } + + /// + /// Creates a new instance of Picker. + /// + /// Creates Picker by special style defined in UX. + [EditorBrowsable(EditorBrowsableState.Never)] + public Picker(string style) : base(style) + { + Initialize(); + } + + /// + /// Creates a new instance of Picker. + /// + /// Creates Picker by style customized by user. + [EditorBrowsable(EditorBrowsableState.Never)] + public Picker(PickerStyle pickerStyle) : base(pickerStyle) + { + Initialize(); + } + + /// + /// Dispose Picker and all children on it. + /// + /// Dispose type. + [EditorBrowsable(EditorBrowsableState.Never)] + protected override void Dispose(DisposeTypes type) + { + if (disposed) + { + return; + } + + if (type == DisposeTypes.Explicit) + { + if (itemList != null) + { + foreach (TextLabel textLabel in itemList) + { + if (pickerScroller) pickerScroller.Remove(textLabel); + Utility.Dispose(textLabel); + } + + itemList = null; + } + + if (pickerScroller != null) + { + Remove(pickerScroller); + Utility.Dispose(pickerScroller); + pickerScroller = null; + } + + Remove(upLine); + Utility.Dispose(upLine); + Remove(downLine); + Utility.Dispose(downLine); + } + + base.Dispose(type); + } + + /// + /// An event emitted when Picker value changed, user can subscribe or unsubscribe to this event handler. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public event EventHandler ValueChanged; + + //TODO Fomatter here + + /// + /// The values to be displayed instead of numbers. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public ReadOnlyCollection DisplayedValues + { + get + { + return displayedValues; + } + set + { + displayedValues = value; + + needItemUpdate = true; + displayedValuesUpdate = true; + + UpdateValueList(); + } + } + + /// + /// The Current value of Picker. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int CurrentValue + { + get + { + return currentValue; + } + set + { + if (currentValue == value) return; + + if (currentValue < minValue) currentValue = minValue; + else if (currentValue > maxValue) currentValue = maxValue; + + currentValue = value; + + UpdateCurrentValue(); + } + } + + /// + /// The max value of Picker. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int MaxValue + { + get + { + return maxValue; + } + set + { + if (maxValue == value) return; + if (currentValue > value) currentValue = value; + + maxValue = value; + needItemUpdate = true; + + UpdateValueList(); + } + } + + /// + /// The min value of Picker. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int MinValue + { + get + { + return minValue; + } + set + { + if (minValue == value) return; + if (currentValue < value) currentValue = value; + + minValue = value; + needItemUpdate = true; + + UpdateValueList(); + } + } + + /// + /// Applies style to Picker. + /// + /// The style to apply. + [EditorBrowsable(EditorBrowsableState.Never)] + public override void ApplyStyle(ViewStyle viewStyle) + { + base.ApplyStyle(viewStyle); + + //Apply StartScrollOffset style. + if (pickerStyle?.StartScrollOffset != null) + startScrollOffset = (int)pickerStyle.StartScrollOffset.Height; + + //Apply ItemTextLabel style. + if (pickerStyle?.ItemTextLabel != null) + { + itemHeight = (int)pickerStyle.ItemTextLabel.Size.Height; + + if (itemList != null) + foreach (TextLabel textLabel in itemList) + textLabel.ApplyStyle(pickerStyle.ItemTextLabel); + } + + //Apply PickerCenterLine style. + if (pickerStyle?.Divider != null && upLine != null && downLine != null) + { + upLine.ApplyStyle(pickerStyle.Divider); + downLine.ApplyStyle(pickerStyle.Divider); + downLine.PositionY = (int)pickerStyle.Divider.PositionY + itemHeight; + } + } + + private void Initialize() + { + HeightSpecification = LayoutParamPolicies.MatchParent; + + //Picker Using scroller internally. actually it is a kind of scroller which has infinity loop, + //and item center align features. + pickerScroller = new PickerScroller(pickerStyle) + { + Size = new Size(-1, pickerStyle.Size.Height), + ScrollingDirection = ScrollableBase.Direction.Vertical, + Layout = new LinearLayout() + { + LinearOrientation = LinearLayout.Orientation.Vertical, + }, + //FIXME: Need to expand as many as possible; + // When user want to start list middle of the list item. currently confused how to create list before render. + ScrollAvailableArea = new Vector2(0, 10000), + Name = "pickerScroller", + }; + pickerScroller.Scrolling += OnScroll; + pickerScroller.ScrollAnimationEnded += OnScrollAnimationEnded; + pickerScroller.ScrollAnimationStarted += OnScrollAnimationStarted; + + itemList = new List(); + + minValue = maxValue = currentValue = 0; + displayedValues = null; + //Those many flags for min, max, value method calling sequence dependency. + needItemUpdate = true; + displayedValuesUpdate = false; + onAnimation = false; + loopEnabled = false; + + startScrollOffset = (int)pickerStyle.StartScrollOffset.Height; + itemHeight = (int)pickerStyle.ItemTextLabel.Size.Height; + startScrollY = (itemHeight * dummyItemsForLoop) + startScrollOffset; + startY = startScrollOffset; + + Add(pickerScroller); + AddLine(); + } + + private void OnValueChanged() + { + ValueChangedEventArgs eventArgs = + new ValueChangedEventArgs(displayedValuesUpdate ? Int32.Parse(itemList[currentValue].Name) : Int32.Parse(itemList[currentValue].Text)); + ValueChanged?.Invoke(this, eventArgs); + } + + private void OnScroll(object sender, ScrollEventArgs e) + { + //Ignore if the scrolling animation happened. + if (!loopEnabled || onAnimation) return; + + //Check the scroll is going out to the dummys if so, bring it back to page. + if (e.Position.Y > -(startScrollY - (itemHeight * 2))) + pickerScroller.ScrollTo(-e.Position.Y + pageSize, false); + else if (e.Position.Y < -(startScrollY + pageSize - (itemHeight * 2))) + pickerScroller.ScrollTo(-e.Position.Y - pageSize, false); + } + + private void OnScrollAnimationStarted(object sender, ScrollEventArgs e) + { + onAnimation = true; + } + + private void OnScrollAnimationEnded(object sender, ScrollEventArgs e) + { + //Ignore if the scroll position was not changed. (called it from this function) + if (lastScrollPosion == (int)e.Position.Y) return; + + //Calc offset from closest item. + int offset = (int)(e.Position.Y + startScrollOffset) % itemHeight; + if (offset < -(itemHeight / 2)) offset += itemHeight; + + lastScrollPosion = (int)(-e.Position.Y + offset); + + //Item center align with animation, otherwise changed event emit. + if (offset != 0) + pickerScroller.ScrollTo(-e.Position.Y + offset, true); + else { + currentValue = ((int)(-e.Position.Y / itemHeight) + 2); + OnValueChanged(); + } + + onAnimation = false; + } + + //This is UI requirement. It helps where exactly center item is. + private void AddLine() + { + upLine = new View(pickerStyle.Divider); + downLine = new View(pickerStyle.Divider) + { + Position = new Position(0, (int)pickerStyle.Divider.PositionY + itemHeight), + }; + + Add(upLine); + Add(downLine); + } + + private String GetItemText(bool loopEnabled, int idx) + { + if (!loopEnabled) return " "; + else { + if (displayedValuesUpdate) { + idx = idx - MinValue; + if (idx <= displayedValues.Count) { + return displayedValues[idx]; + } + return " "; + } + + return idx.ToString(); + } + } + + //FIXME: If textVisual can add in scroller please change it to textVisual for performance + [SuppressMessage("Microsoft.Reliability", + "CA2000:DisposeObjectsBeforeLosingScope", + Justification = "The items are added to itemList and are disposed in Picker.Dispose().")] + private void AddPickerItem(bool loopEnabled, int idx) + { + TextLabel temp = new TextLabel(pickerStyle.ItemTextLabel) + { + WidthSpecification = LayoutParamPolicies.MatchParent, + Text = GetItemText(loopEnabled, idx), + Name = idx.ToString(), + }; + + itemList.Add(temp); + pickerScroller.Add(temp); + } + + private void UpdateCurrentValue() + { + // -2 for center align + int startItemIdx = (currentValue == 0) ? -2 : currentValue - minValue - 2; + + if (loopEnabled) startY = ((dummyItemsForLoop + startItemIdx) * itemHeight) + startScrollOffset; + // + 2 for non loop picker center align + else startY = ((2 + startItemIdx) * itemHeight) + startScrollOffset; + pickerScroller.ScrollTo(startY, false); + } + + private void UpdateValueList() + { + if (!needItemUpdate) return; + if (minValue > maxValue) return; + + //FIXME: This is wrong. + // But scroller can't update item property after added please fix me. + if (itemList.Count > 0) { + itemList.Clear(); + pickerScroller.RemoveAllChildren(); + } + + if (maxValue - minValue + 1 >= scrollVisibleItems) + { + loopEnabled = true; + //Current scroller can't add at specific index. + //So need below calc. + int dummyStartIdx = 0; + if (maxValue - minValue >= dummyItemsForLoop) + dummyStartIdx = maxValue - dummyItemsForLoop + 1; + else + dummyStartIdx = maxValue - (dummyItemsForLoop % (maxValue - minValue + 1)) + 1; + + //Start add items in scroller. first dummys for scroll anim. + for (int i = 0; i < dummyItemsForLoop; i++) + { + if (dummyStartIdx > maxValue) dummyStartIdx = minValue; + AddPickerItem(loopEnabled, dummyStartIdx++); + } + //Second real items. + for (int i = minValue; i <= maxValue; i++) + { + AddPickerItem(loopEnabled, i); + } + //Last dummys for scroll anim. + dummyStartIdx = minValue; + for (int i = 0; i < dummyItemsForLoop; i++) + { + if (dummyStartIdx > maxValue) dummyStartIdx = minValue; + AddPickerItem(loopEnabled, dummyStartIdx++); + } + } + else + { + loopEnabled = false; + + for (int i = 0; i < 2; i++) + AddPickerItem(loopEnabled, 0); + for (int i = minValue; i <= maxValue; i++) + AddPickerItem(!loopEnabled, i); + for (int i = 0; i < 2; i++) + AddPickerItem(loopEnabled, 0); + + } + pageSize = itemHeight * (maxValue - minValue + 1); + + UpdateCurrentValue(); + + //Give a correct scroll area. + pickerScroller.ScrollAvailableArea = new Vector2(0, (itemList.Count * itemHeight) - pickerStyle.Size.Height); + + needItemUpdate = false; + } + + internal class PickerScroller : ScrollableBase + { + private int itemHeight; + private int startScrollOffset; + private float velocityOfLastPan = 0.0f; + private float panAnimationDuration = 0.0f; + private float panAnimationDelta = 0.0f; + private float decelerationRate = 0.0f; + private float logValueOfDeceleration = 0.0f; + private delegate float UserAlphaFunctionDelegate(float progress); + private UserAlphaFunctionDelegate customScrollAlphaFunction; + + public PickerScroller(PickerStyle pickerStyle) : base() + { + //Default rate is 0.998. this is for reduce scroll animation length. + decelerationRate = 0.994f; + startScrollOffset = (int)pickerStyle.StartScrollOffset.Height; + itemHeight = (int)pickerStyle.ItemTextLabel.Size.Height; + logValueOfDeceleration = (float)Math.Log(decelerationRate); + } + + private float CustomScrollAlphaFunction(float progress) + { + if (panAnimationDelta == 0) + { + return 1.0f; + } + else + { + // Parameter "progress" is normalized value. We need to multiply target duration to calculate distance. + // Can get real distance using equation of deceleration (check Decelerating function) + // After get real distance, normalize it + float realDuration = progress * panAnimationDuration; + float realDistance = velocityOfLastPan * ((float)Math.Pow(decelerationRate, realDuration) - 1) / logValueOfDeceleration; + float result = Math.Min(realDistance / Math.Abs(panAnimationDelta), 1.0f); + + return result; + } + } + + //Override Decelerating for Picker feature. + protected override void Decelerating(float velocity, Animation animation) + { + velocityOfLastPan = Math.Abs(velocity); + + float currentScrollPosition = -(ScrollingDirection == Direction.Horizontal ? ContentContainer.CurrentPosition.X : ContentContainer.CurrentPosition.Y); + panAnimationDelta = (velocityOfLastPan * decelerationRate) / (1 - decelerationRate); + panAnimationDelta = velocity > 0 ? -panAnimationDelta : panAnimationDelta; + + float destination = -(panAnimationDelta + currentScrollPosition); + //Animation destination has to center of the item. + float align = destination % itemHeight; + destination -= align; + destination -= startScrollOffset; + + float adjustDestination = AdjustTargetPositionOfScrollAnimation(destination); + + float maxPosition = ScrollAvailableArea != null ? ScrollAvailableArea.Y : ScrollAvailableArea.Y; + float minPosition = ScrollAvailableArea != null ? ScrollAvailableArea.X : 0; + + if (destination < -maxPosition || destination > minPosition) + { + panAnimationDelta = velocity > 0 ? (currentScrollPosition - minPosition) : (maxPosition - currentScrollPosition); + destination = velocity > 0 ? minPosition : -maxPosition; + destination = -maxPosition + itemHeight; + + if (panAnimationDelta == 0) + { + panAnimationDuration = 0.0f; + } + else + { + panAnimationDuration = (float)Math.Log((panAnimationDelta * logValueOfDeceleration / velocityOfLastPan + 1), decelerationRate); + } + } + else + { + panAnimationDuration = (float)Math.Log(-DecelerationThreshold * logValueOfDeceleration / velocityOfLastPan) / logValueOfDeceleration; + + if (adjustDestination != destination) + { + destination = adjustDestination; + panAnimationDelta = destination + currentScrollPosition; + velocityOfLastPan = Math.Abs(panAnimationDelta * logValueOfDeceleration / ((float)Math.Pow(decelerationRate, panAnimationDuration) - 1)); + panAnimationDuration = (float)Math.Log(-DecelerationThreshold * logValueOfDeceleration / velocityOfLastPan) / logValueOfDeceleration; + } + } + + customScrollAlphaFunction = new UserAlphaFunctionDelegate(CustomScrollAlphaFunction); + animation.DefaultAlphaFunction = new AlphaFunction(customScrollAlphaFunction); + animation.Duration = (int)panAnimationDuration; + animation.AnimateTo(ContentContainer, (ScrollingDirection == Direction.Horizontal) ? "PositionX" : "PositionY", (int)destination); + animation.Play(); + } + } + } +} diff --git a/src/Tizen.NUI.Components/Style/PickerStyle.cs b/src/Tizen.NUI.Components/Style/PickerStyle.cs new file mode 100755 index 0000000..70965fe --- /dev/null +++ b/src/Tizen.NUI.Components/Style/PickerStyle.cs @@ -0,0 +1,82 @@ +/* + * Copyright(c) 2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +using System.ComponentModel; +using Tizen.NUI.BaseComponents; +using Tizen.NUI.Binding; + +namespace Tizen.NUI.Components +{ + /// + /// PickerStyle is a class which saves PickerStyle's ux data. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class PickerStyle : ControlStyle + { + /// + /// Creates a new instance of a PickerStyle. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public PickerStyle() : base() + { + } + + /// + /// Creates a new instance of a PickerStyle with style. + /// + /// Creates PickerStyle by style customized by user. + [EditorBrowsable(EditorBrowsableState.Never)] + public PickerStyle(PickerStyle style) : base(style) + { + } + + /// + /// Gets or sets the PickerStyle Item TextLabel style. + /// This style is applied if PickerStyle Item is a TextLabel. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public TextLabelStyle ItemTextLabel { get; set; } = new TextLabelStyle(); + + /// + /// Gets or sets the PickerStyle Center line style. + /// + public ViewStyle Divider { get; set;} = new ViewStyle(); + + /// + /// Gets or sets the PickerStyle Item list start offset value. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public Size2D StartScrollOffset { get; set; } = new Size2D(); + + /// + /// Style's clone function. + /// + /// The style that needs to copy. + [EditorBrowsable(EditorBrowsableState.Never)] + public override void CopyFrom(BindableObject bindableObject) + { + base.CopyFrom(bindableObject); + + if (bindableObject is PickerStyle pickerStyle) + { + ItemTextLabel.CopyFrom(pickerStyle.ItemTextLabel); + Divider.CopyFrom(pickerStyle.Divider); + StartScrollOffset = (pickerStyle.StartScrollOffset == null) ? + new Size2D() : new Size2D(pickerStyle.StartScrollOffset.Width, pickerStyle.StartScrollOffset.Height); + } + } + } +} diff --git a/src/Tizen.NUI.Components/Theme/DefaultTheme.cs b/src/Tizen.NUI.Components/Theme/DefaultTheme.cs index 3980320..d501a06 100755 --- a/src/Tizen.NUI.Components/Theme/DefaultTheme.cs +++ b/src/Tizen.NUI.Components/Theme/DefaultTheme.cs @@ -105,6 +105,13 @@ namespace Tizen.NUI.Components // AppBar (new ExternalThemeKeyList(typeof(AppBar), typeof(AppBarStyle))), + + // Picker + (new ExternalThemeKeyList(typeof(Picker), typeof(PickerStyle))) + .AddSelector("/ItemTextLabel/Background", (ViewStyle style, Selector value) => ((PickerStyle)style).ItemTextLabel.BackgroundColor = value) + .AddSelector("/ItemTextLabel/TextColor", (ViewStyle style, Selector value) => ((PickerStyle)style).ItemTextLabel.TextColor = value) + .AddSelector("/ItemTextLabel/PixelSize", (ViewStyle style, Selector value) => ((PickerStyle)style).ItemTextLabel.PixelSize = value) + .AddSelector("/Divider/Background", (ViewStyle style, Selector value) => ((PickerStyle)style).Divider.BackgroundColor = value), }; return actionSet; diff --git a/src/Tizen.NUI.Components/Theme/DefaultThemeCommon.cs b/src/Tizen.NUI.Components/Theme/DefaultThemeCommon.cs index 721c0c8..f1ce065 100755 --- a/src/Tizen.NUI.Components/Theme/DefaultThemeCommon.cs +++ b/src/Tizen.NUI.Components/Theme/DefaultThemeCommon.cs @@ -409,6 +409,32 @@ namespace Tizen.NUI.Components ActionCellPadding = new Size2D(40, 0), }); + theme.AddStyleWithoutClone("Tizen.NUI.Components.Picker", new PickerStyle() + { + Size = new Size(160, 339), + ItemTextLabel = new TextLabelStyle() + { + //FIXME: Should be check PointSize. given size from UX is too large. + PixelSize = 32, + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Center, + Size = new Size(0,72), + TextColor = new Selector() + { + Normal = new Color("#000C2BFF"), + }, + BackgroundColor = Color.White, + }, + Divider = new ViewStyle() + { + SizeHeight = 2.0f, + WidthResizePolicy = ResizePolicyType.FillToParent, + Position = new Position(0, 132), + BackgroundColor = new Color("#0A0E4AFF"), + }, + StartScrollOffset = new Size2D(0, 12), + }); + return theme; } } diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/PickerSample.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/PickerSample.cs new file mode 100755 index 0000000..5dd0231 --- /dev/null +++ b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/PickerSample.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using Tizen.NUI; +using Tizen.NUI.BaseComponents; +using Tizen.NUI.Components; +using System.Collections.ObjectModel; + +namespace Tizen.NUI.Samples +{ + public class PickerSample : IExample + { + private static int pickerWidth = 160; + private static int pickerHeight = 339; + private Window window; + private Picker picker; + + private void onValueChanged(object sender, ValueChangedEventArgs e) + { + Console.WriteLine("Value is " + e.Value); + } + + public void Activate() + { + window = NUIApplication.GetDefaultWindow(); + window.BackgroundColor = Color.White; + + String[] textValue = new string[] { "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"}; + + picker = new Picker() + { + Size = new Size(pickerWidth, pickerHeight), + Position = new Position(Window.Instance.Size.Width / 2 - pickerWidth / 2, Window.Instance.Size.Height/ 2 - pickerHeight / 2), + MinValue = 1, + MaxValue = 10, + CurrentValue = 3, + DisplayedValues = new ReadOnlyCollection(textValue), + }; + picker.ValueChanged += onValueChanged; + window.Add(picker); + } + public void Deactivate() + { + window.Remove(picker); + picker.Dispose(); + picker = null; + } + } +} -- 2.7.4