Use elevation to implement shadows on Android
Summary: This PR includes a working interface to Android's `elevation` property implemented as an RN style. Elevation is the only (easy) [platform-supported way to create shadows](http://developer.android.com/training/material/shadows-clipping.html). For it to work note that you must be running on Android 5.0+, and add `elevation` to a view with a `backgroundColor` set. These are platform limitations. This PR is not intended to be merged in its current state, but rather to inform the discussion from #2768. At a minimum, before merging we would need to add the elevation style to the docs and rebase this to master (**EDIT** I have now rebased on master because from v0.14.2 too many commits were being pulled in -- haven't tested it since the rebase though). Additionally, it might be good to add tests, although I couldn't find any for the Android code. I'm happy to get that done if this feature gets signed off by the React Native team. Finally, as I argued in #2768 I think that `elevation` is a useful abstraction ov Closes https://github.com/facebook/react-native/pull/4180 Reviewed By: svcscm Differential Revision: D2684746 Pulled By: mkonicek fb-gh-sync-id: 825f3ccd20c4b0eea9d11b5f0e3a6b018b7e4378
This commit is contained in:
parent
c11d861807
commit
b65f1f2234
|
@ -47,6 +47,14 @@ var ViewStylePropTypes = {
|
|||
),
|
||||
shadowOpacity: ReactPropTypes.number,
|
||||
shadowRadius: ReactPropTypes.number,
|
||||
/**
|
||||
* (Android-only) Sets the elevation of a view, using Android's underlying
|
||||
* [elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation).
|
||||
* This adds a drop shadow to the item and affects z-order for overlapping views.
|
||||
* Only supported on Android 5.0+, has no effect on earlier versions.
|
||||
* @platform android
|
||||
*/
|
||||
elevation: ReactPropTypes.number,
|
||||
};
|
||||
|
||||
module.exports = ViewStylePropTypes;
|
||||
|
|
|
@ -17,12 +17,14 @@ import android.graphics.Canvas;
|
|||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.DashPathEffect;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PathEffect;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
|
||||
import com.facebook.react.common.annotations.VisibleForTesting;
|
||||
import com.facebook.csslayout.CSSConstants;
|
||||
|
@ -123,6 +125,23 @@ import com.facebook.csslayout.Spacing;
|
|||
return ColorUtil.getOpacityFromColor(ColorUtil.multiplyColorAlpha(mColor, mAlpha));
|
||||
}
|
||||
|
||||
/* Android's elevation implementation requires this to be implemented to know where to draw the shadow. */
|
||||
@Override
|
||||
public void getOutline(Outline outline) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
super.getOutline(outline);
|
||||
return;
|
||||
}
|
||||
if(!CSSConstants.isUndefined(mBorderRadius) && mBorderRadius > 0) {
|
||||
float extraRadiusFromBorderWidth = (mBorderWidth != null)
|
||||
? mBorderWidth.get(Spacing.ALL) / 2f
|
||||
: 0;
|
||||
outline.setRoundRect(getBounds(), mBorderRadius + extraRadiusFromBorderWidth);
|
||||
} else {
|
||||
super.getOutline(outline);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBorderWidth(int position, float width) {
|
||||
if (mBorderWidth == null) {
|
||||
mBorderWidth = new Spacing();
|
||||
|
|
|
@ -64,6 +64,14 @@ public class ReactViewManager extends ViewGroupManager<ReactViewGroup> {
|
|||
view.setBorderStyle(borderStyle);
|
||||
}
|
||||
|
||||
@ReactProp(name = "elevation")
|
||||
public void setElevation(ReactViewGroup view, float elevation) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setElevation(PixelUtil.toPixelFromDIP(elevation));
|
||||
}
|
||||
// Do nothing on API < 21
|
||||
}
|
||||
|
||||
@ReactProp(name = "pointerEvents")
|
||||
public void setPointerEvents(ReactViewGroup view, @Nullable String pointerEventsStr) {
|
||||
if (pointerEventsStr != null) {
|
||||
|
|
Loading…
Reference in New Issue