Skip to content

Commit

Permalink
shadow
Browse files Browse the repository at this point in the history
  • Loading branch information
KiWiLss committed Jan 5, 2018
1 parent 97093e4 commit 7877931
Show file tree
Hide file tree
Showing 4 changed files with 297 additions and 0 deletions.
1 change: 1 addition & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

279 changes: 279 additions & 0 deletions mylibrary/src/main/java/com/magicsoft/mylibrary/ShadowLayout.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
/*
* Copyright (C) 2015 Basil Miller
*
* 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 com.magicsoft.mylibrary;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.FrameLayout;


/**
* Created by GIGAMOLE on 13.04.2016.
*/
public class ShadowLayout extends FrameLayout {

// Default shadow values
private final static float DEFAULT_SHADOW_RADIUS = 30.0F;
private final static float DEFAULT_SHADOW_DISTANCE = 15.0F;
private final static float DEFAULT_SHADOW_ANGLE = 45.0F;
private final static int DEFAULT_SHADOW_COLOR = Color.DKGRAY;

// Shadow bounds values
private final static int MAX_ALPHA = 255;
private final static float MAX_ANGLE = 360.0F;
private final static float MIN_RADIUS = 0.1F;
private final static float MIN_ANGLE = 0.0F;
// Shadow paint
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG) {
{
setDither(true);
setFilterBitmap(true);
}
};
// Shadow bitmap and canvas
private Bitmap mBitmap;
private final Canvas mCanvas = new Canvas();
// View bounds
private final Rect mBounds = new Rect();
// Check whether need to redraw shadow
private boolean mInvalidateShadow = true;

// Detect if shadow is visible
private boolean mIsShadowed;

// Shadow variables
private int mShadowColor;
private int mShadowAlpha;
private float mShadowRadius;
private float mShadowDistance;
private float mShadowAngle;
private float mShadowDx;
private float mShadowDy;

public ShadowLayout(final Context context) {
this(context, null);
}

public ShadowLayout(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
}

public ShadowLayout(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);

setWillNotDraw(false);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType(LAYER_TYPE_HARDWARE, mPaint);
}

// Retrieve attributes from xml
final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ShadowLayout);
try {
setIsShadowed(typedArray.getBoolean(R.styleable.ShadowLayout_sl_shadowed, true));
setShadowRadius(
typedArray.getDimension(
R.styleable.ShadowLayout_sl_shadow_radius, DEFAULT_SHADOW_RADIUS
)
);
setShadowDistance(
typedArray.getDimension(
R.styleable.ShadowLayout_sl_shadow_distance, DEFAULT_SHADOW_DISTANCE
)
);
setShadowAngle(
typedArray.getInteger(
R.styleable.ShadowLayout_sl_shadow_angle, (int) DEFAULT_SHADOW_ANGLE
)
);
setShadowColor(
typedArray.getColor(
R.styleable.ShadowLayout_sl_shadow_color, DEFAULT_SHADOW_COLOR
)
);
} finally {
typedArray.recycle();
}
}

@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// Clear shadow bitmap
if (mBitmap != null) {
mBitmap.recycle();
mBitmap = null;
}
}

public boolean isShadowed() {
return mIsShadowed;
}

public void setIsShadowed(final boolean isShadowed) {
mIsShadowed = isShadowed;
postInvalidate();
}

public float getShadowDistance() {
return mShadowDistance;
}

public void setShadowDistance(final float shadowDistance) {
mShadowDistance = shadowDistance;
resetShadow();
}

public float getShadowAngle() {
return mShadowAngle;
}

public void setShadowAngle(final float shadowAngle) {
mShadowAngle = Math.max(MIN_ANGLE, Math.min(shadowAngle, MAX_ANGLE));
resetShadow();
}

public float getShadowRadius() {
return mShadowRadius;
}

