// 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); }
// 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; } } 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. window.AddFrameUpdateCallback(frameUpdateCallback); // 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. }
private bool OnTouch(object source, View.TouchEventArgs e) { 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); }
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); }