Skip to content

Commit

Permalink
# fixed issue #12: Lollipop elevation disable shadow
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladyslav Baydak committed Feb 26, 2015
1 parent fd4aa94 commit b1b5004
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 36 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
# 1.0.5

1. Fixed [**issue #12**: Lollipop elevation disable shadow](https://github.com/shell-software/fab/issues/12):

The fix enables elevation on devices with **API 21 Lollipop** and higher. Now if elevation is set and the device *API* meets requirements (has *API 21 Lollipop* and higher) elevation will be drawn instead of the default shadow.
In this case configuration of any of the default shadow's parameters will be ignored.
Previously elevation was not drawn for such devices if set.

A fix was applied to:

* **hasShadow()** method: now if **Action Button** has elevation enabled (for *API 21 Lollipop* and higher) the shadow won't be drawn at all
* **calculateCenterX()** method: **getWidth()** method replaced by **getMeasuredWidth()** to calculate *X-axis* coordinate
* **calculateCenterY()** method: **getHeight()** method replaced by **getMeasuredHeight()** is used to calculate *Y-axis* coordinate

New methods added:

* **drawElevation()**: protected void method, which is called by **onDraw(Canvas)** to draw the elevation for *API 21 Lollipop* devices and higher

# 1.0.4

1. Fixed [**issue #8**: Both buttons show up when I only want one at a time](https://github.com/shell-software/fab/issues/8):
Expand Down
39 changes: 27 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
[![Build Status](https://travis-ci.org/shell-software/fab.svg?branch=master)](https://travis-ci.org/shell-software/fab)
[![Maven Central](https://img.shields.io/maven-central/v/com.github.shell-software/fab.svg)](http://search.maven.org/#search|gav|1|g%3A%22com.github.shell-software%22%20AND%20a%3A%22fab%22)
[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-fab-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/1522)
[![Join the chat at https://gitter.im/shell-software/fab](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/shell-software/fab?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

## Donation

Donation helps to improve the project development and speed up the release of new versions. I appreciate any contribution

[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=44CVJBPFRKXJL)

## Description

Expand All @@ -19,31 +24,40 @@ The Library requires **Android SDK version 9 (Gingerbread)** and higher.

```java
dependencies {
compile 'com.github.shell-software:fab:1.0.4'
compile 'com.github.shell-software:fab:1.0.5'
}
```

## Activity Stream

[**Full ChangeLog**](https://github.com/shell-software/fab/blob/master/CHANGELOG.md)

### 1.0.4 - *current*
### 1.0.5 - *current*

1. Fixed [**issue #12**: Lollipop elevation disable shadow](https://github.com/shell-software/fab/issues/12):

The fix enables elevation on devices with **API 21 Lollipop** and higher. Now if elevation is set and the device *API* meets requirements (has *API 21 Lollipop* and higher) elevation will be drawn instead of the default shadow.
In this case configuration of any of the default shadow's parameters will be ignored.
Previously elevation was not drawn for such devices if set.

A fix was applied to:

* **hasShadow()** method: now if **Action Button** has elevation enabled (for *API 21 Lollipop* and higher) the shadow won't be drawn at all
* **calculateCenterX()** method: **getWidth()** method replaced by **getMeasuredWidth()** to calculate *X-axis* coordinate
* **calculateCenterY()** method: **getHeight()** method replaced by **getMeasuredHeight()** is used to calculate *Y-axis* coordinate

New methods added:

* **drawElevation()**: protected void method, which is called by **onDraw(Canvas)** to draw the elevation for *API 21 Lollipop* devices and higher

### 1.0.4 - *previous*

1. Fixed [**issue #8**: Both buttons show up when I only want one at a time](https://github.com/shell-software/fab/issues/8):

A small fix was applied to **show()**, **hide()** and **dismiss()** methods. Previously these methods might not work properly if the call was done within **onCreate()** method.
This happened because of using **android.view.View#isShown()** method, which returned *false* even if the button was shown. Now these methods relay on **VISIBILITY** and work
as expected wherever they called.

### 1.0.3 - *previous*

1. **Attention!** *Deprecated* XML attributes:

* **normal** XML attribute renamed to **DEFAULT**.
You can still use **normal** XML attribute, however it will be removed in version 2.0.0.
* **mini** XML attribute renamed to **MINI**.
You can still use **mini** XML attribute, however it will be removed in version 2.0.0.

### Features in the next versions:

* **1.1.0**:
Expand Down Expand Up @@ -293,6 +307,7 @@ actionButton.removeShadow();
```

> Shadow radius and offset must be specified in density-independent pixels.
> For *API 21 Lollipop* and higher **elevation** can be enabled. In this case the default shadow becomes disabled and configuration of any of its parameters will be ignored.
#### Image

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ext {
ANDROID_BUILD_TOOLS_VERSION = '21.1.2'
ANDROID_MIN_SDK_VERSION = 9
ANDROID_TARGET_SDK_VERSION = 21
ANDROID_VERSION_CODE = 5
ANDROID_VERSION_CODE = 6

}

Expand Down
70 changes: 47 additions & 23 deletions fab/src/main/java/com/software/shell/fab/ActionButton.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.*;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
Expand All @@ -34,6 +31,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;

Expand All @@ -42,7 +40,7 @@
* <a href="http://www.google.com.ua/design/spec/components/buttons.html">Material Design</a>
*
* @author Vladislav
* @version 1.0.2
* @version 1.0.3
* @since 1.0.0
*/
public class ActionButton extends View {
Expand Down Expand Up @@ -613,13 +611,14 @@ public void setButtonColorPressed(int buttonColorPressed) {
}

/**
* Checks whether <b>Action Button</b> has shadow
* by determining shadow radius
* Checks whether <b>Action Button</b> has shadow by determining shadow radius
* <p>
* Shadow is disabled if elevation is set API level is {@code 21 Lollipop} and higher
*
* @return true if <b>Action Button</b> has radius, otherwise false
*/
public boolean hasShadow() {
return getShadowRadius() > 0.0f;
return !hasElevation() && getShadowRadius() > 0.0f;
}

/**
Expand Down Expand Up @@ -1058,6 +1057,9 @@ protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.v(LOG_TAG, "Action Button onDraw called");
drawCircle(canvas);
if (hasElevation()) {
drawElevation();
}
if (hasStroke()) {
drawStroke(canvas);
}
Expand All @@ -1068,7 +1070,7 @@ protected void onDraw(Canvas canvas) {

/**
* Draws the main circle of the <b>Action Button</b> and calls
* {@link #drawShadow()} to draw shadow if present
* {@link #drawShadow()} to draw the shadow if present
*
* @param canvas canvas, on which circle is to be drawn
*/
Expand All @@ -1089,7 +1091,7 @@ protected void drawCircle(Canvas canvas) {
* @return X-axis center coordinate of the entire view
*/
protected float calculateCenterX() {
final float centerX = getWidth() / 2;
final float centerX = getMeasuredWidth() / 2;
Log.v(LOG_TAG, "Calculated center X = " + centerX);
return centerX;
}
Expand All @@ -1100,7 +1102,7 @@ protected float calculateCenterX() {
* @return Y-axis center coordinate of the entire view
*/
protected float calculateCenterY() {
final float centerY = getHeight() / 2;
final float centerY = getMeasuredHeight() / 2;
Log.v(LOG_TAG, "Calculated center Y = " + centerY);
return centerY;
}
Expand All @@ -1120,12 +1122,23 @@ protected final float calculateCircleRadius() {
* Draws the shadow if view elevation is not enabled
*/
protected void drawShadow() {
if (hasElevation()) {
Log.w(LOG_TAG, "Elevation is enabled, skipping shadow enabling");
} else {
paint.setShadowLayer(getShadowRadius(), getShadowXOffset(), getShadowYOffset(), getShadowColor());
Log.v(LOG_TAG, "Shadow enabled");
}
paint.setShadowLayer(getShadowRadius(), getShadowXOffset(), getShadowYOffset(), getShadowColor());
Log.v(LOG_TAG, "Shadow drawn");
}

/**
* Draws the elevation around the main circle
* <p>
* Uses the stroke corrective, which helps to avoid the elevation overlapping issue
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
protected void drawElevation() {
final int strokeWeightCorrective = (int) (getStrokeWidth() / 1.5f);
final int width = getWidth() - strokeWeightCorrective;
final int height = getHeight() - strokeWeightCorrective;
final ViewOutlineProvider outlineProvider = new ActionButtonOutlineProvider(width, height);
setOutlineProvider(outlineProvider);
Log.v(LOG_TAG, "Elevation drawn");
}

/**
Expand Down Expand Up @@ -1192,7 +1205,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
* @return measured width in actual pixels for the entire view
*/
private int calculateMeasuredWidth() {
final int measuredWidth = (int) (getButtonSize() + calculateShadowWidth() * 2 + getStrokeWidth() * 2);
final int measuredWidth = getButtonSize() + calculateShadowWidth() + calculateStrokeWeight();
Log.v(LOG_TAG, "Calculated measured width = " + measuredWidth);
return measuredWidth;
}
Expand All @@ -1203,7 +1216,7 @@ private int calculateMeasuredWidth() {
* @return measured width in actual pixels for the entire view
*/
private int calculateMeasuredHeight() {
final int measuredHeight = (int) (getButtonSize() + calculateShadowHeight() * 2 + getStrokeWidth() * 2);
final int measuredHeight = getButtonSize() + calculateShadowHeight() + calculateStrokeWeight();
Log.v(LOG_TAG, "Calculated measured height = " + measuredHeight);
return measuredHeight;
}
Expand All @@ -1213,8 +1226,8 @@ private int calculateMeasuredHeight() {
*
* @return shadow width in actual pixels
*/
private float calculateShadowWidth() {
final float shadowWidth = hasShadow() ? getShadowRadius() + Math.abs(getShadowXOffset()) : 0.0f;
private int calculateShadowWidth() {
final int shadowWidth = hasShadow() ? (int) ((getShadowRadius() + Math.abs(getShadowXOffset())) * 2) : 0;
Log.v(LOG_TAG, "Calculated shadow width = " + shadowWidth);
return shadowWidth;
}
Expand All @@ -1224,12 +1237,23 @@ private float calculateShadowWidth() {
*
* @return shadow height in actual pixels
*/
private float calculateShadowHeight() {
final float shadowHeight = hasShadow() ? getShadowRadius() + Math.abs(getShadowYOffset()) : 0.0f;
private int calculateShadowHeight() {
final int shadowHeight = hasShadow() ? (int) ((getShadowRadius() + Math.abs(getShadowYOffset())) * 2) : 0;
Log.v(LOG_TAG, "Calculated shadow height = " + shadowHeight);
return shadowHeight;
}

/**
* Calculates the stroke weight in actual pixels
* *
* @return stroke weight in actual pixels
*/
private int calculateStrokeWeight() {
final int strokeWeight = (int) (getStrokeWidth() * 2.0f);
Log.v(LOG_TAG, "Calculated stroke weight is: " + strokeWeight);
return strokeWeight;
}

/**
* Determines the <b>Action Button</b> types
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2015 Shell Software Inc.
*
* 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.
*
* File created: 2015-02-25 19:54:28
*/

package com.software.shell.fab;

import android.annotation.TargetApi;
import android.graphics.Outline;
import android.os.Build;
import android.view.View;
import android.view.ViewOutlineProvider;

/**
* An implementation of the {@link android.view.ViewOutlineProvider}
* for <b>Action Button</b>
*
* Used for drawing the elevation shadow for {@code API 21 Lollipop} and higher
*
* @author Vladislav
* @version 1.0.0
* @since 1.0.0
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class ActionButtonOutlineProvider extends ViewOutlineProvider {

/**
* Outline provider width
*/
private int width;

/**
* Outline provider height
*/
private int height;

/**
* Creates an instance of the {@link com.software.shell.fab.ActionButtonOutlineProvider}
*
* @param width initial outline provider width
* @param height initial outline provider height
*/
ActionButtonOutlineProvider(int width, int height) {
this.width = width;
this.height = height;
}

/**
* Called to get the provider to populate the Outline. This method will be called by a View
* when its owned Drawables are invalidated, when the View's size changes, or if invalidateOutline()
* is called explicitly. The input outline is empty and has an alpha of 1.0f
*
* @param view a view, which builds the outline
* @param outline an empty outline, which is to be populated
*/
@Override
public void getOutline(View view, Outline outline) {
outline.setOval(0, 0, width, height);
}

}

0 comments on commit b1b5004

Please sign in to comment.