public void setShadowRadius(final float shadowRadius) {
mShadowRadius = Math.max(MIN_RADIUS, shadowRadius);

if (isInEditMode()) return;
// Set blur filter to paint
mPaint.setMaskFilter(new BlurMaskFilter(mShadowRadius, BlurMaskFilter.Blur.NORMAL));
resetShadow();
}

public int getShadowColor() {
return mShadowColor;
}

public void setShadowColor(final int shadowColor) {
mShadowColor = shadowColor;
mShadowAlpha = Color.alpha(shadowColor);

resetShadow();
}

public float getShadowDx() {
return mShadowDx;
}

public float getShadowDy() {
return mShadowDy;
}

// Reset shadow layer
private void resetShadow() {
// Detect shadow axis offset
mShadowDx = (float) ((mShadowDistance) * Math.cos(mShadowAngle / 180.0F * Math.PI));
mShadowDy = (float) ((mShadowDistance) * Math.sin(mShadowAngle / 180.0F * Math.PI));

// Set padding for shadow bitmap
// final int padding = (int) (mShadowDistance + mShadowRadius);
// setPadding(padding, padding, padding, padding);
requestLayout();
}

private int adjustShadowAlpha(final boolean adjust) {
return Color.argb(
adjust ? MAX_ALPHA : mShadowAlpha,
Color.red(mShadowColor),
Color.green(mShadowColor),
Color.blue(mShadowColor)
);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

// Set ShadowLayout bounds
mBounds.set(
0, 0, MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)
);
}

@Override
public void requestLayout() {
// Redraw shadow
mInvalidateShadow = true;
super.requestLayout();
}

@Override
protected void dispatchDraw(final Canvas canvas) {
// If is not shadowed, skip
if (mIsShadowed) {
// If need to redraw shadow
if (mInvalidateShadow) {
// If bounds is zero
if (mBounds.width() != 0 && mBounds.height() != 0) {
// Reset bitmap to bounds
mBitmap = Bitmap.createBitmap(
mBounds.width(), mBounds.height(), Bitmap.Config.ARGB_8888
);
// Canvas reset
mCanvas.setBitmap(mBitmap);

// We just redraw
// mInvalidateShadow = false;
// Main feature of this lib. We create the local copy of all content, so now
// we can draw bitmap as a bottom layer of natural canvas.
// We draw shadow like blur effect on bitmap, cause of setShadowLayer() method of
// paint does`t draw shadow, it draw another copy of bitmap
super.dispatchDraw(mCanvas);

// Get the alpha bounds of bitmap
final Bitmap extractedAlpha = mBitmap.extractAlpha();
// Clear past content content to draw shadow
mCanvas.drawColor(0, PorterDuff.Mode.CLEAR);

// Draw extracted alpha bounds of our local canvas
mPaint.setColor(adjustShadowAlpha(false));
mCanvas.drawBitmap(extractedAlpha, mShadowDx, mShadowDy, mPaint);

// Recycle and clear extracted alpha
extractedAlpha.recycle();
} else {
// Create placeholder bitmap when size is zero and wait until new size coming up
mBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);
}
}

// Reset alpha to draw child with full alpha
mPaint.setColor(adjustShadowAlpha(true));
// Draw shadow bitmap
if (mCanvas != null && mBitmap != null && !mBitmap.isRecycled())
canvas.drawBitmap(mBitmap, 0.0F, 0.0F, mPaint);
}

// Draw child`s
super.dispatchDraw(canvas);
}
}
11 changes: 11 additions & 0 deletions mylibrary/src/main/res/values/attrs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>

<declare-styleable name="ShadowLayout">
<attr name="sl_shadowed" format="boolean" />
<attr name="sl_shadow_distance" format="dimension" />
<attr name="sl_shadow_angle" format="integer" />
<attr name="sl_shadow_radius" format="dimension" />
<attr name="sl_shadow_color" format="color" />
</declare-styleable>
</resources>

0 comments on commit 7877931

Please sign in to comment.