Example usage for android.graphics Canvas drawBitmap

List of usage examples for android.graphics Canvas drawBitmap

Introduction

In this page you can find the example usage for android.graphics Canvas drawBitmap.

Prototype

public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, @Nullable Paint paint) 

Source Link

Document

Draw the specified bitmap, scaling/translating automatically to fill the destination rectangle.

Usage

From source file:com.aujur.ebookreader.activity.ReadingFragment.java

private Bitmap getBookViewSnapshot() {

    try {/*from w w  w .j a va 2s  .c  o  m*/
        Bitmap bitmap = Bitmap.createBitmap(viewSwitcher.getWidth(), viewSwitcher.getHeight(),
                Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);

        bookView.layout(0, 0, viewSwitcher.getWidth(), viewSwitcher.getHeight());

        bookView.draw(canvas);

        if (config.isShowPageNumbers()) {

            /**
             * FIXME: creating an intermediate bitmap here because I can't
             * figure out how to draw the pageNumberView directly on the
             * canvas and have it show up in the right place.
             */

            Bitmap pageNumberBitmap = Bitmap.createBitmap(pageNumberView.getWidth(), pageNumberView.getHeight(),
                    Config.ARGB_8888);
            Canvas pageNumberCanvas = new Canvas(pageNumberBitmap);

            pageNumberView.layout(0, 0, pageNumberView.getWidth(), pageNumberView.getHeight());
            pageNumberView.draw(pageNumberCanvas);

            canvas.drawBitmap(pageNumberBitmap, 0, viewSwitcher.getHeight() - pageNumberView.getHeight(),
                    new Paint());

            pageNumberBitmap.recycle();

        }

        return bitmap;
    } catch (OutOfMemoryError out) {
        viewSwitcher.setBackgroundColor(config.getBackgroundColor());
    }

    return null;
}

From source file:com.android.leanlauncher.CellLayout.java

@Override
protected void onDraw(Canvas canvas) {
    // When we're large, we are either drawn in a "hover" state (ie when dragging an item to
    // a neighboring page) or with just a normal background (if backgroundAlpha > 0.0f)
    // When we're small, we are either drawn normally or in the "accepts drops" state (during
    // a drag). However, we also drag the mini hover background *over* one of those two
    // backgrounds
    if (mDrawBackground && mBackgroundAlpha > 0.0f) {
        Drawable bg;//ww  w . ja  v a  2  s  . c  o  m

        if (mUseActiveGlowBackground) {
            // In the mini case, we draw the active_glow bg *over* the active background
            bg = mActiveGlowBackground;
        } else {
            bg = mNormalBackground;
        }

        bg.setAlpha((int) (mBackgroundAlpha * mBackgroundAlphaMultiplier * 255));
        bg.setBounds(mBackgroundRect);
        bg.draw(canvas);
    }

    final Paint paint = mDragOutlinePaint;
    for (int i = 0; i < mDragOutlines.length; i++) {
        final float alpha = mDragOutlineAlphas[i];
        if (alpha > 0) {
            final Rect r = mDragOutlines[i];
            mTempRect.set(r);
            Utilities.scaleRectAboutCenter(mTempRect, getChildrenScale());
            final Bitmap b = (Bitmap) mDragOutlineAnims[i].getTag();
            paint.setAlpha((int) (alpha + .5f));
            canvas.drawBitmap(b, null, mTempRect, paint);
        }
    }
}

From source file:com.android.launcher2.Workspace.java

/**
 * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
 * Responsibility for the bitmap is transferred to the caller.
 *//*www . j a  v a  2  s  .  c  o  m*/
private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h, boolean clipAlpha) {
    final int outlineColor = getResources().getColor(android.R.color.holo_blue_light);
    final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    canvas.setBitmap(b);

    Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());
    float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),
            (h - padding) / (float) orig.getHeight());
    int scaledWidth = (int) (scaleFactor * orig.getWidth());
    int scaledHeight = (int) (scaleFactor * orig.getHeight());
    Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);

    // center the image
    dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);

    canvas.drawBitmap(orig, src, dst, null);
    mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor, clipAlpha);
    canvas.setBitmap(null);

    return b;
}

From source file:com.android.launcher2.AsyncTaskCallback.java

