2 using Tizen.NUI.Constants;
4 using System.Runtime.InteropServices;
5 using System.Collections.Generic;
9 public class ScrollContainer : CustomView
11 private View _container; // View Container will be the first item added to ScrollContainer and parent to all the items added to the ScrollContainer.
12 private Size _itemSize; // Size of the item / images added to the ScrollContainer.
13 private List<View> _itemList; // List collection of View items/images added to the ScrollContainer.
14 private int _itemCount; // Number of items / images added to the ScrollContainer.
15 private int _focusedItem; // Index of currently focused View item / image on the ScrollContainer.
16 private float _scrollDisplacement; // Used for horizontal pan displacement.
17 private float _currentScrollPosition; // Used for horizontal scroll position.
18 private float _gap; // Used for gap / padding between items / images on the ScrollContainer.
19 private float _width; // Width of the ScrollContainer.
20 private float _height; // Height of the ScrollContainer.
21 private bool _isFocused; // Flag to check if ScrollContainer is enabled or not.
22 private float _marginX; // Extra horizontal margin is used to add an extra gap between items / images after a focused and scaled item / image.
23 private float _marginY; // Extra vertical margin (not used at the moment).
24 private float _offsetYFactor; // Vertical Position offset Factor of item height.
25 private float _offsetX; // Horizontal Position offset of ScrollContainer.
26 private Stage _stage; // Reference to Dali stage.
27 private Size2D _stageSize; // Reference to Dali stage size.
28 private ImageView _shadowBorder; // Reference to Shadow border ImageView applied to the focused item on ScrollContainer.
29 private ImageView _spotLight; // Reference to SpotLight ImageView applied to the focused item on ScrollContainer.
30 private Animation _spotLightAnimation; // SpotLight Animation applied to the focused item on ScrollContainer.
31 private Animation _focusAnimation; // Focused position animation on ScrollContainer.
32 private Animation _scrollAnimation; // Scroll animation on items of ScrollContainer.
33 private Animation _focusTransitionAnimation; // Focus Transition (scaling /unscaling) animation on items of ScrollContainer.
34 private Path _circularPath; // Circular path used for SpotLight Animation applied to the focused item on ScrollContainer.
36 static CustomView CreateInstance()
38 return new ScrollContainer();
41 // static constructor registers the control type (for user can add kinds of visuals to it)
42 static ScrollContainer()
44 // ViewRegistry registers control type with DALi type registery
45 // also uses introspection to find any properties that need to be registered with type registry
46 ViewRegistry.Instance.Register(CreateInstance, typeof(ScrollContainer));
49 public ScrollContainer() : base(typeof(ScrollContainer).Name, CustomViewBehaviour.DisableStyleChangeSignals |
50 CustomViewBehaviour.RequiresKeyboardNavigationSupport)
62 public Tizen.NUI.View Container
89 Position topLeft = new Position(-0.25f * _itemSize.Width, -0.25f * _itemSize.Height, 0.0f);
90 Position topRight = new Position(0.25f * _itemSize.Width, -0.25f * _itemSize.Height, 0.0f);
91 Position bottomRight = new Position(0.25f * _itemSize.Width, 0.25f * _itemSize.Height, 0.0f);
92 Position bottomLeft = new Position(-0.25f * _itemSize.Width, 0.25f * _itemSize.Height, 0.0f);
94 _circularPath = new Path();
95 _circularPath.AddPoint(topLeft);
96 _circularPath.AddPoint(topRight);
97 _circularPath.AddPoint(bottomRight);
98 _circularPath.AddPoint(bottomLeft);
99 _circularPath.AddPoint(topLeft);
100 _circularPath.GenerateControlPoints(0.5f);
130 public float OffsetYFator
134 return _offsetYFactor;
139 _offsetYFactor = value;
195 public ImageView ShadowBorder
199 return _shadowBorder;
204 _shadowBorder = value;
208 public ImageView SpotLight
221 public int FocusedItemID
225 if (_focusedItem < 0)
234 // This override method is called automatically after the Control has been initialized.
235 // Any second phase initialization is done here.
236 public override void OnInitialize()
238 _itemSize = new Size(0.0f, 0.0f, 0.0f);
242 _currentScrollPosition = 0.0f;
248 _offsetYFactor = 0.0f;
251 _container = new View();
252 this.Add(_container);
254 _itemList = new List<View>();
256 this.ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft;
257 this.AnchorPoint = Tizen.NUI.AnchorPoint.TopLeft;
258 this.WidthResizePolicy = ResizePolicyType.FillToParent;
259 this.HeightResizePolicy = ResizePolicyType.FillToParent;
260 this.Focusable = (true);
262 _container.ParentOrigin = Tizen.NUI.ParentOrigin.TopLeft;
263 _container.AnchorPoint = Tizen.NUI.AnchorPoint.TopLeft;
264 _container.WidthResizePolicy = ResizePolicyType.FillToParent;
265 _container.HeightResizePolicy = ResizePolicyType.FillToParent;
267 _stage = Stage.Instance;
268 _stageSize = _stage.Size;
270 _spotLightAnimation = new Animation(Constants.SpotLightDuration);
271 _focusTransitionAnimation = new Animation(Constants.FocusTransitionDuration);
272 _focusAnimation = new Animation(Constants.FocusDuration);
273 _focusAnimation.EndAction = Animation.EndActions.StopFinal;
274 _scrollAnimation = new Animation(Constants.ScrollDuration);
275 _scrollAnimation.EndAction = Animation.EndActions.StopFinal;
277 //changed to internal
278 //EnableGestureDetection(Gesture.Type.Pan);
281 // This will be invoked automatically if an item/image is added to the ScrollContainer
282 public override void OnChildAdd(Actor actor)
284 View item = View.DownCast(actor);
285 //View item = actor as View;
287 if (item is View && item != _container)
289 item.AnchorPoint = Tizen.NUI.AnchorPoint.BottomCenter;
290 item.ParentOrigin = Tizen.NUI.ParentOrigin.BottomCenter;
292 item.Size = _itemSize;
293 item.Focusable = (true);
294 item.Position = GetItemPosition(_itemCount, _currentScrollPosition);
295 item.Name = _itemCount.ToString();
297 _container.Add(item);
304 // This will be invoked automatically if an item/image is removed from the ScrollContainer
305 public override void OnChildRemove(Actor actor)
307 View item = View.DownCast(actor);
308 //View item = actor as View;
310 if (item is View && item != _container)
312 _container.Remove(item);
315 _itemList.Remove(item);
319 // This override function supports two dimensional keyboard navigation.
320 // This function returns the next keyboard focusable actor in ScrollContainer control towards the given direction.
321 public override View GetNextKeyboardFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)
323 if (direction == View.FocusDirection.Left)
325 return View.DownCast(FocusPrevious(loopEnabled));
327 else if (direction == View.FocusDirection.Right)
329 return View.DownCast(FocusNext(loopEnabled));
333 return View.DownCast(currentFocusedView);
337 public override void OnKeyboardFocusChangeCommitted(View commitedFocusableView)
343 // This override function is invoked before chosen focusable actor will be focused.
344 // This allows the application to preform any actions (i.e. Scroll and SpotLight animations) before the focus is actually moved to the chosen actor.
346 // This override function is invoked whenever a pan gesture is detected on this control.
347 // Perform Scroll Animation based upon pan gesture velocity / speed.
348 /*public override void OnPan(PanGesture pan)
350 return; //currently not used
353 // This function returns current focused actor
354 public View GetCurrentFocusedActor()
356 if (_focusedItem < 0)
361 return _itemList[_focusedItem];
364 public void SetFocused(bool focused)
366 _isFocused = focused;
368 // Perform Focus animation if the ScrollContainer is not focused already
371 Actor parent = _shadowBorder.Parent;
374 parent.Remove(_shadowBorder);
377 parent = _spotLight.Parent;
380 parent.Remove(_spotLight);
383 _focusTransitionAnimation.Clear();
385 for (int i = 0; i < _itemList.Count; ++i)
387 Position targetPosition = GetItemPosition(i, _currentScrollPosition);
389 _focusTransitionAnimation.AnimateTo(_itemList[i], "Position", targetPosition, new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine));
391 _focusTransitionAnimation.AnimateTo(_itemList[i], "Scale", new Size(1.0f, 1.0f, 1.0f), new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine));
394 _focusTransitionAnimation.Play();
402 // Obtain ID of first visible item/image on the screen of the ScrollContainer
403 private int GetFirstVisibleItemId()
405 int firstItemId = -1;
409 firstItemId = (int)Math.Floor((-1.0 * _currentScrollPosition + _marginX * 2.0f) / (_itemSize.Width + _gap));
413 firstItemId = (int)Math.Floor(-1.0 * _currentScrollPosition / (_itemSize.Width + _gap));
424 // Obtain ID of last visible item/image on the screen of the ScrollContainer
425 private int GetLastVisibleItemId()
431 lastItemId = (int)Math.Ceiling(((_width - _currentScrollPosition - _marginX * 2.0f) / _itemSize.Width) - 1);
435 lastItemId = (int)Math.Ceiling(((_width - _currentScrollPosition) / _itemSize.Width) - 1);
438 if (lastItemId >= _itemList.Count)
441 lastItemId = _itemList.Count - 1;
447 // Obtain Next item/image (Right of the currently focused item) of the ScrollContainer
448 private Actor FocusNext(bool loopEnabled)
452 if (_focusedItem < GetFirstVisibleItemId() || _focusedItem > GetLastVisibleItemId())
454 nextItem = GetFirstVisibleItemId();
458 nextItem = _focusedItem + 1;
461 if (nextItem >= _itemList.Count)
469 nextItem = _itemList.Count - 1;
473 _focusedItem = nextItem;
474 return _itemList[_focusedItem];
477 // Obtain Previous item/image (left of the currently focused item) of the ScrollContainer
478 private Actor FocusPrevious(bool loopEnabled)
480 int previousItem = -1;
482 if (_focusedItem < GetFirstVisibleItemId() || _focusedItem > GetLastVisibleItemId())
484 previousItem = GetFirstVisibleItemId();
488 previousItem = _focusedItem - 1;
491 if (previousItem < 0)
495 previousItem = _itemList.Count - 1;
503 _focusedItem = previousItem;
504 return _itemList[_focusedItem];
507 // Perform ScrollAnimation on each item
508 private void Scroll(float amount, int baseItem)
510 float tagetScrollPosition = _currentScrollPosition + amount;
511 float totalItemSize = _itemList.Count * (_itemSize.Width + _gap) + _gap + (_marginX * 2.0f);
513 float maxScrollPosition = _width - totalItemSize;
515 if (tagetScrollPosition < maxScrollPosition)
517 tagetScrollPosition = maxScrollPosition;
520 if (tagetScrollPosition > 0.0f)
522 tagetScrollPosition = 0.0f;
525 _scrollAnimation.Clear();
527 for (int i = 0; i < _itemList.Count; ++i)
529 Position targetPosition = GetItemPosition(i, tagetScrollPosition);
531 _scrollAnimation.AnimateTo(_itemList[i], "Position", targetPosition, new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine));
534 _currentScrollPosition = tagetScrollPosition;
535 _scrollAnimation.Play();
538 // This function uses ItemId as next FocusedItem and preforms Scroll and SpotLight animations on that item.
539 private void Focus(int itemId)
546 else if (itemId >= _itemList.Count)
548 itemId = _itemList.Count - 1;
551 _itemList[itemId].Add(_shadowBorder);
552 _itemList[itemId].Add(_spotLight);
554 // Perform Spot Light animation
555 if (_focusedItem != itemId && _spotLight != null)
557 _spotLightAnimation.Clear();
558 _spotLightAnimation.AnimatePath(_spotLight, _circularPath, new Vector3(0.0f, 0.0f, 0.0f));
559 _spotLightAnimation.Looping = true;
560 _spotLightAnimation.Play();
563 _focusedItem = itemId;
565 Position itemPosition = GetItemPosition(_focusedItem, _currentScrollPosition);
567 _focusAnimation.Clear();
569 float relativeItemPositionX = itemPosition.X - _itemSize.Width * 0.5f + (_stageSize.Width * 0.5f) + _offsetX;
570 if (relativeItemPositionX < _marginX + _offsetX + _gap)
572 float amount = _marginX + _offsetX + _gap - relativeItemPositionX;
573 Scroll(amount, itemId + 1); // Perform Scroll animation
575 else if (relativeItemPositionX + _itemSize.Width + _gap + _marginX > _stageSize.Width)
577 float amount = relativeItemPositionX + _marginX + _gap + _itemSize.Width - _stageSize.Width;
578 Scroll(-amount, itemId - 1); // Perform Scroll animation
582 // Perform animation when item is focused
583 for (int i = 0; i < _itemList.Count; ++i)
585 Position targetPosition = GetItemPosition(i, _currentScrollPosition);
587 _focusAnimation.AnimateTo(_itemList[i], "Position",targetPosition, new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine) );
591 for (int i = 0; i < _itemList.Count; ++i)
593 // Perform scale animation on Focused item
594 if (i == _focusedItem)
596 _focusAnimation.AnimateTo(_itemList[i], "Scale", new Size(1.2f, 1.2f, 1.2f), new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine));
601 _focusAnimation.AnimateTo(_itemList[i], "Scale", new Size(1.0f, 1.0f, 1.0f), new AlphaFunction(AlphaFunction.BuiltinFunctions.EaseOutSine) );
605 _focusAnimation.Play();
609 // Calculate Position of any item/image of ScrollContainer
610 private Position GetItemPosition(int itemId, float scrollPosition)
614 // used (_itemSize.Width * 0.5f) because of AnchorPointCenter
615 // used (_stageSize.Width * 0.5f) because of ParentOriginCenter
616 if (_focusedItem > itemId)
618 float positionX = (_itemSize.Width * itemId) + (_gap * (itemId + 1)) + scrollPosition + (_itemSize.Width * 0.5f) - (_stageSize.Width * 0.5f);
619 return new Position(positionX, -_itemSize.Height * _offsetYFactor, 0.0f);
621 else if (_focusedItem == itemId)
623 float positionX = (_itemSize.Width * itemId) + (_gap * (itemId + 1)) + scrollPosition + _marginX + (_itemSize.Width * 0.5f) - (_stageSize.Width * 0.5f);
624 return new Position(positionX, -_itemSize.Height * _offsetYFactor, 0.0f);
628 float positionX = (_itemSize.Width * itemId) + (_gap * (itemId + 1)) + scrollPosition + _marginX * 2.0f + (_itemSize.Width * 0.5f) - (_stageSize.Width * 0.5f);
629 return new Position(positionX, -_itemSize.Height * _offsetYFactor, 0.0f);
634 float positionX = (_itemSize.Width * itemId) + (_gap * (itemId + 1)) + scrollPosition + (_itemSize.Width * 0.5f) - (_stageSize.Width * 0.5f);
635 return new Position(positionX, -_itemSize.Height * _offsetYFactor, 0.0f);