homj
10/11/2014 - 11:33 PM

I'm getting hungry!

I'm getting hungry!

/*
 * Copyright 2014 Johannes Homeier
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.twoid.drawericondrawabletest;

import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;

public class HamburgerIconDrawable extends Drawable {
	public static final int STATE_DRAWER = 0;
	public static final int STATE_ARROW = 1;
	
	private static final float BURGER_SIZE = 18f;
	private static final float SESAME_SIZE = 0.4f;
	private static final float SALAD_THIKNESS = 0.2f;
	private static final float SAUCE_THIKNESS = 0.2f;
	private static final float BUN_THIKNESS = 2f;
	private static final float PATTY_THIKNESS = 1.6f;
	
	private static final int SESAMECOUNT = 7;
	private static final float COMBINED_SESAME_WIDTH = SESAMECOUNT*SESAME_SIZE;
	private static final float SESAME_SPACING = (BURGER_SIZE-COMBINED_SESAME_WIDTH)/7;
	private static final float SESAME_INIT_LEFT = 15+SESAME_SPACING/2;
	
	
	private static final float LEVEL_BREAKPOINT = 0.5f;
	
	//level of the animation
	private float level;
	
	//Dimensions
	private float scale = 3;
	private int width;
	private int height;
	private int offsetX;
	
	//Drawing-Objects
	private Paint mPattyPaint;
	private Paint mSaucePaint;
	private Paint mSaladPaint;
	private Paint mTopBunPaint;
	private Paint mBottomBunPaint;
	private Paint mSesamePaint;
	private RectF topBunRect;
	private RectF saladRect;
	private RectF sauceRect;
	private RectF pattyRect;
	private RectF bottomBunRect;
	private RectF sesameRect;
	
	private boolean breakpointReached = false;
	
	
	/**
	 * Create a new DrawerIconDrawable with size @param size in pixel
	 * @param size
	 */
	public HamburgerIconDrawable(int size){
		this(size, size);
	}
	
	/**
	 * Create a new DrawerIconDrawable with width @param width and height @param height in pixel
	 */
	public HamburgerIconDrawable(int width, int height){
		this(width, height, 0);
	}
	
	/**
	 * Create a new DrawerIconDrawable with width @param width and height @param height, and X-offset @param offsetX in pixel
	 */
	public HamburgerIconDrawable(int width, int height, int offsetX){
		this.width = width;
		this.height = height;
		this.offsetX = offsetX;
		
		scale = Math.min(width, height)/48;
		
		setBounds(new Rect(0, 0, width, height));
		
		mPattyPaint = new Paint();
		mPattyPaint.setAntiAlias(true);
		mPattyPaint.setColor(0xff896a5f);
		
		mSaucePaint = new Paint();
		mSaucePaint.setAntiAlias(true);
		mSaucePaint.setColor(0xfff65140);

		mSaladPaint = new Paint();
		mSaladPaint.setAntiAlias(true);
		mSaladPaint.setColor(0xff5ab33f);
		
		mTopBunPaint = new Paint();
		mTopBunPaint.setAntiAlias(true);
		mTopBunPaint.setColor(0xfffab965);

		mBottomBunPaint = new Paint();
		mBottomBunPaint.setAntiAlias(true);
		mBottomBunPaint.setColor(0xfff89923);

		mSesamePaint = new Paint();
		mSesamePaint.setAntiAlias(true);
		mSesamePaint.setColor(0xfffdd063);
		
		topBunRect = new RectF();
		pattyRect = new RectF();
		sauceRect = new RectF();
		saladRect = new RectF();
		bottomBunRect = new RectF();
		sesameRect = new RectF();
		
		setLevel(0);
	}
	
	@Override
	public void draw(Canvas canvas) {
		canvas.translate(offsetX, 0);
		drawBottomBun(canvas);
		drawPattyAndStuff(canvas);
		drawTopBun(canvas);
	}
	
	private void drawTopBun(Canvas canvas){
		float scaleFactor = level < LEVEL_BREAKPOINT ? level*2 : (level-0.5f)*2;
		canvas.save();
		offsetTopBun(3*scale*scaleFactor, 0, -3*scale*scaleFactor, 0);
		canvas.rotate(level < LEVEL_BREAKPOINT ? level*450 : 225 + (1-level)*270, 24*scale, 24*scale);
		canvas.drawRect(topBunRect, mTopBunPaint);
		drawSesame(canvas, scaleFactor);
		canvas.restore();
	}
	
	private void drawSesame(Canvas canvas, float scaleFactor) {
		for(int i = 0;i<7;i++){
			offsetSesameRect(i, scaleFactor);
			canvas.drawRect(sesameRect, mSesamePaint);
		}
	}

	private void drawPattyAndStuff(Canvas canvas){
		float scaleFactor = level < LEVEL_BREAKPOINT ? level*2 : (level-0.5f)*2;
		canvas.save();
		offsetPatty(0, 0, -2*scale*scaleFactor, 0);
		canvas.rotate(level < LEVEL_BREAKPOINT ? level*360 : 180 + (1-level)*360, 24*scale, 24*scale);
		canvas.drawRect(pattyRect, mPattyPaint);
		canvas.drawRect(sauceRect, mSaucePaint);
		canvas.drawRect(saladRect, mSaladPaint);
		canvas.restore();
	}
	
	private void drawBottomBun(Canvas canvas){
		float scaleFactor = level < LEVEL_BREAKPOINT ? level*2 : (level-0.5f)*2;
		canvas.save();
		offsetBottomBun(3*scale*scaleFactor, 0, -3*scale*scaleFactor, 0);
		canvas.rotate(level < LEVEL_BREAKPOINT ? level*270 : 135 + (1-level)*450, 24*scale, 24*scale);
		canvas.drawRect(bottomBunRect, mBottomBunPaint);
		canvas.restore();
	}

	private void offsetSesameRect(int i, float scaleFactor){
		float shrunkenSesameSpacing = SESAME_SPACING - 6*scaleFactor*3f/BURGER_SIZE;
		sesameRect.set(
				SESAME_INIT_LEFT*scale + 3*scaleFactor*scale + i*(shrunkenSesameSpacing +SESAME_SIZE)*scale
				,BURGER_SIZE*scale
				, (SESAME_INIT_LEFT+SESAME_SIZE)*scale + 3*scaleFactor*scale + i*(shrunkenSesameSpacing +SESAME_SIZE)*scale
				, (BURGER_SIZE+SESAME_SIZE)*scale);
	}

	private void offsetTopBun(float offsetLeft, float offsetTop, float offsetRight, float offsetBottom){
		topBunRect.set(
				15*scale + offsetLeft
				,18*scale + offsetTop
				, (15+BURGER_SIZE)*scale + offsetRight
				, (18+BUN_THIKNESS)*scale + offsetBottom
				);
	}
	
	private void offsetPatty(float offsetLeft, float offsetTop, float offsetRight, float offsetBottom){
		saladRect.set(
				15*scale + offsetLeft
				,23*scale + offsetTop
				, (15+BURGER_SIZE)*scale + offsetRight
				, (23+SALAD_THIKNESS)*scale + offsetBottom
				);
		
		sauceRect.set(
				15*scale + offsetLeft
				,(23+SALAD_THIKNESS)*scale + offsetTop
				, (15+BURGER_SIZE)*scale + offsetRight
				, (23+SALAD_THIKNESS+SAUCE_THIKNESS)*scale + offsetBottom
				);
		
		pattyRect.set(
				15*scale + offsetLeft
				,(23+SALAD_THIKNESS+SAUCE_THIKNESS)*scale + offsetTop
				, (15+BURGER_SIZE)*scale + offsetRight
				, (23+SALAD_THIKNESS+SAUCE_THIKNESS+PATTY_THIKNESS)*scale + offsetBottom
				);
	}
	
	private void offsetBottomBun(float offsetLeft, float offsetTop, float offsetRight, float offsetBottom){
		bottomBunRect.set(
				15*scale + offsetLeft
				,28*scale + offsetTop
				, (15+BURGER_SIZE)*scale + offsetRight
				, (28+BUN_THIKNESS)*scale + offsetBottom
				);
	}


	@Override
	public void setAlpha(int alpha) {
		mPattyPaint.setAlpha(alpha);
		invalidateSelf();
	}

	@Override
	public void setColorFilter(ColorFilter cf) {
		mPattyPaint.setColorFilter(cf);
		invalidateSelf();
	}

	@Override
	public int getOpacity() {
		return 0;
	}
	
	
	/**
	 * set the state of the Drawable; 
	 * @param level
	 */
	public void setState(int state){
		switch(state){
		case STATE_DRAWER:
			setLevel((float) STATE_DRAWER);
			break;
		case STATE_ARROW:
			setLevel((float) STATE_ARROW);
			break;
		}
	}
	
	/**
	 * set the level of the animation; drawer indicator is fully displayed at 0; arrow is fully displayed at 1
	 * @param level
	 */
	public void setLevel(float level){
		if(level == 1) breakpointReached = true;
		if(level == 0) breakpointReached = false;
		
		this.level = (breakpointReached ? LEVEL_BREAKPOINT : 0) + level/2;
		invalidateSelf();
	}
	
	@Override
	public int getIntrinsicWidth() {
		return width;
	}
	
	@Override
	public int getIntrinsicHeight() {
		return height;
	}
}