private Bitmap getWidgetPreview(ComponentName provider, int previewImage, int iconId, int cellHSpan,
        int cellVSpan, int maxWidth, int maxHeight) {
    // Load the preview image if possible
    String packageName = provider.getPackageName();
    if (maxWidth < 0)
        maxWidth = Integer.MAX_VALUE;
    if (maxHeight < 0)
        maxHeight = Integer.MAX_VALUE;

    Drawable drawable = null;// w w  w .  j  a va  2 s. c  o  m
    if (previewImage != 0) {
        drawable = mPackageManager.getDrawable(packageName, previewImage, null);
        if (drawable == null) {
            Log.w(TAG, "Can't load widget preview drawable 0x" + Integer.toHexString(previewImage)
                    + " for provider: " + provider);
        }
    }

    int bitmapWidth;
    int bitmapHeight;
    Bitmap defaultPreview = null;
    boolean widgetPreviewExists = (drawable != null);
    if (widgetPreviewExists) {
        bitmapWidth = drawable.getIntrinsicWidth();
        bitmapHeight = drawable.getIntrinsicHeight();
    } else {
        // Generate a preview image if we couldn't load one
        if (cellHSpan < 1)
            cellHSpan = 1;
        if (cellVSpan < 1)
            cellVSpan = 1;

        BitmapDrawable previewDrawable = (BitmapDrawable) getResources()
                .getDrawable(R.drawable.widget_preview_tile);
        final int previewDrawableWidth = previewDrawable.getIntrinsicWidth();
        final int previewDrawableHeight = previewDrawable.getIntrinsicHeight();
        bitmapWidth = previewDrawableWidth * cellHSpan; // subtract 2 dips
        bitmapHeight = previewDrawableHeight * cellVSpan;

        defaultPreview = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Config.ARGB_8888);
        final Canvas c = mCachedAppWidgetPreviewCanvas.get();
        c.setBitmap(defaultPreview);
        previewDrawable.setBounds(0, 0, bitmapWidth, bitmapHeight);
        previewDrawable.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
        previewDrawable.draw(c);
        c.setBitmap(null);

        // Draw the icon in the top left corner
        int minOffset = (int) (mAppIconSize * sWidgetPreviewIconPaddingPercentage);
        int smallestSide = Math.min(bitmapWidth, bitmapHeight);
        float iconScale = Math.min((float) smallestSide / (mAppIconSize + 2 * minOffset), 1f);

        try {
            Drawable icon = null;
            int hoffset = (int) ((previewDrawableWidth - mAppIconSize * iconScale) / 2);
            int yoffset = (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2);
            if (iconId > 0)
                icon = mIconCache.getFullResIcon(packageName, iconId);
            if (icon != null) {
                renderDrawableToBitmap(icon, defaultPreview, hoffset, yoffset, (int) (mAppIconSize * iconScale),
                        (int) (mAppIconSize * iconScale));
            }
        } catch (Resources.NotFoundException e) {
        }
    }

    // Scale to fit width only - let the widget preview be clipped in the
    // vertical dimension
    float scale = 1f;
    if (bitmapWidth > maxWidth) {
        scale = maxWidth / (float) bitmapWidth;
    }
    if (scale != 1f) {
        bitmapWidth = (int) (scale * bitmapWidth);
        bitmapHeight = (int) (scale * bitmapHeight);
    }

    Bitmap preview = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Config.ARGB_8888);

    // Draw the scaled preview into the final bitmap
    if (widgetPreviewExists) {
        renderDrawableToBitmap(drawable, preview, 0, 0, bitmapWidth, bitmapHeight);
    } else {
        final Canvas c = mCachedAppWidgetPreviewCanvas.get();
        final Rect src = mCachedAppWidgetPreviewSrcRect.get();
        final Rect dest = mCachedAppWidgetPreviewDestRect.get();
        c.setBitmap(preview);
        src.set(0, 0, defaultPreview.getWidth(), defaultPreview.getHeight());
        dest.set(0, 0, preview.getWidth(), preview.getHeight());

        Paint p = mCachedAppWidgetPreviewPaint.get();
        if (p == null) {
            p = new Paint();
            p.setFilterBitmap(true);
            mCachedAppWidgetPreviewPaint.set(p);
        }
        c.drawBitmap(defaultPreview, src, dest, p);
        c.setBitmap(null);
    }
    return preview;
}

From source file:cc.flydev.launcher.Workspace.java

/**
 * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
 * Responsibility for the bitmap is transferred to the caller.
 */// ww w.j  ava  2  s  .c om
