Created
July 9, 2015 08:42
-
-
Save Cheesebaron/f8f2de331a9b55c39086 to your computer and use it in GitHub Desktop.
CircularProgressDrawable, based on castorflex's Java implementation here: https://gist.github.com/castorflex/4e46a9dc2c3a4245a28e
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
[Register("dk.ostebaronen.droid.CircularProgressDrawable")] | |
public class CircularProgressDrawable | |
: Drawable | |
, IAnimatable | |
{ | |
private static readonly IInterpolator AngleInterpolator = new LinearInterpolator(); | |
private static readonly IInterpolator SweepInterpolator = new DecelerateInterpolator(); | |
private static readonly RectF _bounds = new RectF(); | |
private const int AngleAnimatorDuration = 2000; | |
private const int SweepAnimatorDuration = 600; | |
private const int MinSweepAngle = 30; | |
private readonly Paint _paint; | |
private readonly float _borderWidth; | |
private ObjectAnimator _objectAnimatorSweep; | |
private ObjectAnimator _objectAnimatorAngle; | |
private bool _modeAppearing; | |
private float _currentGlobalAngleOffset; | |
private float _currentGlobalAngle; | |
private float _currentSweepAngle; | |
public float CurrentGlobalAngle | |
{ | |
[Export("getCurrentGlobalAngle")] | |
get { return _currentGlobalAngle; } | |
[Export("setCurrentGlobalAngle")] | |
set | |
{ | |
_currentGlobalAngle = value; | |
InvalidateSelf(); | |
} | |
} | |
public float CurrentSweepAngle | |
{ | |
[Export("getCurrentSweepAngle")] | |
get { return _currentSweepAngle; } | |
[Export("setCurrentSweepAngle")] | |
set | |
{ | |
_currentSweepAngle = value; | |
InvalidateSelf(); | |
} | |
} | |
public CircularProgressDrawable(Color color, float borderWidth) | |
{ | |
_borderWidth = borderWidth; | |
_paint = new Paint(PaintFlags.AntiAlias) { | |
Color = color, | |
StrokeWidth = borderWidth | |
}; | |
_paint.SetStyle(Paint.Style.Stroke); | |
SetupAnimations(); | |
} | |
public override void Draw(Canvas canvas) | |
{ | |
var startAngle = CurrentGlobalAngle - _currentGlobalAngleOffset; | |
var sweepAngle = CurrentSweepAngle; | |
if (!_modeAppearing) | |
{ | |
startAngle = startAngle + sweepAngle; | |
sweepAngle = 360 - sweepAngle - MinSweepAngle; | |
} | |
else | |
sweepAngle += MinSweepAngle; | |
canvas.DrawArc(_bounds, startAngle, sweepAngle, false, _paint); | |
} | |
public override void SetAlpha(int alpha) { _paint.Alpha = alpha; } | |
public override void SetColorFilter(ColorFilter cf) { _paint.SetColorFilter(cf); } | |
public override int Opacity | |
{ | |
get { return (int)Format.Transparent; } | |
} | |
protected override void OnBoundsChange(Rect bounds) | |
{ | |
base.OnBoundsChange(bounds); | |
_bounds.Left = bounds.Left + _borderWidth/2f + .5f; | |
_bounds.Right = bounds.Right - _borderWidth / 2f - .5f; | |
_bounds.Top = bounds.Top + _borderWidth / 2f + .5f; | |
_bounds.Bottom = bounds.Bottom - _borderWidth / 2f - .5f; | |
} | |
public void Start() | |
{ | |
if (IsRunning) | |
return; | |
IsRunning = true; | |
_objectAnimatorAngle.Start(); | |
_objectAnimatorSweep.Start(); | |
InvalidateSelf(); | |
} | |
public void Stop() | |
{ | |
if (!IsRunning) | |
return; | |
IsRunning = false; | |
_objectAnimatorAngle.Cancel(); | |
_objectAnimatorSweep.Cancel(); | |
InvalidateSelf(); | |
} | |
public bool IsRunning { get; private set; } | |
private void ToggleAppearingMode() | |
{ | |
_modeAppearing = !_modeAppearing; | |
if (_modeAppearing) | |
_currentGlobalAngleOffset = (_currentGlobalAngleOffset + MinSweepAngle*2)%360; | |
} | |
private void SetupAnimations() | |
{ | |
_objectAnimatorAngle = ObjectAnimator.OfFloat(this, "CurrentGlobalAngle", 360f); | |
_objectAnimatorAngle.SetInterpolator(AngleInterpolator); | |
_objectAnimatorAngle.SetDuration(AngleAnimatorDuration); | |
_objectAnimatorAngle.RepeatMode = ValueAnimatorRepeatMode.Restart; | |
_objectAnimatorAngle.RepeatCount = ValueAnimator.Infinite; | |
_objectAnimatorSweep = ObjectAnimator.OfFloat(this, "CurrentSweepAngle", | |
360f - MinSweepAngle*2); | |
_objectAnimatorSweep.SetInterpolator(SweepInterpolator); | |
_objectAnimatorSweep.SetDuration(SweepAnimatorDuration); | |
_objectAnimatorSweep.RepeatMode = ValueAnimatorRepeatMode.Restart; | |
_objectAnimatorSweep.RepeatCount = ValueAnimator.Infinite; | |
_objectAnimatorSweep.AnimationRepeat += (sender, args) => { | |
ToggleAppearingMode(); | |
}; | |
} | |
} |
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
[Register("dk.ostebaronen.droid.CircularProgressView")] | |
public class CircularProgressView : View | |
{ | |
private readonly CircularProgressDrawable _drawable; | |
protected CircularProgressView(IntPtr javaReference, JniHandleOwnership transfer) | |
: base(javaReference, transfer) {} | |
public CircularProgressView(Context context) | |
: this(context, null) { } | |
public CircularProgressView(Context context, IAttributeSet attrs) | |
: this(context, attrs, 0) { } | |
public CircularProgressView(Context context, IAttributeSet attrs, int defStyleAttr) | |
: base(context, attrs, defStyleAttr) | |
{ | |
_drawable = new CircularProgressDrawable(Color.Red, 10); | |
_drawable.SetCallback(this); | |
} | |
protected override void OnVisibilityChanged(View changedView, ViewStates visibility) | |
{ | |
base.OnVisibilityChanged(changedView, visibility); | |
if (visibility == ViewStates.Visible) | |
_drawable.Start(); | |
else | |
_drawable.Stop(); | |
} | |
protected override void OnSizeChanged(int w, int h, int oldw, int oldh) | |
{ | |
base.OnSizeChanged(w, h, oldw, oldh); | |
_drawable.SetBounds(0, 0, w, h); | |
} | |
public override void Draw(Canvas canvas) | |
{ | |
base.Draw(canvas); | |
_drawable.Draw(canvas); | |
} | |
protected override bool VerifyDrawable(Drawable who) | |
{ | |
return who == _drawable || base.VerifyDrawable(who); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment