This is part 3 in the series of custom view tutorials. There was need of rating star in one of my app that fills from left to right based on percentage something like below.
Screenshot_2014-10-11-22-05-53

You got an idea…! I tried much more ways to achieve this but none of them worked for me. At last these steps I followed.
1) Draw star(inner) with Blue color (with paint FILL).
2) Draw a rect above this Star which hides inner star completely.
3) Based on percentage left side of the rect is modified from its original position.
4) Again an outer star with Gray color (with paint STROKE) is drawn.

Stars are drawn based on this blog post author made use of circles to draw stars.

Inner & Outer stars
Drawing is nothing moving Path based on calculations in a canvas (with specified bitmap to draw into). Here is the code. Inner star is drawn with FILL paint and Outer star is drawn with STROKE paint refer source code for more.

private void drawInnerFillStarInTempCanvas() {
bitmap = Bitmap.createBitmap(getWidth(),getHeight(),Bitmap.Config.ARGB_8888);
		tempCanvas = new Canvas(bitmap);
		
		int measuredWidth = getWidth();
		int measuredHeight = getHeight();

		int x = (measuredWidth / 2);
		int y = (measuredHeight / 2);
		int outerRadius = measuredWidth / 4;
		int innerRadius = outerRadius / 3;
		
		int points = 5, fillPercent = 1;

		if (points < 3)
			return;

		float a = (float) (Math.PI * 2) / (points * 2);
		int workingRadius = outerRadius;
		polyPath.reset();

		tempCanvas.translate(x, y);
		for (int j = 0; j < ((fillPercent < 1) ? 2 : 1); j++) {
			polyPath.moveTo(workingRadius, 0);
			for (int i = 1; i < points * 2; i++) {
				workingRadius = (workingRadius == outerRadius) ? innerRadius : outerRadius;
				float xPt = (float) (workingRadius * Math.cos(a * i));
				float yPt = (float) (workingRadius * Math.sin(a * i));
				polyPath.lineTo(xPt, yPt);
			}
			polyPath.close();
			outerRadius -= outerRadius * fillPercent;
			innerRadius = outerRadius / 2;
			a = -a;
		}

		float startAngle = 126;

		tempCanvas.rotate(startAngle);
		tempCanvas.drawPath(polyPath, innerStarPaint);	
}

Drawing Rect to hide inner star
This rect will hide the star which we drawn, by changing the left side of this rect we can show portion of star.

 private void formHidingRectAroundStar(int screenWidth, int screenHeight, int outerRadius) {		
		rectLeft = screenWidth - (screenWidth / 2 + outerRadius - 25);
		rectRight = (screenWidth / 2 + outerRadius) - 25;
		rectTop = screenHeight - (screenHeight / 2 + outerRadius);
		rectBottom = screenHeight / 2 + outerRadius;
		
		rectWidthIs = rectRight - rectLeft;
		
		rect.set(rectLeft, rectTop, rectRight, rectBottom);
	}

screenWidth, screenHeight, outerRadius, rectWidthIs are required attributes. Rect drawn when the view is instantiated as below.

@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		
		//	where as getWidth() / 4 is also outer radius of Outer circle of Star
		formHidingRectAroundStar(getWidth(),getHeight(),getWidth() / 4);
	}

From Activity this method is called periodically, which sets 4 sides of the rect.

//	from activity
	public void setRectLeftSideValue() {		
		int factor = rectWidthIs / 50; 
		rectLeft += factor;
		rect.set(rectLeft, rectTop, rectRight, rectBottom);
	}

OnDraw method

@Override
	protected void onDraw(Canvas canvas) {
		
		//	drawing innerStar using Canvas
		drawInnerFillStarInTempCanvas();
		canvas.drawBitmap(bitmap, 0,0, innerStarPaint);
		
                //      drawing hiding rect
		canvas.drawRect(rect, rectPaint);

		//	drawing outerStar using Canvas
		drawOuterStrokeStarInTempCanvas();
		canvas.drawBitmap(bitmap, 0,0, outerStarPaint);
	}

Runnable which is called from Activity

Runnable runnable = new Runnable() {
		
		@Override
		public void run() {
			if(value <= 50){
				
				if(value < 10){
					((TextView)findViewById(R.id.RatingTxtView)).setText("0."+value);
				}
				else{
					((TextView)findViewById(R.id.RatingTxtView)).setText(String.valueOf(value / 10)+"."+String.valueOf(value % 10));
				}
				
				ratingStar.setRectLeftSideValue();
				value++;
				ratingStar.invalidate();
				myHandler.postDelayed(this, 3);
			}
		}
	};

You can make use of my work if needed, after some time I may tweak it more to look & work better.
Source code is available at github.

Enjoy Happy coding!!!

Advertisements

One thought on “Custom View – Rating Star fills from left to right based on percentage – part 3(5 parts)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s