private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h, boolean clipAlpha) {
    final int outlineColor = getResources().getColor(R.color.outline_color);
    final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    canvas.setBitmap(b);

    Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());
    float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),
            (h - padding) / (float) orig.getHeight());
    int scaledWidth = (int) (scaleFactor * orig.getWidth());
    int scaledHeight = (int) (scaleFactor * orig.getHeight());
    Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);

    // center the image
    dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);

    canvas.drawBitmap(orig, src, dst, null);
    mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor, clipAlpha);
    canvas.setBitmap(null);

    return b;
}

From source file:xiaofan.llongimageview.view.SubsamplingScaleImageView.java

/**
 * Draw method should not be called until the view has dimensions so the first calls are used as triggers to calculate
 * the scaling and tiling required. Once the view is setup, tiles are displayed as they are loaded.
 *///from w  ww.  j  av a  2  s  .  co  m
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    createPaints();

    // If image or view dimensions are not known yet, abort.
    if (sWidth == 0 || sHeight == 0 || decoder == null || getWidth() == 0 || getHeight() == 0) {
        return;
    }

    // On first render with no tile map ready, initialise it and kick off async base image loading.
    if (tileMap == null) {
        initialiseBaseLayer(getMaxBitmapDimensions(canvas));
        return;
    }

    // If waiting to translate to new center position, set translate now
    if (sPendingCenter != null && pendingScale != null) {
        scale = pendingScale;
        vTranslate.x = (getWidth() / 2) - (scale * sPendingCenter.x);
        vTranslate.y = (getHeight() / 2) - (scale * sPendingCenter.y);
        sPendingCenter = null;
        pendingScale = null;
        fitToBounds(true);
        refreshRequiredTiles(true);
    }

    // On first display of base image set up position, and in other cases make sure scale is correct.
    fitToBounds(false);

    // Everything is set up and coordinates are valid. Inform subclasses.
    if (!readySent) {
        readySent = true;
        new Thread(new Runnable() {
            public void run() {
                onImageReady();
            }
        }).start();
    }

    // If animating scale, calculate current scale and center with easing equations
    if (anim != null) {
        long scaleElapsed = System.currentTimeMillis() - anim.time;
        boolean finished = scaleElapsed > anim.duration;
        scaleElapsed = Math.min(scaleElapsed, anim.duration);
        scale = ease(anim.easing, scaleElapsed, anim.scaleStart, anim.scaleEnd - anim.scaleStart,
                anim.duration);

        // Apply required animation to the focal point
        float vFocusNowX = ease(anim.easing, scaleElapsed, anim.vFocusStart.x,
                anim.vFocusEnd.x - anim.vFocusStart.x, anim.duration);
        float vFocusNowY = ease(anim.easing, scaleElapsed, anim.vFocusStart.y,
                anim.vFocusEnd.y - anim.vFocusStart.y, anim.duration);
        // Find out where the focal point is at this scale and adjust its position to follow the animation path
        PointF vFocus = sourceToViewCoord(anim.sCenterEnd);
        vTranslate.x -= vFocus.x - vFocusNowX;
        vTranslate.y -= vFocus.y - vFocusNowY;

        // For translate anims, showing the image non-centered is never allowed, for scaling anims it is during the animation.
        fitToBounds(finished || (anim.scaleStart == anim.scaleEnd));
        refreshRequiredTiles(finished);
        if (finished) {
            anim = null;
        }
        invalidate();
    }

    // Optimum sample size for current scale
    int sampleSize = Math.min(fullImageSampleSize, calculateInSampleSize());

    // First check for missing tiles - if there are any we need the base layer underneath to avoid gaps
    boolean hasMissingTiles = false;
    for (Map.Entry<Integer, List<Tile>> tileMapEntry : tileMap.entrySet()) {
        if (tileMapEntry.getKey() == sampleSize) {
            for (Tile tile : tileMapEntry.getValue()) {
                if (tile.visible && (tile.loading || tile.bitmap == null)) {
                    hasMissingTiles = true;
                }
            }
        }
    }

    // Render all loaded tiles. LinkedHashMap used for bottom up rendering - lower res tiles underneath.
    for (Map.Entry<Integer, List<Tile>> tileMapEntry : tileMap.entrySet()) {
        if (tileMapEntry.getKey() == sampleSize || hasMissingTiles) {
            for (Tile tile : tileMapEntry.getValue()) {
                Rect vRect = convertRect(sourceToViewRect(tile.sRect));
                if (!tile.loading && tile.bitmap != null) {
                    canvas.drawBitmap(tile.bitmap, null, vRect, bitmapPaint);
                    if (debug) {
                        canvas.drawRect(vRect, debugPaint);
                    }
                } else if (tile.loading && debug) {
                    canvas.drawText("LOADING", vRect.left + 5, vRect.top + 35, debugPaint);
                }
                if (tile.visible && debug) {
                    canvas.drawText(
                            "ISS " + tile.sampleSize + " RECT " + tile.sRect.top + "," + tile.sRect.left + ","
                                    + tile.sRect.bottom + "," + tile.sRect.right,
                            vRect.left + 5, vRect.top + 15, debugPaint);
                }
            }
        }
    }

    if (debug) {
        canvas.drawText("Scale: " + String.format("%.2f", scale), 5, 15, debugPaint);
        canvas.drawText(
                "Translate: " + String.format("%.2f", vTranslate.x) + ":" + String.format("%.2f", vTranslate.y),
                5, 35, debugPaint);
        PointF center = getCenter();
        canvas.drawText(
                "Source center: " + String.format("%.2f", center.x) + ":" + String.format("%.2f", center.y), 5,
                55, debugPaint);

        if (anim != null) {
            PointF vCenterStart = sourceToViewCoord(anim.sCenterStart);
            PointF vCenterEndRequested = sourceToViewCoord(anim.sCenterEndRequested);
            PointF vCenterEnd = sourceToViewCoord(anim.sCenterEnd);
            canvas.drawCircle(vCenterStart.x, vCenterStart.y, 10, debugPaint);
            canvas.drawCircle(vCenterEndRequested.x, vCenterEndRequested.y, 20, debugPaint);
            canvas.drawCircle(vCenterEnd.x, vCenterEnd.y, 25, debugPaint);
            canvas.drawCircle(getWidth() / 2, getHeight() / 2, 30, debugPaint);
        }
    }
}

From source file:com.bizcom.vc.widget.cus.SubsamplingScaleImageView.java

/**
 * Draw method should not be called until the view has dimensions so the
 * first calls are used as triggers to calculate the scaling and tiling
 * required. Once the view is setup, tiles are displayed as they are loaded.
 *///from ww  w . jav a  2s.  c om
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    createPaints();

    // If image or view dimensions are not known yet, abort.
    if (sWidth == 0 || sHeight == 0 || decoder == null || getWidth() == 0 || getHeight() == 0) {
        return;
    }

    // On first render with no tile map ready, initialise it and kick off
    // async base image loading.
    if (tileMap == null) {
        initialiseBaseLayer(getMaxBitmapDimensions(canvas));
        return;
    }

    // If waiting to translate to new center position, set translate now
    if (sPendingCenter != null && pendingScale != null) {
        scale = pendingScale;
        vTranslate.x = (getWidth() / 2) - (scale * sPendingCenter.x);
        vTranslate.y = (getHeight() / 2) - (scale * sPendingCenter.y);
        sPendingCenter = null;
        pendingScale = null;
        fitToBounds(true);
        refreshRequiredTiles(true);
    }

    // On first display of base image set up position, and in other cases
    // make sure scale is correct.
    fitToBounds(false);

    // Everything is set up and coordinates are valid. Inform subclasses.
    if (!readySent) {
        readySent = true;
        new Thread(new Runnable() {
            public void run() {
                onImageReady();
            }
        }).start();
    }

    // If animating scale, calculate current scale and center with easing
    // equations
    if (anim != null) {
        long scaleElapsed = System.currentTimeMillis() - anim.time;
        boolean finished = scaleElapsed > anim.duration;
        scaleElapsed = Math.min(scaleElapsed, anim.duration);
        scale = ease(anim.easing, scaleElapsed, anim.scaleStart, anim.scaleEnd - anim.scaleStart,
                anim.duration);

        // Apply required animation to the focal point
        float vFocusNowX = ease(anim.easing, scaleElapsed, anim.vFocusStart.x,
                anim.vFocusEnd.x - anim.vFocusStart.x, anim.duration);
        float vFocusNowY = ease(anim.easing, scaleElapsed, anim.vFocusStart.y,
                anim.vFocusEnd.y - anim.vFocusStart.y, anim.duration);
        // Find out where the focal point is at this scale and adjust its
        // position to follow the animation path
        PointF vFocus = sourceToViewCoord(anim.sCenterEnd);
        vTranslate.x -= vFocus.x - vFocusNowX;
        vTranslate.y -= vFocus.y - vFocusNowY;

        // For translate anims, showing the image non-centered is never
        // allowed, for scaling anims it is during the animation.
        fitToBounds(finished || (anim.scaleStart == anim.scaleEnd));
        refreshRequiredTiles(finished);
        if (finished) {
            anim = null;
        }
        invalidate();
    }

    // Optimum sample size for current scale
    int sampleSize = Math.min(fullImageSampleSize, calculateInSampleSize());

    // First check for missing tiles - if there are any we need the base
    // layer underneath to avoid gaps
    boolean hasMissingTiles = false;
    for (Map.Entry<Integer, List<Tile>> tileMapEntry : tileMap.entrySet()) {
        if (tileMapEntry.getKey() == sampleSize) {
            for (Tile tile : tileMapEntry.getValue()) {
                if (tile.visible && (tile.loading || tile.bitmap == null)) {
                    hasMissingTiles = true;
                }
            }
        }
    }

    // Render all loaded tiles. LinkedHashMap used for bottom up rendering -
    // lower res tiles underneath.
    for (Map.Entry<Integer, List<Tile>> tileMapEntry : tileMap.entrySet()) {
        if (tileMapEntry.getKey() == sampleSize || hasMissingTiles) {
            for (Tile tile : tileMapEntry.getValue()) {
                Rect vRect = convertRect(sourceToViewRect(tile.sRect));
                if (!tile.loading && tile.bitmap != null) {
                    canvas.drawBitmap(tile.bitmap, null, vRect, bitmapPaint);
                    if (debug) {
                        canvas.drawRect(vRect, debugPaint);
                    }
                } else if (tile.loading && debug) {
                    canvas.drawText("LOADING", vRect.left + 5, vRect.top + 35, debugPaint);
                }
                if (tile.visible && debug) {
                    canvas.drawText(
                            "ISS " + tile.sampleSize + " RECT " + tile.sRect.top + "," + tile.sRect.left + ","
                                    + tile.sRect.bottom + "," + tile.sRect.right,
                            vRect.left + 5, vRect.top + 15, debugPaint);
                }
            }
        }
    }

    if (debug) {
        canvas.drawText("Scale: " + String.format("%.2f", scale), 5, 15, debugPaint);
        canvas.drawText(
                "Translate: " + String.format("%.2f", vTranslate.x) + ":" + String.format("%.2f", vTranslate.y),
                5, 35, debugPaint);
        PointF center = getCenter();
        canvas.drawText(
                "Source center: " + String.format("%.2f", center.x) + ":" + String.format("%.2f", center.y), 5,
                55, debugPaint);

        if (anim != null) {
            PointF vCenterStart = sourceToViewCoord(anim.sCenterStart);
            PointF vCenterEndRequested = sourceToViewCoord(anim.sCenterEndRequested);
            PointF vCenterEnd = sourceToViewCoord(anim.sCenterEnd);
            canvas.drawCircle(vCenterStart.x, vCenterStart.y, 10, debugPaint);
            canvas.drawCircle(vCenterEndRequested.x, vCenterEndRequested.y, 20, debugPaint);
            canvas.drawCircle(vCenterEnd.x, vCenterEnd.y, 25, debugPaint);
            canvas.drawCircle(getWidth() / 2, getHeight() / 2, 30, debugPaint);
        }
    }
}

