namespace Tizen.NUI.Samples
{
- enum TOUCH_ANIMATION_STATE
- {
- NO_ANIMATION = 0,
- ON_ANIMATION,
- ON_FINISH_ANIMATION,
- END_ANIMATION = NO_ANIMATION
- };
-
- public class FrameUpdateCallbackTest : IExample
- {
-
- private static string resourcePath = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
- private static string[] BACKGROUND_IMAGE_PATH = {
+ enum TOUCH_ANIMATION_STATE
+ {
+ NO_ANIMATION = 0,
+ ON_ANIMATION,
+ ON_FINISH_ANIMATION,
+ END_ANIMATION = NO_ANIMATION
+ };
+
+ public class FrameUpdateCallbackTest : IExample
+ {
+
+ private static string resourcePath = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
+ private static string[] BACKGROUND_IMAGE_PATH = {
resourcePath + "/images/FrameUpdateCallbackTest/launcher_bg_02_nor.png",
resourcePath + "/images/FrameUpdateCallbackTest/launcher_bg_03_nor.png",
resourcePath + "/images/FrameUpdateCallbackTest/launcher_bg_04_nor.png",
resourcePath + "/images/FrameUpdateCallbackTest/launcher_bg_apps_nor.png"
};
- private static string[] APPS_IMAGE_PATH = {
+ private static string[] APPS_IMAGE_PATH = {
resourcePath + "/images/FrameUpdateCallbackTest/launcher_ic_culinary_nor.png",
resourcePath + "/images/FrameUpdateCallbackTest/launcher_ic_family_nor.png",
resourcePath + "/images/FrameUpdateCallbackTest/launcher_ic_ent_nor.png",
resourcePath + "/images/FrameUpdateCallbackTest/launcher_ic_homecare_nor.png"
};
- private static string[] APPS_ICON_NAME = {
+ private static string[] APPS_ICON_NAME = {
"Culinary",
"Family",
"Entertainment",
"Homecare"
};
- private static string[] CONTROL_IMAGE_PATH = {
+ private static string[] CONTROL_IMAGE_PATH = {
resourcePath + "/images/FrameUpdateCallbackTest/launcher_ic_apps_nor.png",
resourcePath + "/images/FrameUpdateCallbackTest/launcher_ic_settings_nor.png",
resourcePath + "/images/FrameUpdateCallbackTest/launcher_ic_viewinside_nor.png",
resourcePath + "/images/FrameUpdateCallbackTest/launcher_ic_internet_nor.png"
};
- private static string[] CONTROL_ICON_NAME = {
+ private static string[] CONTROL_ICON_NAME = {
"Apps",
"Settings",
"ViewInside",
"Internet"
};
- private const int FRAME_RATE = 60;
- private const int OBJECT_DELAY = 30;
- private const int OBJECT_SIZE = 150;
- private const int INITIAL_POSITION = 46;
- private const int DEFAULT_SPACE = 9;
- private const int DEVIDE_BAR_SIZE = 4;
+ private const int FRAME_RATE = 60;
+ private const int OBJECT_DELAY = 30;
+ private const int OBJECT_SIZE = 150;
+ private const int INITIAL_POSITION = 46;
+ private const int DEFAULT_SPACE = 9;
+ private const int DEVIDE_BAR_SIZE = 4;
- public class FrameUpdateCallback : FrameUpdateCallbackInterface
- {
- private int timeInterval;
-
- private uint containerId;
- private List<uint> viewId; ///< View ID in the container.
- private List<float> viewPosition;
-
- // Movement is position difference of Container from start position of this animation to current position.
- // Time interval between each containerMovement entry is 16 milliseconds(about 60 fps)
- // For example.
- // containerMovement[i] + containerStartPosition is the position of container after i*16 milliseconds from this animation started.
- private List<float> containerMovement;
-
- // latestMovement is actually current movement of container.
- private float latestMovement;
-
- // An icon of touchedViewIndex moves with container at the same time.
- // Each icon of (touchedViewIndex -/+ i) moves as following container after i*OBJECT_DELAY milliseconds.
- private int touchedViewIndex;
-
- // If every icon between mLeftIndext and rightIndex is stopped, this frame callback can be reset.
- // Then isResetTouchedViewPossible becomes true.
- private bool isResetTouchedViewPossible;
- private int leftIndex;
- private int rightIndex;
-
- // Total animation time from start to current.
- private float totalAnimationTime;
- // Total animation time from start to the time that last movement is added.
- private float previousTotalAnimationTime;
-
- // Start position of container in this animation.
- private float containerStartPosition;
- // Position of container at the time that last movement is added.
- private float previousContainerPosition;
-
- // This animation only need to save movement about (the number of view * OBJECT_DELAY) milliseconds.
- // and this size is updated when new view is added.
- // and, If the list of containerMovement size become larger than this size, remove unnecessary entries.
- private int requiredMovementSize;
- private bool needUpdateMovementSize;
-
- // current velocity.
- private float velocity;
- // dirty flag.
- private bool dirty;
-
- public FrameUpdateCallback()
- {
- viewId = new List<uint>();
- containerMovement = new List<float>();
- requiredMovementSize = 0;
- needUpdateMovementSize = false;
- isResetTouchedViewPossible = false;
- }
-
- public void ResetAnimationData()
- {
- SetLatestMovement(0.0f);
- containerMovement.Clear();
- totalAnimationTime = 0.0f;
- previousTotalAnimationTime = 0.0f;
- dirty = true;
- }
-
- public void SetTimeInterval(int interval)
- {
- needUpdateMovementSize = true;
- timeInterval = interval;
- }
-
- public void AddId(uint id)
- {
- viewId.Add(id);
- needUpdateMovementSize = true;
- }
-
- public void SetContainerId(uint id)
- {
- containerId = id;
- }
-
- public void SetContainerStartPosition(float position)
- {
- containerStartPosition = position;
- }
-
- public void SetLatestMovement(float movement)
- {
- latestMovement = movement;
- }
-
- public void ResetViewPosition()
- {
- viewPosition = Enumerable.Repeat(0.0f, viewId.Count).ToList();
- }
-
- public void SetViewPosition(int index, float position)
- {
- viewPosition[index] = position;
- }
-
- public void SetTouchedViewIndex(int controlIndex)
- {
- touchedViewIndex = controlIndex;
- }
-
- public void AddMovement(float movement)
- {
- containerMovement.Add(movement);
- }
-
- public void SetLeftIndex(int Index)
- {
- leftIndex = Index;
- }
-
- public void SetRightIndex(int Index)
- {
- rightIndex = Index;
- }
-
- public bool IsResetTouchedViewPossible()
- {
- return isResetTouchedViewPossible;
- }
- public void Dirty()
- {
- dirty = true;
- }
-
- public bool IsDirty()
- {
- return dirty;
- }
-
- public float GetVelocity()
- {
- return velocity;
- }
-
- private void ComputeNewPositions(int totalTime)
- {
- // save latestMovement to avoid interference between thread.
- float lastMovement = latestMovement;
- bool isStillMoving = true;
- for (int i = 0; i < viewId.Count; ++i)
- {
- if (i == touchedViewIndex)
- {
- continue;
- }
-
- // compute delay of view of i.
- int totalDelay = Math.Abs(i - touchedViewIndex) * OBJECT_DELAY;
- if (totalDelay > totalTime)
- {
- continue;
- }
-
- int actorTime = totalTime - totalDelay;
- int movementIndex = actorTime / timeInterval;
- float factor = (float)(actorTime - (movementIndex * timeInterval)) / (float)timeInterval;
- float movement;
- if (movementIndex >= containerMovement.Count - 1)
- {
- // 1. delay is zero(every view moves with container at the same time)
- // 2. after every icons are stopped and the finger is stopped to move, the movement is still not added more.
- // than the view has lastMovement.
- movement = lastMovement;
- }
- else if (movementIndex < 0)
- {
- // If this animation is just staarted and the view need to wait more.
- // movement is 0.
- movement = 0.0f;
- }
- else
- {
- // Get the movement of ith view by interpolating containerMovement
- movement = factor * containerMovement[movementIndex + 1] + (1.0f - factor) * containerMovement[movementIndex];
- }
-
- // Prevent to overlap of each views.
- float currentSpace = Math.Abs((viewPosition[i] + movement) - (viewPosition[touchedViewIndex] + lastMovement));
- float minimumSpace = (float)Math.Abs(viewPosition[i] - viewPosition[touchedViewIndex]);
- if (currentSpace < minimumSpace)
- {
- movement = lastMovement;
- }
-
- // check views in screen are still moving or stopped.
- float newPosition = viewPosition[i] + movement - lastMovement;
- if (i >= leftIndex && i <= rightIndex)
- {
- Vector3 previousPosition = new Vector3();
- GetPosition(viewId[i], previousPosition);
- if (Math.Abs(previousPosition.X - newPosition) >= 1.0f)
- {
- isStillMoving = false;
- }
- }
- // update new position.
- SetPosition(viewId[i], new Vector3(newPosition, 0.0f, 0.0f));
- }
- isResetTouchedViewPossible = isStillMoving;
- }
-
- public override void OnUpdate(float elapsedSeconds)
- {
- // second -> millisecond
- totalAnimationTime += elapsedSeconds * 1000.0f;
-
- Vector3 currentPosition = new Vector3();
- GetPosition(containerId, currentPosition);
-
- // Add new Movement, if there is change in position.
- // 1. if dirty(there is reserved event)
- // 2. if container position is changed.
- // 3. if every icons in screen is stopped
- if (dirty || currentPosition.X != previousContainerPosition || isResetTouchedViewPossible)
+ private const uint FRAME_UPDATE_CALLBACK_VERSION = 0u;
+
+ public class FrameUpdateCallback : FrameUpdateCallbackInterface
{
- dirty = false;
- if (totalAnimationTime >= containerMovement.Count * timeInterval)
- {
- // If the passed time is larger than timeInterval, add new movements.
- // If we need to add more than one, compute each movement by using interpolation.
- while (containerMovement.Count <= totalAnimationTime / timeInterval)
- {
- float factor = ((float)(containerMovement.Count * timeInterval) - previousTotalAnimationTime) / (totalAnimationTime - previousTotalAnimationTime);
- float movement = (float)(factor * currentPosition.X + (1.0f - factor) * previousContainerPosition) - containerStartPosition;
- AddMovement(movement);
- }
- // Compute velocity.
- // We need to compute velocity here to get reasonable value.
- velocity = (currentPosition.X - previousContainerPosition) / (totalAnimationTime - previousTotalAnimationTime);
- previousTotalAnimationTime = totalAnimationTime;
- previousContainerPosition = currentPosition.X;
- }
- }
- float currentMovement = currentPosition.X - containerStartPosition;
- SetLatestMovement(currentMovement);
+ private int timeInterval;
+
+ private uint containerId;
+ private List<uint> viewId; ///< View ID in the container.
+ private List<float> viewPosition;
+
+ // Movement is position difference of Container from start position of this animation to current position.
+ // Time interval between each containerMovement entry is 16 milliseconds(about 60 fps)
+ // For example.
+ // containerMovement[i] + containerStartPosition is the position of container after i*16 milliseconds from this animation started.
+ private List<float> containerMovement;
+
+ // latestMovement is actually current movement of container.
+ private float latestMovement;
+
+ // An icon of touchedViewIndex moves with container at the same time.
+ // Each icon of (touchedViewIndex -/+ i) moves as following container after i*OBJECT_DELAY milliseconds.
+ private int touchedViewIndex;
+
+ // If every icon between mLeftIndext and rightIndex is stopped, this frame callback can be reset.
+ // Then isResetTouchedViewPossible becomes true.
+ private bool isResetTouchedViewPossible;
+ private int leftIndex;
+ private int rightIndex;
+
+ // Total animation time from start to current.
+ private float totalAnimationTime;
+ // Total animation time from start to the time that last movement is added.
+ private float previousTotalAnimationTime;
+
+ // Start position of container in this animation.
+ private float containerStartPosition;
+ // Position of container at the time that last movement is added.
+ private float previousContainerPosition;
+
+ // This animation only need to save movement about (the number of view * OBJECT_DELAY) milliseconds.
+ // and this size is updated when new view is added.
+ // and, If the list of containerMovement size become larger than this size, remove unnecessary entries.
+ private int requiredMovementSize;
+ private bool needUpdateMovementSize;
+
+ // current velocity.
+ private float velocity;
+ // dirty flag.
+ private bool dirty;
+
+ // Check whether position changed at this frame, or not.
+ // If some position changed, let we keep rendering for next frame.
+ private bool positionChanged;
+
+ // Initialize base class that we will use OnUpdate with return.
+ public FrameUpdateCallback() : base(FRAME_UPDATE_CALLBACK_VERSION)
+ {
+ viewId = new List<uint>();
+ containerMovement = new List<float>();
+ requiredMovementSize = 0;
+ needUpdateMovementSize = false;
+ isResetTouchedViewPossible = false;
+ positionChanged = true;
+ }
- // Compute positions of each icon
- ComputeNewPositions((int)totalAnimationTime);
+ public void ResetAnimationData()
+ {
+ SetLatestMovement(0.0f);
+ containerMovement.Clear();
+ totalAnimationTime = 0.0f;
+ previousTotalAnimationTime = 0.0f;
+ dirty = true;
+ }
- // compute requiredMovementSize
- if (requiredMovementSize == 0 || needUpdateMovementSize)
- {
- needUpdateMovementSize = false;
- requiredMovementSize = viewId.Count * OBJECT_DELAY / timeInterval;
- }
+ public void SetTimeInterval(int interval)
+ {
+ needUpdateMovementSize = true;
+ timeInterval = interval;
+ }
- // Remove unnecessary movement for memory optimization.
- if (containerMovement.Count > requiredMovementSize * 2)
- {
- int movementNumberToRemove = containerMovement.Count - requiredMovementSize;
- containerMovement.RemoveRange(0, movementNumberToRemove);
- totalAnimationTime -= (float)(timeInterval * movementNumberToRemove);
- }
- }
- }
+ public void AddId(uint id)
+ {
+ viewId.Add(id);
+ needUpdateMovementSize = true;
+ positionChanged = true;
+ }
- private Window window;
+ public void SetContainerId(uint id)
+ {
+ containerId = id;
+ }
- private FrameUpdateCallback frameUpdateCallback; ///< An instance of our implementation of the FrameUpdateCallbackInterface.
+ public void SetContainerStartPosition(float position)
+ {
+ containerStartPosition = position;
+ }
- // Views for launcher
- private View baseView;
- private View controlView;
- private View layoutView;
+ public void SetLatestMovement(float movement)
+ {
+ latestMovement = movement;
+ }
- // Variables for animation
- private float previousTouchedPosition;
- private int touchedViewIndex;
- private TOUCH_ANIMATION_STATE animationState;
+ public void ResetViewPosition()
+ {
+ viewPosition = Enumerable.Repeat(0.0f, viewId.Count).ToList();
+ }
- private float leftDirectionLimit;
- private float rightDirectionLimit;
+ public void SetViewPosition(int index, float position)
+ {
+ viewPosition[index] = position;
+ }
+ public void SetTouchedViewIndex(int controlIndex)
+ {
+ touchedViewIndex = controlIndex;
+ }
- // Variables for Finish animation
- // These variables are for deceleration curve.
- // If we want to use another curve like bezier, uses different variables
- private delegate float UserAlphaFunctionDelegate(float progress);
- private UserAlphaFunctionDelegate customScrollAlphaFunction;
- private float absoluteVelocity = 0.0f;
- private float finishAnimationDuration = 0.0f;
- private float finishAnimationDelta = 0.0f;
- private float logDeceleration = 0.0f;
- private float decelerationRate = 0.99f;
- private float easingThreshold = 0.1f;
+ public void AddMovement(float movement)
+ {
+ containerMovement.Add(movement);
+ }
- private Animation finishAnimation;
- private Timer animationOffTimer; // timer to end animation after the easing animation is finished
+ public void SetLeftIndex(int Index)
+ {
+ leftIndex = Index;
+ }
- // Vies of contents
- private View contentsView;
+ public void SetRightIndex(int Index)
+ {
+ rightIndex = Index;
+ }
- public void Activate()
- {
- frameUpdateCallback = new FrameUpdateCallback();
- Initialize();
- }
+ public bool IsResetTouchedViewPossible()
+ {
+ return isResetTouchedViewPossible;
+ }
+ public void Dirty()
+ {
+ dirty = true;
+ }
- public void Deactivate()
- {
- }
+ public bool IsDirty()
+ {
+ return dirty;
+ }
- void Initialize()
- {
- // Set the stage background color and connect to the stage's key signal to allow Back and Escape to exit.
- window = Window.Instance;
- window.BackgroundColor = Color.White;
-
- rightDirectionLimit = INITIAL_POSITION;
-
- // Contents
-
- contentsView = new View();
- contentsView.BackgroundColor = new Color(0.921568f, 0.9098039f, 0.890196f, 0.5f);
- contentsView.ParentOrigin = ParentOrigin.TopLeft;
- contentsView.PivotPoint = PivotPoint.TopLeft;
- contentsView.PositionUsesPivotPoint = true;
- contentsView.WidthResizePolicy = ResizePolicyType.FillToParent;
- contentsView.HeightResizePolicy = ResizePolicyType.FillToParent;
- window.GetDefaultLayer().Add(contentsView);
-
- // Launcher
- baseView = new View();
- baseView.ParentOrigin = ParentOrigin.BottomLeft;
- baseView.PivotPoint = PivotPoint.BottomLeft;
- baseView.PositionUsesPivotPoint = true;
- baseView.Size = new Size(window.Size.Width, 278);
- baseView.Position = new Position(0, 0);
- window.GetDefaultLayer().Add(baseView);
-
- View iconBackgroundView = new View();
- iconBackgroundView.BackgroundColor = new Color(0.921568f, 0.9098039f, 0.890196f, 0.5f);
- iconBackgroundView.ParentOrigin = ParentOrigin.BottomLeft;
- iconBackgroundView.PivotPoint = PivotPoint.BottomLeft;
- iconBackgroundView.PositionUsesPivotPoint = true;
- iconBackgroundView.Size = new Size(window.Size.Width, 278);
- iconBackgroundView.Position = new Position(0, 0);
- baseView.Add(iconBackgroundView);
-
- controlView = new View();
- controlView.ParentOrigin = ParentOrigin.CenterLeft;
- controlView.PivotPoint = PivotPoint.CenterLeft;
- controlView.PositionUsesPivotPoint = true;
- controlView.Position = new Position(rightDirectionLimit, 0);
- baseView.Add(controlView);
- frameUpdateCallback.SetContainerId(controlView.ID);
-
- layoutView = new View();
- layoutView.ParentOrigin = ParentOrigin.CenterLeft;
- layoutView.PivotPoint = PivotPoint.CenterLeft;
- layoutView.PositionUsesPivotPoint = true;
- layoutView.Layout = new LinearLayout()
- {
- LinearOrientation = LinearLayout.Orientation.Horizontal,
- CellPadding = new Size2D(DEFAULT_SPACE, 0),
- };
- layoutView.Position = new Position(0, 0);
- controlView.Add(layoutView);
-
- for (int i = 0; i < 4; ++i)
- {
- AddIcon(BACKGROUND_IMAGE_PATH[i], APPS_IMAGE_PATH[i], APPS_ICON_NAME[i], Color.White);
- }
-
- View divideBar = new View();
- divideBar.BackgroundColor = new Color(0.0f, 0.0f, 0.0f, 0.1f);
- divideBar.ParentOrigin = ParentOrigin.CenterLeft;
- divideBar.PivotPoint = PivotPoint.CenterLeft;
- divideBar.PositionUsesPivotPoint = true;
- divideBar.Size = new Size(DEVIDE_BAR_SIZE, OBJECT_SIZE);
- layoutView.Add(divideBar);
- frameUpdateCallback.AddId(divideBar.ID);
-
- int iconNumber = 8;
- for (int i = 0; i < iconNumber; ++i)
- {
- AddIcon(BACKGROUND_IMAGE_PATH[5], CONTROL_IMAGE_PATH[i % 5], CONTROL_ICON_NAME[i % 5], new Color(0.0f, 0.0f, 0.0f, 0.5f));
- }
-
- frameUpdateCallback.ResetViewPosition();
- frameUpdateCallback.SetTimeInterval(1000 / FRAME_RATE);
-
- animationState = TOUCH_ANIMATION_STATE.NO_ANIMATION;
-
- animationOffTimer = new Timer(16);
- animationOffTimer.Tick += OffAnimatable;
-
- baseView.TouchEvent += OnTouch;
-
- finishAnimation = new Animation();
- finishAnimation.Finished += EasingAnimationFinishedCallback;
- logDeceleration = (float)Math.Log(decelerationRate);
- }
+ public float GetVelocity()
+ {
+ return velocity;
+ }
- // Add icons
+ private void ComputeNewPositions(int totalTime)
+ {
+ // save latestMovement to avoid interference between thread.
+ float lastMovement = latestMovement;
+ bool isStillMoving = true;
+ for (int i = 0; i < viewId.Count; ++i)
+ {
+ if (i == touchedViewIndex)
+ {
+ continue;
+ }
+
+ // compute delay of view of i.
+ int totalDelay = Math.Abs(i - touchedViewIndex) * OBJECT_DELAY;
+ if (totalDelay > totalTime)
+ {
+ continue;
+ }
+
+ int actorTime = totalTime - totalDelay;
+ int movementIndex = actorTime / timeInterval;
+ float factor = (float)(actorTime - (movementIndex * timeInterval)) / (float)timeInterval;
+ float movement;
+ if (movementIndex >= containerMovement.Count - 1)
+ {
+ // 1. delay is zero(every view moves with container at the same time)
+ // 2. after every icons are stopped and the finger is stopped to move, the movement is still not added more.
+ // than the view has lastMovement.
+ movement = lastMovement;
+ }
+ else if (movementIndex < 0)
+ {
+ // If this animation is just staarted and the view need to wait more.
+ // movement is 0.
+ movement = 0.0f;
+ }
+ else
+ {
+ // Get the movement of ith view by interpolating containerMovement
+ movement = factor * containerMovement[movementIndex + 1] + (1.0f - factor) * containerMovement[movementIndex];
+ }
+
+ // Prevent to overlap of each views.
+ float currentSpace = Math.Abs((viewPosition[i] + movement) - (viewPosition[touchedViewIndex] + lastMovement));
+ float minimumSpace = (float)Math.Abs(viewPosition[i] - viewPosition[touchedViewIndex]);
+ if (currentSpace < minimumSpace)
+ {
+ movement = lastMovement;
+ }
+
+ // check views in screen are still moving or stopped.
+ float newPosition = viewPosition[i] + movement - lastMovement;
+ if (i >= leftIndex && i <= rightIndex)
+ {
+ Vector3 previousPosition = new Vector3();
+ GetPosition(viewId[i], previousPosition);
+ if (Math.Abs(previousPosition.X - newPosition) >= 1.0f)
+ {
+ isStillMoving = false;
+ }
+ }
+ // update new position.
+ SetPosition(viewId[i], new Vector3(newPosition, 0.0f, 0.0f));
+ positionChanged = true;
+ }
+ isResetTouchedViewPossible = isStillMoving;
+ }
- void AddIcon(string background, string icon, string text, Color textColor)
- {
- ImageView backgroundView = new ImageView();
- backgroundView.ResourceUrl = background;
- backgroundView.Size = new Size(OBJECT_SIZE, OBJECT_SIZE);
- backgroundView.ParentOrigin = ParentOrigin.CenterLeft;
- backgroundView.PivotPoint = PivotPoint.CenterLeft;
- backgroundView.PositionUsesPivotPoint = true;
- layoutView.Add(backgroundView);
- frameUpdateCallback.AddId(backgroundView.ID);
-
- ImageView iconView = new ImageView();
- iconView.ResourceUrl = icon;
- iconView.Position = new Position(0, -15);
- iconView.ParentOrigin = ParentOrigin.Center;
- iconView.PivotPoint = PivotPoint.Center;
- iconView.PositionUsesPivotPoint = true;
- backgroundView.Add(iconView);
-
- TextLabel label = new TextLabel(text);
- label.Position = new Position(0, 30);
- label.HorizontalAlignment = HorizontalAlignment.Center;
- label.TextColor = textColor;
- label.FontFamily = "SamsungOneUI";
- label.PointSize = 12;
- label.ParentOrigin = ParentOrigin.Center;
- label.PivotPoint = PivotPoint.Center;
- label.PositionUsesPivotPoint = true;
- backgroundView.Add(label);
- }
+ public override void OnUpdate(float elapsedSeconds)
+ {
+ // FRAME_UPDATE_CALLBACK_VERSION == 0u
+ OnUpdate(this, elapsedSeconds);
+ }
- // Set frame callback to start drag animation.
- private void SetFrameUpdateCallback(float position)
- {
- // remove frame callback if it is already added.
- window.RemoveFrameUpdateCallback(frameUpdateCallback);
-
- frameUpdateCallback.ResetAnimationData();
- frameUpdateCallback.AddMovement(0.0f); // Add first movement.
-
- // Set container start position and start positions of each icon(and vertical bar)
- // And compute total container size.
- float totalSize = 0.0f;
- frameUpdateCallback.SetContainerStartPosition(controlView.Position.X);
- for (int i = 0; i < layoutView.ChildCount; ++i)
- {
- frameUpdateCallback.SetViewPosition(i, layoutView.Children[i].Position.X);
- totalSize += (float)(layoutView.Children[i].Size.Width + DEFAULT_SPACE);
- }
- totalSize -= (float)DEFAULT_SPACE;
-
- // Find touched icon
- for (int i = (int)layoutView.ChildCount - 1; i >= 0; --i)
- {
- if (position >= layoutView.Children[i].Position.X + controlView.Position.X)
- {
- frameUpdateCallback.SetTouchedViewIndex(i);
- touchedViewIndex = i;
- break;
+ public override bool OnUpdate(FrameUpdateCallbackInterface obj /* Not using */, float elapsedSeconds)
+ {
+ // FRAME_UPDATE_CALLBACK_VERSION == 1u
+
+ // second -> millisecond
+ totalAnimationTime += elapsedSeconds * 1000.0f;
+
+ Vector3 currentPosition = new Vector3();
+ GetPosition(containerId, currentPosition);
+
+ // Add new Movement, if there is change in position.
+ // 1. if dirty(there is reserved event)
+ // 2. if container position is changed.
+ // 3. if every icons in screen is stopped
+ if (dirty || currentPosition.X != previousContainerPosition || isResetTouchedViewPossible)
+ {
+ dirty = false;
+ if (totalAnimationTime >= containerMovement.Count * timeInterval)
+ {
+ // If the passed time is larger than timeInterval, add new movements.
+ // If we need to add more than one, compute each movement by using interpolation.
+ while (containerMovement.Count <= totalAnimationTime / timeInterval)
+ {
+ float factor = ((float)(containerMovement.Count * timeInterval) - previousTotalAnimationTime) / (totalAnimationTime - previousTotalAnimationTime);
+ float movement = (float)(factor * currentPosition.X + (1.0f - factor) * previousContainerPosition) - containerStartPosition;
+ AddMovement(movement);
+ }
+ // Compute velocity.
+ // We need to compute velocity here to get reasonable value.
+ velocity = (currentPosition.X - previousContainerPosition) / (totalAnimationTime - previousTotalAnimationTime);
+ previousTotalAnimationTime = totalAnimationTime;
+ previousContainerPosition = currentPosition.X;
+ }
+ }
+ float currentMovement = currentPosition.X - containerStartPosition;
+ SetLatestMovement(currentMovement);
+
+ // Compute positions of each icon
+ ComputeNewPositions((int)totalAnimationTime);
+
+ // compute requiredMovementSize
+ if (requiredMovementSize == 0 || needUpdateMovementSize)
+ {
+ needUpdateMovementSize = false;
+ requiredMovementSize = viewId.Count * OBJECT_DELAY / timeInterval;
+ }
+
+ // Remove unnecessary movement for memory optimization.
+ if (containerMovement.Count > requiredMovementSize * 2)
+ {
+ int movementNumberToRemove = containerMovement.Count - requiredMovementSize;
+ containerMovement.RemoveRange(0, movementNumberToRemove);
+ totalAnimationTime -= (float)(timeInterval * movementNumberToRemove);
+ }
+
+ // Reset flag
+ bool retValue = positionChanged;
+ positionChanged = false;
+ return retValue;
+ }
}
- }
- if (position < layoutView.Children[0].Position.X + controlView.Position.X)
- {
- frameUpdateCallback.SetTouchedViewIndex(0);
- touchedViewIndex = 0;
- }
- previousTouchedPosition = position;
+ private Window window;
- // Add frame callback on window.
- // OnUpdate callback of frameUpdateCallback will be called before every render frame.
- // We can set root view what given frameUpdateCallback used
- window.AddFrameUpdateCallback(frameUpdateCallback, controlView);
+ private FrameUpdateCallback frameUpdateCallback; // An instance of our implementation of the FrameUpdateCallbackInterface.
- // compute limit position the container could go.
- leftDirectionLimit = (float)window.Size.Width - (totalSize + (float)(INITIAL_POSITION));
+ // Views for launcher
+ private View baseView;
+ private View controlView;
+ private View layoutView;
- window.RenderingBehavior = RenderingBehaviorType.Continuously; // make rendering be done for upto 60 fps even though there is no update in main thread.
- animationState = TOUCH_ANIMATION_STATE.ON_ANIMATION; // make rendering state on.
- }
+ // Variables for animation
+ private float previousTouchedPosition;
+ private int touchedViewIndex;
+ private TOUCH_ANIMATION_STATE animationState;
- private bool OnTouch(object source, View.TouchEventArgs e)
- {
- Vector2 position = e.Touch.GetScreenPosition(0);
+ private float leftDirectionLimit;
+ private float rightDirectionLimit;
+
+
+ // Variables for Finish animation
+ // These variables are for deceleration curve.
+ // If we want to use another curve like bezier, uses different variables
+ private delegate float UserAlphaFunctionDelegate(float progress);
+ private UserAlphaFunctionDelegate customScrollAlphaFunction;
+ private float absoluteVelocity = 0.0f;
+ private float finishAnimationDuration = 0.0f;
+ private float finishAnimationDelta = 0.0f;
+ private float logDeceleration = 0.0f;
+ private float decelerationRate = 0.99f;
+ private float easingThreshold = 0.1f;
- PointStateType state = e.Touch.GetState(0);
- if (PointStateType.Down == state)
- {
- if (animationState == TOUCH_ANIMATION_STATE.ON_FINISH_ANIMATION)
+ private Animation finishAnimation;
+ private Timer animationOffTimer; // timer to end animation after the easing animation is finished
+
+ // Vies of contents
+ private View contentsView;
+
+ public void Activate()
{
- // re-birth current animation
- // in case of touch during finish animation,
- // quit easingAnimation and AnimationOffTimer because animation ownership is returned to the touch event again.
- // AND, DO NOT RESET ALL PROPERTIES OF FRAMECALLBACK.
- // because, for example, if touched icon index is changed, the movement is wrong and the animation can be not continous.
- // This re-birthed animation is just for smooth moving during complex user interaction.
- // during complex and fast interaction, this is not so noticeable.
- // and reset of such properties will be done in the below Motion state
- finishAnimation.Stop();
- animationOffTimer.Stop();
-
- // Set Animation State to ON_ANIMATION again
- animationState = TOUCH_ANIMATION_STATE.ON_ANIMATION;
- // Set previousTouchPosition
- previousTouchedPosition = position.X;
+ frameUpdateCallback = new FrameUpdateCallback();
+ Initialize();
}
- else
+
+ public void Deactivate()
{
- // in case of stable state
- // just set new framecallback for this touched position.
- SetFrameUpdateCallback(position.X);
}
- }
- else if (PointStateType.Motion == state)
- {
- // if framecallback can be reset, quit current frame callback and re-launch new frame callback.
- // because, if current frame callback is re-birthed one, the animation is not totally re-created one.
- // So, some properties like touched icon index can be wrong for the continuous animation.
- // But, some case like that finger is stopped and restart to move, this could make weired feeling.
- // We reset frameUpdateCallback as soon as possible we can. And the conditions are ...
- // 1. icons in screen is stopped.
- // 2. velocity of frame callback is 0.0 (this frame callback will not move again instantly)
- // 3. frame callback is not dirty (there is no reserved action)
- if (frameUpdateCallback.IsResetTouchedViewPossible() && frameUpdateCallback.GetVelocity() == 0.0f && !frameUpdateCallback.IsDirty())
+
+ void Initialize()
{
- SetFrameUpdateCallback(position.X);
+ // Set the stage background color and connect to the stage's key signal to allow Back and Escape to exit.
+ window = Window.Instance;
+ window.BackgroundColor = Color.White;
+
+ rightDirectionLimit = INITIAL_POSITION;
+
+ // Contents
+
+ contentsView = new View();
+ contentsView.BackgroundColor = new Color(0.921568f, 0.9098039f, 0.890196f, 0.5f);
+ contentsView.ParentOrigin = ParentOrigin.TopLeft;
+ contentsView.PivotPoint = PivotPoint.TopLeft;
+ contentsView.PositionUsesPivotPoint = true;
+ contentsView.WidthResizePolicy = ResizePolicyType.FillToParent;
+ contentsView.HeightResizePolicy = ResizePolicyType.FillToParent;
+ window.GetDefaultLayer().Add(contentsView);
+
+ // Launcher
+ baseView = new View();
+ baseView.ParentOrigin = ParentOrigin.BottomLeft;
+ baseView.PivotPoint = PivotPoint.BottomLeft;
+ baseView.PositionUsesPivotPoint = true;
+ baseView.Size = new Size(window.Size.Width, 278);
+ baseView.Position = new Position(0, 0);
+ window.GetDefaultLayer().Add(baseView);
+
+ View iconBackgroundView = new View();
+ iconBackgroundView.BackgroundColor = new Color(0.921568f, 0.9098039f, 0.890196f, 0.5f);
+ iconBackgroundView.ParentOrigin = ParentOrigin.BottomLeft;
+ iconBackgroundView.PivotPoint = PivotPoint.BottomLeft;
+ iconBackgroundView.PositionUsesPivotPoint = true;
+ iconBackgroundView.Size = new Size(window.Size.Width, 278);
+ iconBackgroundView.Position = new Position(0, 0);
+ baseView.Add(iconBackgroundView);
+
+ controlView = new View();
+ controlView.ParentOrigin = ParentOrigin.CenterLeft;
+ controlView.PivotPoint = PivotPoint.CenterLeft;
+ controlView.PositionUsesPivotPoint = true;
+ controlView.Position = new Position(rightDirectionLimit, 0);
+ baseView.Add(controlView);
+ frameUpdateCallback.SetContainerId(controlView.ID);
+
+ layoutView = new View();
+ layoutView.ParentOrigin = ParentOrigin.CenterLeft;
+ layoutView.PivotPoint = PivotPoint.CenterLeft;
+ layoutView.PositionUsesPivotPoint = true;
+ layoutView.Layout = new LinearLayout()
+ {
+ LinearOrientation = LinearLayout.Orientation.Horizontal,
+ CellPadding = new Size2D(DEFAULT_SPACE, 0),
+ };
+ layoutView.Position = new Position(0, 0);
+ controlView.Add(layoutView);
+
+ for (int i = 0; i < 4; ++i)
+ {
+ AddIcon(BACKGROUND_IMAGE_PATH[i], APPS_IMAGE_PATH[i], APPS_ICON_NAME[i], Color.White);
+ }
+
+ View divideBar = new View();
+ divideBar.BackgroundColor = new Color(0.0f, 0.0f, 0.0f, 0.1f);
+ divideBar.ParentOrigin = ParentOrigin.CenterLeft;
+ divideBar.PivotPoint = PivotPoint.CenterLeft;
+ divideBar.PositionUsesPivotPoint = true;
+ divideBar.Size = new Size(DEVIDE_BAR_SIZE, OBJECT_SIZE);
+ layoutView.Add(divideBar);
+ frameUpdateCallback.AddId(divideBar.ID);
+
+ int iconNumber = 8;
+ for (int i = 0; i < iconNumber; ++i)
+ {
+ AddIcon(BACKGROUND_IMAGE_PATH[5], CONTROL_IMAGE_PATH[i % 5], CONTROL_ICON_NAME[i % 5], new Color(0.0f, 0.0f, 0.0f, 0.5f));
+ }
+
+ frameUpdateCallback.ResetViewPosition();
+ frameUpdateCallback.SetTimeInterval(1000 / FRAME_RATE);
+
+ animationState = TOUCH_ANIMATION_STATE.NO_ANIMATION;
+
+ animationOffTimer = new Timer(16);
+ animationOffTimer.Tick += OffAnimatable;
+
+ baseView.TouchEvent += OnTouch;
+
+ finishAnimation = new Animation();
+ finishAnimation.Finished += EasingAnimationFinishedCallback;
+ logDeceleration = (float)Math.Log(decelerationRate);
}
- // Set new controlView(container) position
- // in here, we need to consider the container is not go outside of limits.
- float containerPosition = controlView.Position.X + (position.X - previousTouchedPosition);
- containerPosition = Math.Min(containerPosition, rightDirectionLimit);
- containerPosition = Math.Max(containerPosition, leftDirectionLimit);
- float adjustedPosition = containerPosition - controlView.Position.X + previousTouchedPosition;
- previousTouchedPosition = adjustedPosition;
- controlView.Position.X = containerPosition;
- }
- else if ((PointStateType.Up == state || PointStateType.Leave == state || PointStateType.Interrupted == state) &&
- animationState == TOUCH_ANIMATION_STATE.ON_ANIMATION)
- {
- animationState = TOUCH_ANIMATION_STATE.ON_FINISH_ANIMATION;
-
- // To launch finish animation, we get latest velocty from frame callback
- float lastVelocity = frameUpdateCallback.GetVelocity();
-
- /* TUNING */
- // This is just for turning of finish animation.
- // change the values if you want.
- lastVelocity = Math.Max(lastVelocity, -3.5f);
- lastVelocity = Math.Min(lastVelocity, 3.5f);
- if (Math.Abs(lastVelocity) < 0.0001f)
+ // Add icons
+
+ void AddIcon(string background, string icon, string text, Color textColor)
{
- // If velocity is zero. just start animationOfftimer.
- animationOffTimer.Start();
+ ImageView backgroundView = new ImageView();
+ backgroundView.ResourceUrl = background;
+ backgroundView.Size = new Size(OBJECT_SIZE, OBJECT_SIZE);
+ backgroundView.ParentOrigin = ParentOrigin.CenterLeft;
+ backgroundView.PivotPoint = PivotPoint.CenterLeft;
+ backgroundView.PositionUsesPivotPoint = true;
+ layoutView.Add(backgroundView);
+ frameUpdateCallback.AddId(backgroundView.ID);
+
+ ImageView iconView = new ImageView();
+ iconView.ResourceUrl = icon;
+ iconView.Position = new Position(0, -15);
+ iconView.ParentOrigin = ParentOrigin.Center;
+ iconView.PivotPoint = PivotPoint.Center;
+ iconView.PositionUsesPivotPoint = true;
+ backgroundView.Add(iconView);
+
+ TextLabel label = new TextLabel(text);
+ label.Position = new Position(0, 30);
+ label.HorizontalAlignment = HorizontalAlignment.Center;
+ label.TextColor = textColor;
+ label.FontFamily = "SamsungOneUI";
+ label.PointSize = 12;
+ label.ParentOrigin = ParentOrigin.Center;
+ label.PivotPoint = PivotPoint.Center;
+ label.PositionUsesPivotPoint = true;
+ backgroundView.Add(label);
}
- else
+
+ // Set frame callback to start drag animation.
+ private void SetFrameUpdateCallback(float position)
{
- // If velocity is not zero, make decelerating animation.
- Decelerating(lastVelocity);
+ // remove frame callback if it is already added.
+ window.RemoveFrameUpdateCallback(frameUpdateCallback);
+
+ frameUpdateCallback.ResetAnimationData();
+ frameUpdateCallback.AddMovement(0.0f); // Add first movement.
+
+ // Set container start position and start positions of each icon(and vertical bar)
+ // And compute total container size.
+ float totalSize = 0.0f;
+ frameUpdateCallback.SetContainerStartPosition(controlView.Position.X);
+ for (int i = 0; i < layoutView.ChildCount; ++i)
+ {
+ frameUpdateCallback.SetViewPosition(i, layoutView.Children[i].Position.X);
+ totalSize += (float)(layoutView.Children[i].Size.Width + DEFAULT_SPACE);
+ }
+ totalSize -= (float)DEFAULT_SPACE;
+
+ // Find touched icon
+ for (int i = (int)layoutView.ChildCount - 1; i >= 0; --i)
+ {
+ if (position >= layoutView.Children[i].Position.X + controlView.Position.X)
+ {
+ frameUpdateCallback.SetTouchedViewIndex(i);
+ touchedViewIndex = i;
+ break;
+ }
+ }
+ if (position < layoutView.Children[0].Position.X + controlView.Position.X)
+ {
+ frameUpdateCallback.SetTouchedViewIndex(0);
+ touchedViewIndex = 0;
+ }
+
+ previousTouchedPosition = position;
+
+ // Add frame callback on window.
+ // OnUpdate callback of frameUpdateCallback will be called before every render frame.
+ // We can set root view what given frameUpdateCallback used
+ window.AddFrameUpdateCallback(frameUpdateCallback, controlView);
+
+ // compute limit position the container could go.
+ leftDirectionLimit = (float)window.Size.Width - (totalSize + (float)(INITIAL_POSITION));
+
+ window.RenderingBehavior = RenderingBehaviorType.Continuously; // make rendering be done for upto 60 fps even though there is no update in main thread.
+ animationState = TOUCH_ANIMATION_STATE.ON_ANIMATION; // make rendering state on.
}
- }
- // set currently visible icons for optimization
- SetVisibleLimit();
- // make frame callback dirty.
- frameUpdateCallback.Dirty();
- return true;
- }
- private void SetVisibleLimit()
- {
- int leftViewIndex = touchedViewIndex;
- for (; leftViewIndex >= 0; --leftViewIndex)
- {
- float newPosition = layoutView.Children[leftViewIndex].Position.X + controlView.Position.X;
- if (newPosition + (float)layoutView.Children[leftViewIndex].Size.Width < 0.0f)
+ private bool OnTouch(object source, View.TouchEventArgs e)
{
- break;
+ Vector2 position = e.Touch.GetScreenPosition(0);
+
+ PointStateType state = e.Touch.GetState(0);
+ if (PointStateType.Down == state)
+ {
+ if (animationState == TOUCH_ANIMATION_STATE.ON_FINISH_ANIMATION)
+ {
+ // re-birth current animation
+ // in case of touch during finish animation,
+ // quit easingAnimation and AnimationOffTimer because animation ownership is returned to the touch event again.
+ // AND, DO NOT RESET ALL PROPERTIES OF FRAMECALLBACK.
+ // because, for example, if touched icon index is changed, the movement is wrong and the animation can be not continous.
+ // This re-birthed animation is just for smooth moving during complex user interaction.
+ // during complex and fast interaction, this is not so noticeable.
+ // and reset of such properties will be done in the below Motion state
+ finishAnimation.Stop();
+ animationOffTimer.Stop();
+
+ // Set Animation State to ON_ANIMATION again
+ animationState = TOUCH_ANIMATION_STATE.ON_ANIMATION;
+ // Set previousTouchPosition
+ previousTouchedPosition = position.X;
+ }
+ else
+ {
+ // in case of stable state
+ // just set new framecallback for this touched position.
+ SetFrameUpdateCallback(position.X);
+ }
+ }
+ else if (PointStateType.Motion == state)
+ {
+ // if framecallback can be reset, quit current frame callback and re-launch new frame callback.
+ // because, if current frame callback is re-birthed one, the animation is not totally re-created one.
+ // So, some properties like touched icon index can be wrong for the continuous animation.
+ // But, some case like that finger is stopped and restart to move, this could make weired feeling.
+ // We reset frameUpdateCallback as soon as possible we can. And the conditions are ...
+ // 1. icons in screen is stopped.
+ // 2. velocity of frame callback is 0.0 (this frame callback will not move again instantly)
+ // 3. frame callback is not dirty (there is no reserved action)
+ if (frameUpdateCallback.IsResetTouchedViewPossible() && frameUpdateCallback.GetVelocity() == 0.0f && !frameUpdateCallback.IsDirty())
+ {
+ SetFrameUpdateCallback(position.X);
+ }
+
+ // Set new controlView(container) position
+ // in here, we need to consider the container is not go outside of limits.
+ float containerPosition = controlView.Position.X + (position.X - previousTouchedPosition);
+ containerPosition = Math.Min(containerPosition, rightDirectionLimit);
+ containerPosition = Math.Max(containerPosition, leftDirectionLimit);
+ float adjustedPosition = containerPosition - controlView.Position.X + previousTouchedPosition;
+ previousTouchedPosition = adjustedPosition;
+ controlView.Position.X = containerPosition;
+ }
+ else if ((PointStateType.Up == state || PointStateType.Leave == state || PointStateType.Interrupted == state) &&
+ animationState == TOUCH_ANIMATION_STATE.ON_ANIMATION)
+ {
+ animationState = TOUCH_ANIMATION_STATE.ON_FINISH_ANIMATION;
+
+ // To launch finish animation, we get latest velocty from frame callback
+ float lastVelocity = frameUpdateCallback.GetVelocity();
+
+ /* TUNING */
+ // This is just for turning of finish animation.
+ // change the values if you want.
+ lastVelocity = Math.Max(lastVelocity, -3.5f);
+ lastVelocity = Math.Min(lastVelocity, 3.5f);
+ if (Math.Abs(lastVelocity) < 0.0001f)
+ {
+ // If velocity is zero. just start animationOfftimer.
+ animationOffTimer.Start();
+ }
+ else
+ {
+ // If velocity is not zero, make decelerating animation.
+ Decelerating(lastVelocity);
+ }
+ }
+ // set currently visible icons for optimization
+ SetVisibleLimit();
+ // make frame callback dirty.
+ frameUpdateCallback.Dirty();
+ return true;
}
- }
- leftViewIndex = Math.Max(leftViewIndex, 0);
- int rightViewIndex = touchedViewIndex;
- for (; rightViewIndex < layoutView.ChildCount; ++rightViewIndex)
- {
- float newPosition = layoutView.Children[rightViewIndex].Position.X + controlView.Position.X;
- if (newPosition > window.Size.Width)
+
+ private void SetVisibleLimit()
{
- break;
- }
- }
- rightViewIndex = Math.Min(rightViewIndex, (int)layoutView.ChildCount - 1);
+ int leftViewIndex = touchedViewIndex;
+ for (; leftViewIndex >= 0; --leftViewIndex)
+ {
+ float newPosition = layoutView.Children[leftViewIndex].Position.X + controlView.Position.X;
+ if (newPosition + (float)layoutView.Children[leftViewIndex].Size.Width < 0.0f)
+ {
+ break;
+ }
+ }
+ leftViewIndex = Math.Max(leftViewIndex, 0);
+ int rightViewIndex = touchedViewIndex;
+ for (; rightViewIndex < layoutView.ChildCount; ++rightViewIndex)
+ {
+ float newPosition = layoutView.Children[rightViewIndex].Position.X + controlView.Position.X;
+ if (newPosition > window.Size.Width)
+ {
+ break;
+ }
+ }
+ rightViewIndex = Math.Min(rightViewIndex, (int)layoutView.ChildCount - 1);
- frameUpdateCallback.SetLeftIndex(leftViewIndex);
- frameUpdateCallback.SetRightIndex(rightViewIndex);
- }
+ frameUpdateCallback.SetLeftIndex(leftViewIndex);
+ frameUpdateCallback.SetRightIndex(rightViewIndex);
+ }
- // set decelerating properties
- // in this example, we used decelerate animation in "https://medium.com/@esskeetit/scrolling-mechanics-of-uiscrollview-142adee1142c"
- // But, if this method is problematic or violate some patent of other company, change this other way.
- // We didn't checked anything.
- // Only thing we need to remember when we change this animation is to add "EasingAnimationFinishedCallback" for the new animation.
- private void Decelerating(float lastVelocity)
- {
- absoluteVelocity = Math.Abs(lastVelocity);
- finishAnimationDelta = (absoluteVelocity * decelerationRate) / (1 - decelerationRate);
- float destination = (lastVelocity > 0) ? controlView.Position.X + finishAnimationDelta : controlView.Position.X - finishAnimationDelta;
-
- if (destination < leftDirectionLimit || destination > rightDirectionLimit)
- {
- finishAnimationDelta = lastVelocity > 0 ? (rightDirectionLimit - controlView.Position.X) : (controlView.Position.X - leftDirectionLimit);
- destination = lastVelocity > 0 ? rightDirectionLimit : leftDirectionLimit;
- if (finishAnimationDelta == 0)
+ // set decelerating properties
+ // in this example, we used decelerate animation in "https://medium.com/@esskeetit/scrolling-mechanics-of-uiscrollview-142adee1142c"
+ // But, if this method is problematic or violate some patent of other company, change this other way.
+ // We didn't checked anything.
+ // Only thing we need to remember when we change this animation is to add "EasingAnimationFinishedCallback" for the new animation.
+ private void Decelerating(float lastVelocity)
{
- finishAnimationDuration = 0.0f;
+ absoluteVelocity = Math.Abs(lastVelocity);
+ finishAnimationDelta = (absoluteVelocity * decelerationRate) / (1 - decelerationRate);
+ float destination = (lastVelocity > 0) ? controlView.Position.X + finishAnimationDelta : controlView.Position.X - finishAnimationDelta;
+
+ if (destination < leftDirectionLimit || destination > rightDirectionLimit)
+ {
+ finishAnimationDelta = lastVelocity > 0 ? (rightDirectionLimit - controlView.Position.X) : (controlView.Position.X - leftDirectionLimit);
+ destination = lastVelocity > 0 ? rightDirectionLimit : leftDirectionLimit;
+ if (finishAnimationDelta == 0)
+ {
+ finishAnimationDuration = 0.0f;
+ }
+ else
+ {
+ finishAnimationDuration = (float)Math.Log((finishAnimationDelta * logDeceleration / absoluteVelocity + 1), decelerationRate);
+ }
+ }
+ else
+ {
+ if (finishAnimationDelta == 0)
+ {
+ finishAnimationDuration = 0.0f;
+ }
+ else
+ {
+ finishAnimationDuration = (float)Math.Log(-easingThreshold * logDeceleration / absoluteVelocity) / logDeceleration;
+ }
+ }
+
+ finishAnimation.Clear();
+ customScrollAlphaFunction = new UserAlphaFunctionDelegate(CustomScrollAlphaFunction);
+ finishAnimation.DefaultAlphaFunction = new AlphaFunction(customScrollAlphaFunction);
+ GC.KeepAlive(customScrollAlphaFunction);
+ finishAnimation.Duration = (int)finishAnimationDuration;
+ finishAnimation.AnimateTo(controlView, "PositionX", destination);
+ finishAnimation.Play();
}
- else
+
+ private float CustomScrollAlphaFunction(float progress)
{
- finishAnimationDuration = (float)Math.Log((finishAnimationDelta * logDeceleration / absoluteVelocity + 1), decelerationRate);
+ if (finishAnimationDelta == 0)
+ {
+ return 1.0f;
+ }
+ else
+ {
+ float realDuration = progress * finishAnimationDuration;
+ float realDistance = absoluteVelocity * ((float)Math.Pow(decelerationRate, realDuration) - 1) / logDeceleration;
+ float result = Math.Min(realDistance / Math.Abs(finishAnimationDelta), 1.0f);
+
+ return result;
+ }
}
- }
- else
- {
- if (finishAnimationDelta == 0)
+
+ private void EasingAnimationFinishedCallback(object sender, EventArgs e)
{
- finishAnimationDuration = 0.0f;
+ if (animationState != TOUCH_ANIMATION_STATE.ON_FINISH_ANIMATION)
+ {
+ return;
+ }
+
+ // start Animation Off Timer
+ finishAnimation.Clear();
+ SetVisibleLimit();
+ animationOffTimer.Start();
}
- else
+
+ // Check each icons in screen is not moving.
+ // If it is, finish all animation and make animationstate End_animation(NO_ANIMATION)
+ private bool OffAnimatable(object target, Timer.TickEventArgs args)
{
- finishAnimationDuration = (float)Math.Log(-easingThreshold * logDeceleration / absoluteVelocity) / logDeceleration;
+ if (frameUpdateCallback.IsResetTouchedViewPossible())
+ {
+ window.RenderingBehavior = RenderingBehaviorType.IfRequired;
+ window.RemoveFrameUpdateCallback(frameUpdateCallback);
+ animationOffTimer.Stop();
+ animationState = TOUCH_ANIMATION_STATE.END_ANIMATION;
+ return false;
+ }
+ SetVisibleLimit();
+ return true;
}
- }
-
- finishAnimation.Clear();
- customScrollAlphaFunction = new UserAlphaFunctionDelegate(CustomScrollAlphaFunction);
- finishAnimation.DefaultAlphaFunction = new AlphaFunction(customScrollAlphaFunction);
- GC.KeepAlive(customScrollAlphaFunction);
- finishAnimation.Duration = (int)finishAnimationDuration;
- finishAnimation.AnimateTo(controlView, "PositionX", destination);
- finishAnimation.Play();
- }
-
- private float CustomScrollAlphaFunction(float progress)
- {
- if (finishAnimationDelta == 0)
- {
- return 1.0f;
- }
- else
- {
- float realDuration = progress * finishAnimationDuration;
- float realDistance = absoluteVelocity * ((float)Math.Pow(decelerationRate, realDuration) - 1) / logDeceleration;
- float result = Math.Min(realDistance / Math.Abs(finishAnimationDelta), 1.0f);
-
- return result;
- }
- }
-
- private void EasingAnimationFinishedCallback(object sender, EventArgs e)
- {
- if (animationState != TOUCH_ANIMATION_STATE.ON_FINISH_ANIMATION)
- {
- return;
- }
-
- // start Animation Off Timer
- finishAnimation.Clear();
- SetVisibleLimit();
- animationOffTimer.Start();
- }
-
- // Check each icons in screen is not moving.
- // If it is, finish all animation and make animationstate End_animation(NO_ANIMATION)
- private bool OffAnimatable(object target, Timer.TickEventArgs args)
- {
- if (frameUpdateCallback.IsResetTouchedViewPossible())
- {
- window.RenderingBehavior = RenderingBehaviorType.IfRequired;
- window.RemoveFrameUpdateCallback(frameUpdateCallback);
- animationOffTimer.Stop();
- animationState = TOUCH_ANIMATION_STATE.END_ANIMATION;
- return false;
- }
- SetVisibleLimit();
- return true;
}
- }
}
\ No newline at end of file