Yet Another [à compléter]

MfA Tricks #4 - a Youtube-style Like Bar

To represent the two antagonist “like” and “dislike” values, YouTube uses an elegant solution with a bar that is filled depending on both values:

I used a similar idea in my application where I have the notion of a value “given” and and a value “gotten” for the same item:

The bar uses the color theme defined in the corresponding section in the Android design documentation (that you should really read if you haven’t already).

The code for the bar (called KarmaBar from the above definition) is given below. It’s implemented as a View and it supports animating between different values:

public class KarmaMeter : View
{
	const int DefaultHeight = 10;
	const int DefaultWidth = 120;

	double position = 0.5;
	float lastWidth = -1;
	Paint positivePaint;
	Paint negativePaint;

	public KarmaMeter (Context context, IAttributeSet attrs) :
		base (context, attrs)
	{
		Initialize ();
	}

	public KarmaMeter (Context context, IAttributeSet attrs, int defStyle) :
		base (context, attrs, defStyle)
	{
		Initialize ();
	}

	void Initialize ()
	{
		positivePaint = new Paint {
			AntiAlias = true,
			Color = Color.Rgb (0x99, 0xcc, 0),
		};
		positivePaint.SetStyle (Paint.Style.FillAndStroke);

		negativePaint = new Paint {
			AntiAlias = true,
			Color = Color.Rgb (0xff, 0x44, 0x44)
		};
		negativePaint.SetStyle (Paint.Style.FillAndStroke);
	}

	public void SetKarmaBasedOnValues (int totalGiven, int totalGotten, bool animate = true)
	{
		var value = (((totalGiven - totalGotten) / (float)(totalGiven + totalGotten)) + 1) / 2f;
		SetKarmaValue (value, animate);
	}

	public double KarmaValue {
		get {
			return position;
		}
		set {
			position = Math.Max (0f, Math.Min (value, 1f));
			Invalidate ();
		}
	}

	public void SetKarmaValue (double value, bool animate)
	{
		if (!animate) {
			KarmaValue = value;
			return;
		}

		var animator = ValueAnimator.OfFloat ((float)position, (float)Math.Max (0f, Math.Min (value, 1f)));
		animator.SetDuration (500);
		animator.Update += (sender, e) => KarmaValue = (double)e.Animation.AnimatedValue;
		animator.AnimationEnd += (sender, e) => animator.RemoveAllListeners ();
		animator.Start ();
	}

	protected override void OnMeasure (int widthMeasureSpec, int heightMeasureSpec)
	{
		var width = View.MeasureSpec.GetSize (widthMeasureSpec);
		SetMeasuredDimension (width < DefaultWidth ? DefaultWidth : width,
		                      DefaultHeight);
	}

	protected override void OnDraw (Canvas canvas)
	{
		base.OnDraw (canvas);

		float middle = canvas.Width * (float)position;
		canvas.DrawPaint (negativePaint);
		canvas.DrawRect (0,
		                 0,
		                 middle,
		                 canvas.Height,
		                 positivePaint);
	}
}

To set the value displayed by the bar (between 0.0f and 1.0f), you can either directly use the property KarmaValue/SetKarmaValue or if you maintain a count of your positive/negatives values, you can use the SetKarmaBasedOnValues method.