From source file:cn.oddcloud.www.navigationtabbar.ntb.NavigationTabBar.java

@SuppressWarnings("ConstantConditions")
@Override/*from   w  w w . j  a v  a2 s  . c o  m*/
protected void onDraw(final Canvas canvas) {
    // Get height of NTB with badge on nor
    final int mBadgedHeight = (int) (mBounds.height() + mBadgeMargin);

    // Set main canvas
    if (mBitmap == null || mBitmap.isRecycled()) {
        mBitmap = Bitmap.createBitmap((int) mBounds.width(), mBadgedHeight, Bitmap.Config.ARGB_8888);
        mCanvas.setBitmap(mBitmap);
    }
    // Set pointer canvas
    if (mPointerBitmap == null || mPointerBitmap.isRecycled()) {
        mPointerBitmap = Bitmap.createBitmap((int) mBounds.width(), mBadgedHeight, Bitmap.Config.ARGB_8888);
        mPointerCanvas.setBitmap(mPointerBitmap);
    }
    // Set icons canvas
    if (mIconsBitmap == null || mIconsBitmap.isRecycled()) {
        mIconsBitmap = Bitmap.createBitmap((int) mBounds.width(), mBadgedHeight, Bitmap.Config.ARGB_8888);
        mIconsCanvas.setBitmap(mIconsBitmap);
    }
    // Set titles canvas
    if (mIsTitled) {
        if (mTitlesBitmap == null || mTitlesBitmap.isRecycled()) {
            mTitlesBitmap = Bitmap.createBitmap((int) mBounds.width(), mBadgedHeight, Bitmap.Config.ARGB_8888);
            mTitlesCanvas.setBitmap(mTitlesBitmap);
        }
    } else
        mTitlesBitmap = null;

    // Reset and clear canvases
    mCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
    mPointerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
    mIconsCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
    if (mIsTitled)
        mTitlesCanvas.drawColor(0, PorterDuff.Mode.CLEAR);

    if (mCornersRadius == 0)
        canvas.drawRect(mBgBounds, mBgPaint);
    else
        canvas.drawRoundRect(mBgBounds, mCornersRadius, mCornersRadius, mBgPaint);

    // Get pointer badge margin for gravity
    final float barBadgeMargin = mBadgeGravity == BadgeGravity.TOP ? mBadgeMargin : 0.0F;

    // Draw our model colors
    for (int i = 0; i < mModels.size(); i++) {
        mPaint.setColor(mModels.get(i).getColor());

        if (mIsHorizontalOrientation) {
            final float left = mModelSize * i;
            final float right = left + mModelSize;
            mCanvas.drawRect(left, barBadgeMargin, right, mBounds.height() + barBadgeMargin, mPaint);
        } else {
            final float top = mModelSize * i;
            final float bottom = top + mModelSize;
            mCanvas.drawRect(0.0F, top, mBounds.width(), bottom, mPaint);
        }
    }

    // Set bound of pointer
    if (mIsHorizontalOrientation)
        mPointerBounds.set(mPointerLeftTop, barBadgeMargin, mPointerRightBottom,
                mBounds.height() + barBadgeMargin);
    else
        mPointerBounds.set(0.0F, mPointerLeftTop, mBounds.width(), mPointerRightBottom);

    // Draw pointer for model colors
    if (mCornersRadius == 0)
        mPointerCanvas.drawRect(mPointerBounds, mPaint);
    else
        mPointerCanvas.drawRoundRect(mPointerBounds, mCornersRadius, mCornersRadius, mPaint);

    // Draw pointer into main canvas
    mCanvas.drawBitmap(mPointerBitmap, 0.0F, 0.0F, mPointerPaint);

    // Set vars for icon when model with title or without
    final float iconMarginTitleHeight = mIconSize + mTitleMargin + mModelTitleSize;

    // Draw model icons
    for (int i = 0; i < mModels.size(); i++) {
        final Model model = mModels.get(i);

        // Variables to center our icons
        final float leftOffset;
        final float topOffset;
        final float matrixCenterX;
        final float matrixCenterY;

        // Set offset to titles
        final float leftTitleOffset = (mModelSize * i) + (mModelSize * 0.5F);
        final float topTitleOffset = mBounds.height() - (mBounds.height() - iconMarginTitleHeight) * 0.5F;

        if (mIsHorizontalOrientation) {
            leftOffset = (mModelSize * i) + (mModelSize - model.mIcon.getWidth()) * 0.5F;
            topOffset = (mBounds.height() - model.mIcon.getHeight()) * 0.5F;
        } else {
            leftOffset = (mBounds.width() - (float) model.mIcon.getWidth()) * 0.5F;
            topOffset = (mModelSize * i) + (mModelSize - (float) model.mIcon.getHeight()) * 0.5F;
        }

        matrixCenterX = leftOffset + (float) model.mIcon.getWidth() * 0.5F;
        matrixCenterY = topOffset + (float) model.mIcon.getHeight() * 0.5F;

        // Title translate position
        final float titleTranslate = topOffset - model.mIcon.getHeight() * TITLE_MARGIN_SCALE_FRACTION;

        // Translate icon to model center
        model.mIconMatrix.setTranslate(leftOffset,
                (mIsTitled && mTitleMode == TitleMode.ALL) ? titleTranslate : topOffset);

        // Get interpolated fraction for left last and current models
        final float interpolation = mResizeInterpolator.getResizeInterpolation(mFraction, true);
        final float lastInterpolation = mResizeInterpolator.getResizeInterpolation(mFraction, false);

        // Scale value relative to interpolation
        final float matrixScale = model.mActiveIconScaleBy * (mIsScaled ? interpolation : NON_SCALED_FRACTION);
        final float matrixLastScale = model.mActiveIconScaleBy
                * (mIsScaled ? lastInterpolation : (MAX_FRACTION - NON_SCALED_FRACTION));

        // Get title alpha relative to interpolation
        final int titleAlpha = (int) (MAX_ALPHA * interpolation);
        final int titleLastAlpha = MAX_ALPHA - (int) (MAX_ALPHA * lastInterpolation);
        // Get title scale relative to interpolation
        final float titleScale = MAX_FRACTION
                + ((mIsScaled ? interpolation : NON_SCALED_FRACTION) * TITLE_ACTIVE_SCALE_BY);
        final float titleLastScale = mIsScaled
                ? (MAX_FRACTION + TITLE_ACTIVE_SCALE_BY) - (lastInterpolation * TITLE_ACTIVE_SCALE_BY)
                : titleScale;

        mIconPaint.setAlpha(MAX_ALPHA);
        if (model.mSelectedIcon != null)
            mSelectedIconPaint.setAlpha(MAX_ALPHA);

        // Check if we handle models from touch on NTB or from ViewPager
        // There is a strange logic
        // of ViewPager onPageScrolled method, so it is
        if (mIsSetIndexFromTabBar) {
            if (mIndex == i)
                updateCurrentModel(model, leftOffset, topOffset, titleTranslate, interpolation, matrixCenterX,
                        matrixCenterY, matrixScale, titleScale, titleAlpha);
            else if (mLastIndex == i)
                updateLastModel(model, leftOffset, topOffset, titleTranslate, lastInterpolation, matrixCenterX,
                        matrixCenterY, matrixLastScale, titleLastScale, titleLastAlpha);
            else
                updateInactiveModel(model, leftOffset, topOffset, titleScale, matrixScale, matrixCenterX,
                        matrixCenterY);
        } else {
            if (i == mIndex + 1)
                updateCurrentModel(model, leftOffset, topOffset, titleTranslate, interpolation, matrixCenterX,
                        matrixCenterY, matrixScale, titleScale, titleAlpha);
            else if (i == mIndex)
                updateLastModel(model, leftOffset, topOffset, titleTranslate, lastInterpolation, matrixCenterX,
                        matrixCenterY, matrixLastScale, titleLastScale, titleLastAlpha);
            else
                updateInactiveModel(model, leftOffset, topOffset, titleScale, matrixScale, matrixCenterX,
                        matrixCenterY);
        }

        // Draw original model icon
        if (model.mSelectedIcon == null) {
            if (model.mIcon != null && !model.mIcon.isRecycled())
                mIconsCanvas.drawBitmap(model.mIcon, model.mIconMatrix, mIconPaint);
        } else {
            if (mIconPaint.getAlpha() != MIN_ALPHA && model.mIcon != null && !model.mIcon.isRecycled())
                // Draw original icon when is visible
                mIconsCanvas.drawBitmap(model.mIcon, model.mIconMatrix, mIconPaint);
        }
        // Draw selected icon when exist and visible
        if (mSelectedIconPaint.getAlpha() != MIN_ALPHA && model.mSelectedIcon != null
                && !model.mSelectedIcon.isRecycled())
            mIconsCanvas.drawBitmap(model.mSelectedIcon, model.mIconMatrix, mSelectedIconPaint);

        if (mIsTitled)
            mTitlesCanvas.drawText(isInEditMode() ? PREVIEW_TITLE : model.getTitle(), leftTitleOffset,
                    topTitleOffset, mModelTitlePaint);
    }

    // Reset pointer bounds for icons and titles
    if (mIsHorizontalOrientation)
        mPointerBounds.set(mPointerLeftTop, 0.0F, mPointerRightBottom, mBounds.height());
    if (mCornersRadius == 0) {
        if (mIsTinted)
            mIconsCanvas.drawRect(mPointerBounds, mIconPointerPaint);
        if (mIsTitled)
            mTitlesCanvas.drawRect(mPointerBounds, mIconPointerPaint);
    } else {
        if (mIsTinted)
            mIconsCanvas.drawRoundRect(mPointerBounds, mCornersRadius, mCornersRadius, mIconPointerPaint);
        if (mIsTitled)
            mTitlesCanvas.drawRoundRect(mPointerBounds, mCornersRadius, mCornersRadius, mIconPointerPaint);
    }

    // Draw general bitmap
    canvas.drawBitmap(mBitmap, 0.0F, 0.0F, null);
    // Draw icons bitmap on top
    canvas.drawBitmap(mIconsBitmap, 0.0F, barBadgeMargin, null);
    // Draw titles bitmap on top
    if (mIsTitled)
        canvas.drawBitmap(mTitlesBitmap, 0.0F, barBadgeMargin, null);

    // If is not badged, exit
    if (!mIsBadged)
        return;

    // Model badge margin and offset relative to gravity mode
    final float modelBadgeMargin = mBadgeGravity == BadgeGravity.TOP ? mBadgeMargin : mBounds.height();
    final float modelBadgeOffset = mBadgeGravity == BadgeGravity.TOP ? 0.0F : mBounds.height() - mBadgeMargin;

    for (int i = 0; i < mModels.size(); i++) {
        final Model model = mModels.get(i);

        // Set preview badge title
        if (isInEditMode() || TextUtils.isEmpty(model.getBadgeTitle()))
            model.setBadgeTitle(PREVIEW_BADGE);

        // Set badge title bounds
        mBadgePaint.setTextSize(mBadgeTitleSize * model.mBadgeFraction);
        mBadgePaint.getTextBounds(model.getBadgeTitle(), 0, model.getBadgeTitle().length(), mBadgeBounds);

        // Get horizontal and vertical padding for bg
        final float horizontalPadding = mBadgeTitleSize * BADGE_HORIZONTAL_FRACTION;
        final float verticalPadding = horizontalPadding * BADGE_VERTICAL_FRACTION;

        // Set horizontal badge offset
        final float badgeBoundsHorizontalOffset = (mModelSize * i)
                + (mModelSize * mBadgePosition.mPositionFraction);

        // If is badge title only one char, so create circle else round rect
        final float badgeMargin = mBadgeMargin * model.mBadgeFraction;
        if (model.getBadgeTitle().length() == 1) {
            mBgBadgeBounds.set(badgeBoundsHorizontalOffset - badgeMargin, modelBadgeMargin - badgeMargin,
                    badgeBoundsHorizontalOffset + badgeMargin, modelBadgeMargin + badgeMargin);
        } else
            mBgBadgeBounds.set(
                    badgeBoundsHorizontalOffset
                            - Math.max(badgeMargin, mBadgeBounds.centerX() + horizontalPadding),
                    modelBadgeMargin - badgeMargin,
                    badgeBoundsHorizontalOffset
                            + Math.max(badgeMargin, mBadgeBounds.centerX() + horizontalPadding),
                    modelBadgeOffset + (verticalPadding * 2.0F) + mBadgeBounds.height());

        // Set color and alpha for badge bg
        if (model.mBadgeFraction == MIN_FRACTION)
            mBadgePaint.setColor(Color.TRANSPARENT);
        else
            mBadgePaint.setColor(mBadgeBgColor == AUTO_COLOR ? mActiveColor : mBadgeBgColor);
        mBadgePaint.setAlpha((int) (MAX_ALPHA * model.mBadgeFraction));

        // Set corners to round rect for badge bg and draw
        final float cornerRadius = mBgBadgeBounds.height() * 0.5F;
        canvas.drawRoundRect(mBgBadgeBounds, cornerRadius, cornerRadius, mBadgePaint);

        // Set color and alpha for badge title
        if (model.mBadgeFraction == MIN_FRACTION)
            mBadgePaint.setColor(Color.TRANSPARENT);
        else //noinspection ResourceAsColor
            mBadgePaint.setColor(mBadgeTitleColor == AUTO_COLOR ? model.getColor() : mBadgeTitleColor);
        mBadgePaint.setAlpha((int) (MAX_ALPHA * model.mBadgeFraction));

        // Set badge title center position and draw title
        final float badgeHalfHeight = mBadgeBounds.height() * 0.5F;
        float badgeVerticalOffset = (mBgBadgeBounds.height() * 0.5F) + badgeHalfHeight - mBadgeBounds.bottom
                + modelBadgeOffset;
        canvas.drawText(model.getBadgeTitle(), badgeBoundsHorizontalOffset,
                badgeVerticalOffset + mBadgeBounds.height() - (mBadgeBounds.height() * model.mBadgeFraction),
                mBadgePaint);
    }
}