Skip to content

Commit b1b5004

Browse files
author
Vladyslav Baydak
committed
# fixed issue #12: Lollipop elevation disable shadow
1 parent fd4aa94 commit b1b5004

File tree

5 files changed

+167
-36
lines changed

5 files changed

+167
-36
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
# 1.0.5
2+
3+
1. Fixed [**issue #12**: Lollipop elevation disable shadow](https://github.com/shell-software/fab/issues/12):
4+
5+
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.
6+
In this case configuration of any of the default shadow's parameters will be ignored.
7+
Previously elevation was not drawn for such devices if set.
8+
9+
A fix was applied to:
10+
11+
* **hasShadow()** method: now if **Action Button** has elevation enabled (for *API 21 Lollipop* and higher) the shadow won't be drawn at all
12+
* **calculateCenterX()** method: **getWidth()** method replaced by **getMeasuredWidth()** to calculate *X-axis* coordinate
13+
* **calculateCenterY()** method: **getHeight()** method replaced by **getMeasuredHeight()** is used to calculate *Y-axis* coordinate
14+
15+
New methods added:
16+
17+
* **drawElevation()**: protected void method, which is called by **onDraw(Canvas)** to draw the elevation for *API 21 Lollipop* devices and higher
18+
119
# 1.0.4
220

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

README.md

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
[![Build Status](https://travis-ci.org/shell-software/fab.svg?branch=master)](https://travis-ci.org/shell-software/fab)
44
[![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)
55
[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-fab-brightgreen.svg?style=flat)](https://android-arsenal.com/details/1/1522)
6-
[![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)
6+
7+
## Donation
8+
9+
Donation helps to improve the project development and speed up the release of new versions. I appreciate any contribution
10+
11+
[![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)
712

813
## Description
914

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

2025
```java
2126
dependencies {
22-
compile 'com.github.shell-software:fab:1.0.4'
27+
compile 'com.github.shell-software:fab:1.0.5'
2328
}
2429
```
2530

2631
## Activity Stream
2732

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

30-
### 1.0.4 - *current*
35+
### 1.0.5 - *current*
36+
37+
1. Fixed [**issue #12**: Lollipop elevation disable shadow](https://github.com/shell-software/fab/issues/12):
38+
39+
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.
40+
In this case configuration of any of the default shadow's parameters will be ignored.
41+
Previously elevation was not drawn for such devices if set.
42+
43+
A fix was applied to:
44+
45+
* **hasShadow()** method: now if **Action Button** has elevation enabled (for *API 21 Lollipop* and higher) the shadow won't be drawn at all
46+
* **calculateCenterX()** method: **getWidth()** method replaced by **getMeasuredWidth()** to calculate *X-axis* coordinate
47+
* **calculateCenterY()** method: **getHeight()** method replaced by **getMeasuredHeight()** is used to calculate *Y-axis* coordinate
48+
49+
New methods added:
50+
51+
* **drawElevation()**: protected void method, which is called by **onDraw(Canvas)** to draw the elevation for *API 21 Lollipop* devices and higher
52+
53+
### 1.0.4 - *previous*
3154

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

3457
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.
3558
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
3659
as expected wherever they called.
3760

38-
### 1.0.3 - *previous*
39-
40-
1. **Attention!** *Deprecated* XML attributes:
41-
42-
* **normal** XML attribute renamed to **DEFAULT**.
43-
You can still use **normal** XML attribute, however it will be removed in version 2.0.0.
44-
* **mini** XML attribute renamed to **MINI**.
45-
You can still use **mini** XML attribute, however it will be removed in version 2.0.0.
46-
4761
### Features in the next versions:
4862

4963
* **1.1.0**:
@@ -293,6 +307,7 @@ actionButton.removeShadow();
293307
```
294308

295309
> Shadow radius and offset must be specified in density-independent pixels.
310+
> 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.
296311
297312
#### Image
298313

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ ext {
2222
ANDROID_BUILD_TOOLS_VERSION = '21.1.2'
2323
ANDROID_MIN_SDK_VERSION = 9
2424
ANDROID_TARGET_SDK_VERSION = 21
25-
ANDROID_VERSION_CODE = 5
25+
ANDROID_VERSION_CODE = 6
2626

2727
}
2828

fab/src/main/java/com/software/shell/fab/ActionButton.java

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@
2222
import android.annotation.TargetApi;
2323
import android.content.Context;
2424
import android.content.res.TypedArray;
25-
import android.graphics.Bitmap;
26-
import android.graphics.Canvas;
27-
import android.graphics.Color;
28-
import android.graphics.Paint;
25+
import android.graphics.*;
2926
import android.graphics.drawable.BitmapDrawable;
3027
import android.graphics.drawable.Drawable;
3128
import android.os.Build;
@@ -34,6 +31,7 @@
3431
import android.view.MotionEvent;
3532
import android.view.View;
3633
import android.view.ViewGroup;
34+
import android.view.ViewOutlineProvider;
3735
import android.view.animation.Animation;
3836
import android.view.animation.AnimationUtils;
3937

@@ -42,7 +40,7 @@
4240
* <a href="http://www.google.com.ua/design/spec/components/buttons.html">Material Design</a>
4341
*
4442
* @author Vladislav
45-
* @version 1.0.2
43+
* @version 1.0.3
4644
* @since 1.0.0
4745
*/
4846
public class ActionButton extends View {
@@ -613,13 +611,14 @@ public void setButtonColorPressed(int buttonColorPressed) {
613611
}
614612

615613
/**
616-
* Checks whether <b>Action Button</b> has shadow
617-
* by determining shadow radius
614+
* Checks whether <b>Action Button</b> has shadow by determining shadow radius
615+
* <p>
616+
* Shadow is disabled if elevation is set API level is {@code 21 Lollipop} and higher
618617
*
619618
* @return true if <b>Action Button</b> has radius, otherwise false
620619
*/
621620
public boolean hasShadow() {
622-
return getShadowRadius() > 0.0f;
621+
return !hasElevation() && getShadowRadius() > 0.0f;
623622
}
624623

625624
/**
@@ -1058,6 +1057,9 @@ protected void onDraw(Canvas canvas) {
10581057
super.onDraw(canvas);
10591058
Log.v(LOG_TAG, "Action Button onDraw called");
10601059
drawCircle(canvas);
1060+
if (hasElevation()) {
1061+
drawElevation();
1062+
}
10611063
if (hasStroke()) {
10621064
drawStroke(canvas);
10631065
}
@@ -1068,7 +1070,7 @@ protected void onDraw(Canvas canvas) {
10681070

10691071
/**
10701072
* Draws the main circle of the <b>Action Button</b> and calls
1071-
* {@link #drawShadow()} to draw shadow if present
1073+
* {@link #drawShadow()} to draw the shadow if present
10721074
*
10731075
* @param canvas canvas, on which circle is to be drawn
10741076
*/
@@ -1089,7 +1091,7 @@ protected void drawCircle(Canvas canvas) {
10891091
* @return X-axis center coordinate of the entire view
10901092
*/
10911093
protected float calculateCenterX() {
1092-
final float centerX = getWidth() / 2;
1094+
final float centerX = getMeasuredWidth() / 2;
10931095
Log.v(LOG_TAG, "Calculated center X = " + centerX);
10941096
return centerX;
10951097
}
@@ -1100,7 +1102,7 @@ protected float calculateCenterX() {
11001102
* @return Y-axis center coordinate of the entire view
11011103
*/
11021104
protected float calculateCenterY() {
1103-
final float centerY = getHeight() / 2;
1105+
final float centerY = getMeasuredHeight() / 2;
11041106
Log.v(LOG_TAG, "Calculated center Y = " + centerY);
11051107
return centerY;
11061108
}
@@ -1120,12 +1122,23 @@ protected final float calculateCircleRadius() {
11201122
* Draws the shadow if view elevation is not enabled
11211123
*/
11221124
protected void drawShadow() {
1123-
if (hasElevation()) {
1124-
Log.w(LOG_TAG, "Elevation is enabled, skipping shadow enabling");
1125-
} else {
1126-
paint.setShadowLayer(getShadowRadius(), getShadowXOffset(), getShadowYOffset(), getShadowColor());
1127-
Log.v(LOG_TAG, "Shadow enabled");
1128-
}
1125+
paint.setShadowLayer(getShadowRadius(), getShadowXOffset(), getShadowYOffset(), getShadowColor());
1126+
Log.v(LOG_TAG, "Shadow drawn");
1127+
}
1128+
1129+
/**
1130+
* Draws the elevation around the main circle
1131+
* <p>
1132+
* Uses the stroke corrective, which helps to avoid the elevation overlapping issue
1133+
*/
1134+
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
1135+
protected void drawElevation() {
1136+
final int strokeWeightCorrective = (int) (getStrokeWidth() / 1.5f);
1137+
final int width = getWidth() - strokeWeightCorrective;
1138+
final int height = getHeight() - strokeWeightCorrective;
1139+
final ViewOutlineProvider outlineProvider = new ActionButtonOutlineProvider(width, height);
1140+
setOutlineProvider(outlineProvider);
1141+
Log.v(LOG_TAG, "Elevation drawn");
11291142
}
11301143

11311144
/**
@@ -1192,7 +1205,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
11921205
* @return measured width in actual pixels for the entire view
11931206
*/
11941207
private int calculateMeasuredWidth() {
1195-
final int measuredWidth = (int) (getButtonSize() + calculateShadowWidth() * 2 + getStrokeWidth() * 2);
1208+
final int measuredWidth = getButtonSize() + calculateShadowWidth() + calculateStrokeWeight();
11961209
Log.v(LOG_TAG, "Calculated measured width = " + measuredWidth);
11971210
return measuredWidth;
11981211
}
@@ -1203,7 +1216,7 @@ private int calculateMeasuredWidth() {
12031216
* @return measured width in actual pixels for the entire view
12041217
*/
12051218
private int calculateMeasuredHeight() {
1206-
final int measuredHeight = (int) (getButtonSize() + calculateShadowHeight() * 2 + getStrokeWidth() * 2);
1219+
final int measuredHeight = getButtonSize() + calculateShadowHeight() + calculateStrokeWeight();
12071220
Log.v(LOG_TAG, "Calculated measured height = " + measuredHeight);
12081221
return measuredHeight;
12091222
}
@@ -1213,8 +1226,8 @@ private int calculateMeasuredHeight() {
12131226
*
12141227
* @return shadow width in actual pixels
12151228
*/
1216-
private float calculateShadowWidth() {
1217-
final float shadowWidth = hasShadow() ? getShadowRadius() + Math.abs(getShadowXOffset()) : 0.0f;
1229+
private int calculateShadowWidth() {
1230+
final int shadowWidth = hasShadow() ? (int) ((getShadowRadius() + Math.abs(getShadowXOffset())) * 2) : 0;
12181231
Log.v(LOG_TAG, "Calculated shadow width = " + shadowWidth);
12191232
return shadowWidth;
12201233
}
@@ -1224,12 +1237,23 @@ private float calculateShadowWidth() {
12241237
*
12251238
* @return shadow height in actual pixels
12261239
*/
1227-
private float calculateShadowHeight() {
1228-
final float shadowHeight = hasShadow() ? getShadowRadius() + Math.abs(getShadowYOffset()) : 0.0f;
1240+
private int calculateShadowHeight() {
1241+
final int shadowHeight = hasShadow() ? (int) ((getShadowRadius() + Math.abs(getShadowYOffset())) * 2) : 0;
12291242
Log.v(LOG_TAG, "Calculated shadow height = " + shadowHeight);
12301243
return shadowHeight;
12311244
}
12321245

1246+
/**
1247+
* Calculates the stroke weight in actual pixels
1248+
* *
1249+
* @return stroke weight in actual pixels
1250+
*/
1251+
private int calculateStrokeWeight() {
1252+
final int strokeWeight = (int) (getStrokeWidth() * 2.0f);
1253+
Log.v(LOG_TAG, "Calculated stroke weight is: " + strokeWeight);
1254+
return strokeWeight;
1255+
}
1256+
12331257
/**
12341258
* Determines the <b>Action Button</b> types
12351259
*/
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2015 Shell Software Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* File created: 2015-02-25 19:54:28
17+
*/
18+
19+
package com.software.shell.fab;
20+
21+
import android.annotation.TargetApi;
22+
import android.graphics.Outline;
23+
import android.os.Build;
24+
import android.view.View;
25+
import android.view.ViewOutlineProvider;
26+
27+
/**
28+
* An implementation of the {@link android.view.ViewOutlineProvider}
29+
* for <b>Action Button</b>
30+
*
31+
* Used for drawing the elevation shadow for {@code API 21 Lollipop} and higher
32+
*
33+
* @author Vladislav
34+
* @version 1.0.0
35+
* @since 1.0.0
36+
*/
37+
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
38+
class ActionButtonOutlineProvider extends ViewOutlineProvider {
39+
40+
/**
41+
* Outline provider width
42+
*/
43+
private int width;
44+
45+
/**
46+
* Outline provider height
47+
*/
48+
private int height;
49+
50+
/**
51+
* Creates an instance of the {@link com.software.shell.fab.ActionButtonOutlineProvider}
52+
*
53+
* @param width initial outline provider width
54+
* @param height initial outline provider height
55+
*/
56+
ActionButtonOutlineProvider(int width, int height) {
57+
this.width = width;
58+
this.height = height;
59+
}
60+
61+
/**
62+
* Called to get the provider to populate the Outline. This method will be called by a View
63+
* when its owned Drawables are invalidated, when the View's size changes, or if invalidateOutline()
64+
* is called explicitly. The input outline is empty and has an alpha of 1.0f
65+
*
66+
* @param view a view, which builds the outline
67+
* @param outline an empty outline, which is to be populated
68+
*/
69+
@Override
70+
public void getOutline(View view, Outline outline) {
71+
outline.setOval(0, 0, width, height);
72+
}
73+
74+
}

0 commit comments

Comments
 (0)