internal void HandleTouch(TouchEff sender, TouchStatus status) { if (sender.IsDisabled) { return; } var canExecuteAction = sender.CanExecute; if (status != TouchStatus.Started || canExecuteAction) { if (!canExecuteAction) { status = TouchStatus.Canceled; } var state = status == TouchStatus.Started ? TouchState.Pressed : TouchState.Regular; if (status == TouchStatus.Started) { _animationProgress = 0; _animationState = state; } var isToggled = sender.IsToggled; if (isToggled.HasValue) { if (status != TouchStatus.Started) { _durationMultiplier = (_animationState == TouchState.Pressed && !isToggled.Value) || (_animationState == TouchState.Regular && isToggled.Value) ? 1 - _animationProgress : _animationProgress; UpdateStatusAndState(sender, status, state); if (status == TouchStatus.Canceled) { sender.ForceUpdateState(false); return; } OnTapped(sender); sender.IsToggled = !isToggled; return; } state = isToggled.Value ? TouchState.Regular : TouchState.Pressed; } UpdateStatusAndState(sender, status, state); } if (status == TouchStatus.Completed) { OnTapped(sender); } }
internal void HandleLongPress(TouchEff sender) { if (sender.State == TouchState.Regular) { _longPressTokenSource?.Cancel(); _longPressTokenSource?.Dispose(); _longPressTokenSource = null; return; } if (sender.LongPressCommand == null || sender.UserInteractionState == UserInteractionState.Idle) { return; } _longPressTokenSource = new CancellationTokenSource(); Task.Delay(sender.LongPressDuration, _longPressTokenSource.Token).ContinueWith(t => { if (t.IsCanceled) { return; } sender.HandleUserInteraction(UserInteractionState.Idle); var involeLongPressCommand = new Action(() => sender.LongPressCommand?.Execute(sender.LongPressCommandParameter)); if (Device.IsInvokeRequired) { Device.BeginInvokeOnMainThread(involeLongPressCommand); return; } involeLongPressCommand.Invoke(); }); }
private async Task SetRotationYAsync(TouchEff sender, TouchState touchState, HoverState hoverState, int duration) { var regularRotationY = sender.RegularRotationY; var pressedRotationY = sender.PressedRotationY; var hoveredRotationY = sender.HoveredRotationY; if (Abs(regularRotationY) <= double.Epsilon && Abs(pressedRotationY) <= double.Epsilon && Abs(hoveredRotationY) <= double.Epsilon) { return; } var rotationY = regularRotationY; var easing = sender.RegularAnimationEasing; if (touchState == TouchState.Pressed) { rotationY = pressedRotationY; easing = sender.PressedAnimationEasing; } else if (hoverState == HoverState.Hovering) { rotationY = hoveredRotationY; easing = sender.HoveredAnimationEasing; } await sender.Control.RotateYTo(rotationY, (uint)Abs(duration), easing); }
private async Task SetRotationXAsync(TouchEff sender, TouchState touchState, HoverState hoverState, int duration, Easing easing) { var regularRotationX = sender.RegularRotationX; var pressedRotationX = sender.PressedRotationX; var hoveredRotationX = sender.HoveredRotationX; if (Abs(regularRotationX) <= double.Epsilon && Abs(pressedRotationX) <= double.Epsilon && Abs(hoveredRotationX) <= double.Epsilon) { return; } var rotationX = regularRotationX; if (touchState == TouchState.Pressed) { rotationX = pressedRotationX; } else if (hoverState == HoverState.Hovering) { rotationX = hoveredRotationX; } await sender.Control.RotateXTo(rotationX, (uint)Abs(duration), easing); }
private async Task SetTranslationAsync(TouchEff sender, TouchState state, int duration) { var regularTranslationX = sender.RegularTranslationX; var pressedTranslationX = sender.PressedTranslationX; var regularTranslationY = sender.RegularTranslationY; var pressedTranslationY = sender.PressedTranslationY; if (Abs(regularTranslationX) <= double.Epsilon && Abs(pressedTranslationX) <= double.Epsilon && Abs(regularTranslationY) <= double.Epsilon && Abs(pressedTranslationY) <= double.Epsilon) { return; } var translationX = regularTranslationX; var translationY = regularTranslationY; var easing = sender.RegularAnimationEasing; if (state == TouchState.Pressed) { translationX = pressedTranslationX; translationY = pressedTranslationY; easing = sender.PressedAnimationEasing; } await sender.Control.TranslateTo(translationX, translationY, (uint)Abs(duration), easing); }
private async Task SetOpacityAsync(TouchEff sender, TouchState touchState, HoverState hoverState, int duration) { var regularOpacity = sender.RegularOpacity; var pressedOpacity = sender.PressedOpacity; var hoveredOpacity = sender.HoveredOpacity; if (Abs(regularOpacity - 1) <= double.Epsilon && Abs(pressedOpacity - 1) <= double.Epsilon && Abs(hoveredOpacity - 1) <= double.Epsilon) { return; } var opacity = regularOpacity; var easing = sender.RegularAnimationEasing; if (touchState == TouchState.Pressed) { opacity = pressedOpacity; easing = sender.PressedAnimationEasing; } else if (hoverState == HoverState.Hovering) { opacity = hoveredOpacity; easing = sender.HoveredAnimationEasing; } await sender.Control.FadeTo(opacity, (uint)Abs(duration), easing); }
internal async void ChangeStateAsync(TouchEff sender, bool animated) { var state = sender.State; AbortAnimations(sender); _animationTokenSource = new CancellationTokenSource(); var token = _animationTokenSource.Token; var isToggled = sender.IsToggled; if (!animated) { if (isToggled.HasValue) { state = isToggled.Value ? TouchState.Pressed : TouchState.Regular; } var durationMultiplier = _durationMultiplier; _durationMultiplier = null; await GetAnimationTask(sender, state, durationMultiplier.GetValueOrDefault()); return; } var rippleCount = sender.RippleCount; if (rippleCount == 0 || (state == TouchState.Regular && !isToggled.HasValue)) { await GetAnimationTask(sender, state); return; } do { var rippleState = isToggled.HasValue && isToggled.Value ? TouchState.Regular : TouchState.Pressed; await GetAnimationTask(sender, rippleState); if (token.IsCancellationRequested) { return; } rippleState = isToggled.HasValue && isToggled.Value ? TouchState.Pressed : TouchState.Regular; await GetAnimationTask(sender, rippleState); if (token.IsCancellationRequested) { return; } } while (--rippleCount != 0); }
internal void OnTapped(TouchEff sender) { if (!sender.CanExecute || (sender.LongPressCommand != null && sender.UserInteractionState == UserInteractionState.Idle)) { return; } sender.Command?.Execute(sender.CommandParameter); sender.RaiseCompleted(); }
internal void OnTapped(TouchEff sender) { if (!sender.CanExecute) { return; } sender.Command?.Execute(sender.CommandParameter); sender.RaiseCompleted(); }
private Task GetAnimationTask(TouchEff sender, TouchState touchState, HoverState hoverState, double?durationMultiplier = null) { if (sender.Control == null) { return(Task.CompletedTask); } var token = _animationTokenSource.Token; var duration = sender.RegularAnimationDuration; var easing = sender.RegularAnimationEasing; if (touchState == TouchState.Pressed) { duration = sender.RegularAnimationDuration; easing = sender.PressedAnimationEasing; } else if (hoverState == HoverState.Hovering) { duration = sender.HoveredAnimationDuration; easing = sender.HoveredAnimationEasing; } duration = duration.AdjustDurationMultiplier(durationMultiplier); if (duration <= 0 && Device.RuntimePlatform != Device.iOS && Device.RuntimePlatform != Device.macOS) { duration = 1; } sender.RaiseAnimationStarted(touchState, hoverState, duration); return(Task.WhenAll( _customAnimationTaskGetter?.Invoke(sender, touchState, hoverState, duration, easing, token) ?? Task.FromResult(true), SetBackgroundColorAsync(sender, touchState, hoverState, duration, easing), SetOpacityAsync(sender, touchState, hoverState, duration, easing), SetScaleAsync(sender, touchState, hoverState, duration, easing), SetTranslationAsync(sender, touchState, hoverState, duration, easing), SetRotationAsync(sender, touchState, hoverState, duration, easing), SetRotationXAsync(sender, touchState, hoverState, duration, easing), SetRotationYAsync(sender, touchState, hoverState, duration, easing), Task.Run(async() => { _animationProgress = 0; _animationState = touchState; for (var progress = AnimationProgressDelay; progress < duration; progress += AnimationProgressDelay) { await Task.Delay(AnimationProgressDelay).ConfigureAwait(false); if (token.IsCancellationRequested) { return; } _animationProgress = (double)progress / duration; } _animationProgress = 1; }))); }
private void UpdateStatusAndState(TouchEff sender, TouchStatus status, TouchState state) { if (sender.State != state || status != TouchStatus.Canceled) { sender.State = state; sender.RaiseStateChanged(); } sender.Status = status; sender.RaiseStatusChanged(); }
internal void AbortAnimations(TouchEff sender) { _animationTokenSource?.Cancel(); var control = sender.Control; if (control == null) { return; } ViewExtensions.CancelAnimations(control); AnimationExtensions.AbortAnimation(control, ChangeBackgroundColorAnimationName); }
private async Task SetBackgroundColorAsync(TouchEff sender, TouchState touchState, HoverState hoverState, int duration) { var regularBackgroundColor = sender.RegularBackgroundColor; var pressedBackgroundColor = sender.PressedBackgroundColor; var hoveredBackgroundColor = sender.HoveredBackgroundColor; if (regularBackgroundColor == Color.Default && pressedBackgroundColor == Color.Default && hoveredBackgroundColor == Color.Default) { return; } var control = sender.Control; if (_defaultBackgroundColor == default(Color)) { _defaultBackgroundColor = control.BackgroundColor; } var color = GetBackgroundColor(regularBackgroundColor); var easing = sender.RegularAnimationEasing; if (touchState == TouchState.Pressed) { color = GetBackgroundColor(pressedBackgroundColor); easing = sender.PressedAnimationEasing; } else if (hoverState == HoverState.Hovering) { color = GetBackgroundColor(hoveredBackgroundColor); easing = sender.HoveredAnimationEasing; } if (duration <= 0) { control.BackgroundColor = color; return; } var animationCompletionSource = new TaskCompletionSource <bool>(); new Animation { { 0, 1, new Animation(v => control.BackgroundColor = new Color(v, control.BackgroundColor.G, control.BackgroundColor.B, control.BackgroundColor.A), control.BackgroundColor.R, color.R) }, { 0, 1, new Animation(v => control.BackgroundColor = new Color(control.BackgroundColor.R, v, control.BackgroundColor.B, control.BackgroundColor.A), control.BackgroundColor.G, color.G) }, { 0, 1, new Animation(v => control.BackgroundColor = new Color(control.BackgroundColor.R, control.BackgroundColor.G, v, control.BackgroundColor.A), control.BackgroundColor.B, color.B) }, { 0, 1, new Animation(v => control.BackgroundColor = new Color(control.BackgroundColor.R, control.BackgroundColor.G, control.BackgroundColor.B, v), control.BackgroundColor.A, color.A) }, }.Commit(sender.Control, ChangeBackgroundColorAnimationName, 16, (uint)duration, easing, (d, b) => animationCompletionSource.SetResult(true)); await animationCompletionSource.Task; }
private Task GetAnimationTask(TouchEff sender, TouchState state, double? durationMultiplier = null) { if (sender.Control == null) { return Task.CompletedTask; } var token = _animationTokenSource.Token; var duration = (state == TouchState.Regular ? sender.RegularAnimationDuration : sender.PressedAnimationDuration).AdjustDurationMultiplier(durationMultiplier); if(duration <= 0 && Device.RuntimePlatform == Device.Android) { duration = 1; } sender.RaiseAnimationStarted(state, duration); return Task.WhenAll( _customAnimationTaskGetter?.Invoke(sender, state, duration, token) ?? Task.FromResult(true), SetBackgroundColorAsync(sender, state, duration), SetOpacityAsync(sender, state, duration), SetScaleAsync(sender, state, duration), SetTranslationAsync(sender, state, duration), SetRotationAsync(sender, state, duration), SetRotationXAsync(sender, state, duration), SetRotationYAsync(sender, state, duration), Task.Run(async () => { _animationProgress = 0; _animationState = state; for (var progress = AnimationProgressDelay; progress < duration; progress += AnimationProgressDelay) { await Task.Delay(AnimationProgressDelay).ConfigureAwait(false); if (token.IsCancellationRequested) { return; } _animationProgress = (double)progress / duration; } _animationProgress = 1; })); }
internal void HandleHover(TouchEff sender, HoverStatus status) { if (!sender.Control.IsEnabled) { return; } var hoverState = status == HoverStatus.Entered ? HoverState.Hovering : HoverState.Regular; if(sender.HoverState != hoverState) { sender.HoverState = hoverState; sender.RaiseHoverStateChanged(); } sender.HoverStatus = status; sender.RaiseHoverStatusChanged(); }
private async Task SetRotationXAsync(TouchEff sender, TouchState state, int duration) { var regularRotationX = sender.RegularRotationX; var pressedRotationX = sender.PressedRotationX; if (Abs(regularRotationX) <= double.Epsilon && Abs(pressedRotationX) <= double.Epsilon) { return; } var rotationX = regularRotationX; var easing = sender.RegularAnimationEasing; if (state == TouchState.Pressed) { rotationX = pressedRotationX; easing = sender.PressedAnimationEasing; } await sender.Control.RotateXTo(rotationX, (uint)Abs(duration), easing); }
private async Task SetScaleAsync(TouchEff sender, TouchState state, int duration) { var regularScale = sender.RegularScale; var pressedScale = sender.PressedScale; if (Abs(regularScale - 1) <= double.Epsilon && Abs(pressedScale - 1) <= double.Epsilon) { return; } var scale = regularScale; var easing = sender.RegularAnimationEasing; if (state == TouchState.Pressed) { scale = pressedScale; easing = sender.PressedAnimationEasing; } await sender.Control.ScaleTo(scale, (uint)Abs(duration), easing); }
private async Task SetScaleAsync(TouchEff sender, TouchState touchState, HoverState hoverState, int duration) { var regularScale = sender.RegularScale; var pressedScale = sender.PressedScale; var hoveredScale = sender.HoveredScale; if (Abs(regularScale - 1) <= double.Epsilon && Abs(pressedScale - 1) <= double.Epsilon && Abs(hoveredScale - 1) <= double.Epsilon) { return; } var scale = regularScale; var easing = sender.RegularAnimationEasing; if (touchState == TouchState.Pressed) { scale = pressedScale; easing = sender.PressedAnimationEasing; } else if (hoverState == HoverState.Hovering) { scale = hoveredScale; easing = sender.HoveredAnimationEasing; } var control = sender.Control; var tcs = new TaskCompletionSource <bool>(); control.Animate($"{nameof(SetScaleAsync)}{control.Id}", v => { if (double.IsNaN(v)) { return; } control.Scale = v; }, control.Scale, scale, 16, (uint)Abs(duration), easing, (v, b) => tcs.SetResult(b)); await tcs.Task; }
private async Task SetTranslationAsync(TouchEff sender, TouchState touchState, HoverState hoverState, int duration, Easing easing) { var regularTranslationX = sender.RegularTranslationX; var pressedTranslationX = sender.PressedTranslationX; var hoveredTranslationX = sender.HoveredTranslationX; var regularTranslationY = sender.RegularTranslationY; var pressedTranslationY = sender.PressedTranslationY; var hoveredTranslationY = sender.HoveredTranslationY; if (Abs(regularTranslationX) <= double.Epsilon && Abs(pressedTranslationX) <= double.Epsilon && Abs(hoveredTranslationX) <= double.Epsilon && Abs(regularTranslationY) <= double.Epsilon && Abs(pressedTranslationY) <= double.Epsilon && Abs(hoveredTranslationY) <= double.Epsilon) { return; } var translationX = regularTranslationX; var translationY = regularTranslationY; if (touchState == TouchState.Pressed) { translationX = pressedTranslationX; translationY = pressedTranslationY; } else if (hoverState == HoverState.Hovering) { translationX = hoveredTranslationX; translationY = hoveredTranslationY; } await sender.Control.TranslateTo(translationX, translationY, (uint)Abs(duration), easing); }
private bool CanExecuteAction(TouchEff sender) => sender.Control.IsEnabled && ((sender.Command?.CanExecute(sender.CommandParameter) ?? false) || sender.IsCompletedSet);