To represent the two competing “like” and “dislike” tallies on individual videos, YouTube uses an elegant solution—a partially filled bar that indicates both values:
I wanted to use a similar interface in one of my applications to represent the “given” and “received” counts for an item. To display the values, I created a custom Android control called KarmaMeter
. The bar uses the color theme defined in the corresponding section in the Android design documentation.
The code for the control is given below. It’s implemented as a View
and supports animating the changes 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.