Skip to content

Instantly share code, notes, and snippets.

@homj
Created October 11, 2014 23:33
Show Gist options
  • Select an option

  • Save homj/f7805d744e7bd3be0432 to your computer and use it in GitHub Desktop.

Select an option

Save homj/f7805d744e7bd3be0432 to your computer and use it in GitHub Desktop.

Revisions

  1. homj created this gist Oct 11, 2014.
    282 changes: 282 additions & 0 deletions HamburgerDrawable.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,282 @@
    /*
    * 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;
    }
    }