Created
March 21, 2022 17:16
-
-
Save entdark/99c5fe39a8524a7da986b8f218965230 to your computer and use it in GitHub Desktop.
Telegram back-arrow<->cross rotating animation in Xamarin.Android
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//source: https://github.com/DrKLO/Telegram/blob/master/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BackDrawable.java | |
using Android.Graphics; | |
using Android.Graphics.Drawables; | |
using Android.Views.Animations; | |
using DPTOPX_EXTENSION; | |
namespace YOUR_NAMESPACE { | |
public class BackDrawable : Drawable { | |
private const float DefaultAnimationTime = 300.0f; | |
private readonly Paint paint = new Paint(PaintFlags.AntiAlias); | |
private readonly bool alwaysClose; | |
private readonly DecelerateInterpolator interpolator = new DecelerateInterpolator(); | |
private bool reverseAngle; | |
private long lastFrameTime; | |
private float finalRotation; | |
private float currentRotation; | |
private int currentAnimationTime; | |
private Color color = Color.White; | |
public Color Color { | |
get => color; | |
set { color = value; InvalidateSelf(); } | |
} | |
private Color rotatedColor = Color.Gray; | |
public Color RotatedColor { | |
get => rotatedColor; | |
set { rotatedColor = value; InvalidateSelf(); } | |
} | |
private int arrowRotation; | |
public int ArrowRotation { | |
get => arrowRotation; | |
set { arrowRotation = value; InvalidateSelf(); } | |
} | |
public float AnimationTime { get; set; } = DefaultAnimationTime; | |
public bool Rotated { get; set; } = true; | |
public BackDrawable(bool close) { | |
paint.StrokeWidth = 2.0f.DpToPx(); | |
alwaysClose = close; | |
} | |
public void SetRotation(float rotation, bool animated) { | |
lastFrameTime = 0; | |
if (currentRotation == 1) { | |
reverseAngle = true; | |
} else if (currentRotation == 0) { | |
reverseAngle = false; | |
} | |
lastFrameTime = 0; | |
if (animated) { | |
if (currentRotation < rotation) { | |
currentAnimationTime = (int)(currentRotation * AnimationTime); | |
} else { | |
currentAnimationTime = (int)((1.0f - currentRotation) * AnimationTime); | |
} | |
lastFrameTime = Java.Lang.JavaSystem.CurrentTimeMillis(); | |
finalRotation = rotation; | |
} else { | |
finalRotation = currentRotation = rotation; | |
} | |
InvalidateSelf(); | |
} | |
public override void Draw(Canvas canvas) { | |
if (currentRotation != finalRotation) { | |
if (lastFrameTime != 0) { | |
long dt = Java.Lang.JavaSystem.CurrentTimeMillis() - lastFrameTime; | |
currentAnimationTime += (int)dt; | |
if (currentAnimationTime >= AnimationTime) { | |
currentRotation = finalRotation; | |
} else { | |
if (currentRotation < finalRotation) { | |
currentRotation = interpolator.GetInterpolation(currentAnimationTime / AnimationTime) * finalRotation; | |
} else { | |
currentRotation = 1.0f - interpolator.GetInterpolation(currentAnimationTime / AnimationTime); | |
} | |
} | |
} | |
lastFrameTime = Java.Lang.JavaSystem.CurrentTimeMillis(); | |
InvalidateSelf(); | |
} | |
int rD = Rotated ? (int)((rotatedColor.R - color.R) * currentRotation) : 0; | |
int rG = Rotated ? (int)((rotatedColor.G - color.G) * currentRotation) : 0; | |
int rB = Rotated ? (int)((rotatedColor.B - color.B) * currentRotation) : 0; | |
paint.Color = Color.Rgb(color.R + rD, color.G + rG, color.B + rB); | |
canvas.Save(); | |
canvas.Translate(IntrinsicWidth / 2, IntrinsicHeight / 2); | |
if (arrowRotation != 0) { | |
canvas.Rotate(arrowRotation); | |
} | |
float rotation = currentRotation; | |
if (!alwaysClose) { | |
canvas.Rotate(currentRotation * (reverseAngle ? -225 : 135)); | |
} else { | |
canvas.Rotate(135 + currentRotation * (reverseAngle ? -180 : 180)); | |
rotation = 1.0f; | |
} | |
canvas.DrawLine(-7.0f.DpToPx() - 1.0f.DpToPx() * rotation, 0, 8.0f.DpToPx(), 0, paint); | |
float startYDiff = -0.5f.DpToPx(); | |
float endYDiff = 7.0f.DpToPx() + 1.0f.DpToPx() * rotation; | |
float startXDiff = -7.0f.DpToPx() + 7.0f.DpToPx() * rotation; | |
float endXDiff = 0.5f.DpToPx() - 0.5f.DpToPx() * rotation; | |
canvas.DrawLine(startXDiff, -startYDiff, endXDiff, -endYDiff, paint); | |
canvas.DrawLine(startXDiff, startYDiff, endXDiff, endYDiff, paint); | |
canvas.Restore(); | |
} | |
public override void SetAlpha(int alpha) {} | |
public override void SetColorFilter(ColorFilter cf) {} | |
public override int Opacity => (int)Format.Transparent; | |
public override int IntrinsicWidth => 24.0f.DpToPx(); | |
public override int IntrinsicHeight => 24.0f.DpToPx(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var back = new BackDrawable(false) { | |
Color = Color.White, | |
RotatedColor = Color.Red | |
}; | |
Toolbar.NavigationIcon = back; | |
//arrow -> cross | |
back.SetRotation(1.0f, true); | |
//cross -> arrow | |
back.SetRotation(0.0f, true); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment