* [android] Fix linear-gradient & border-radius & clipPath cannot work together if system version is 4.3 or 4.4. (#2759)
Without this fix, the border-radius of linear-gradient div in the following page will not work. http://dotwe.org/weex/963c9ade129f86757cecdd85651cd30e This is mostly likely due to OpenGL ES 3.1, which provided "Separate shader objects" is not supported until android 5.0. Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/fc11bc58 Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/fc11bc58 Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/fc11bc58 Branch: refs/heads/0.11-dev Commit: fc11bc58c4813be8f68bb696bf920e1980107bfd Parents: 5a03143 Author: YorkShen <shenyua...@gmail.com> Authored: Tue Feb 28 20:05:31 2017 +0800 Committer: sospartan zheng <sospar...@apache.org> Committed: Tue Feb 28 20:05:31 2017 +0800 ---------------------------------------------------------------------- .../weex/ui/view/border/BorderDrawable.java | 4 ++ .../java/com/taobao/weex/utils/WXViewUtils.java | 71 ++++++++++++++++---- 2 files changed, 62 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/fc11bc58/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderDrawable.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderDrawable.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderDrawable.java index 174b4f7..dd5f96d 100755 --- a/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderDrawable.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/view/border/BorderDrawable.java @@ -455,6 +455,10 @@ public class BorderDrawable extends Drawable { invalidateSelf(); } + public boolean hasImage(){ + return mShader!=null; + } + public boolean isRounded() { return mBorderRadius != null && (!FloatUtil.floatsEqual(getBorderRadius(mBorderRadius, BORDER_TOP_LEFT_RADIUS), 0) || http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/fc11bc58/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java index 3dd5bcc..e075ee8 100755 --- a/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java +++ b/android/sdk/src/main/java/com/taobao/weex/utils/WXViewUtils.java @@ -216,6 +216,7 @@ import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.View; +import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import com.taobao.weex.WXEnvironment; @@ -535,22 +536,66 @@ public class WXViewUtils { public static void clipCanvasWithinBorderBox(View targetView, Canvas canvas) { Drawable drawable; - /* According to https://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported - API 18 or higher supports clipPath to canvas based on hardware acceleration. - */ - /** - * According to https://code.google.com/p/android/issues/detail?id=225556&sort=-id&colspec=ID - * clipPath doesn't work with rotation nor scale when API level is 24 or higher. - */ - if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 || !canvas.isHardwareAccelerated()) && - Build.VERSION.SDK_INT <= Build.VERSION_CODES.M && + if (clipCanvasDueToAndroidVersion(canvas) && + clipCanvasIfAnimationExist() && ((drawable = targetView.getBackground()) instanceof BorderDrawable)) { BorderDrawable borderDrawable = (BorderDrawable) drawable; - if(borderDrawable.isRounded()) { - Path path = borderDrawable.getContentPath( - new RectF(0, 0, targetView.getWidth(), targetView.getHeight())); - canvas.clipPath(path); + if (borderDrawable.isRounded()) { + if (clipCanvasIfBackgroundImageExist(targetView, borderDrawable)) { + Path path = borderDrawable.getContentPath( + new RectF(0, 0, targetView.getWidth(), targetView.getHeight())); + canvas.clipPath(path); + } + } + } + } + + /** + * According to https://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported + API 18 or higher supports clipPath to canvas based on hardware acceleration. + * @param canvas + * @return + */ + private static boolean clipCanvasDueToAndroidVersion(Canvas canvas) { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 || + !canvas.isHardwareAccelerated(); + } + + /** + * According to https://code.google.com/p/android/issues/detail?id=225556&sort=-id&colspec=ID + * clipPath doesn't work with rotation nor scale when API level is 24. + * As animation will not cause redraw if hardware-acceleration enabled, clipCanvas feature has + * to be disabled when API level is 24 without considering the animation property. + * As the compile version of weex_sdk is 23, so API level 24 has to be hard-code. + */ + private static boolean clipCanvasIfAnimationExist() { + return Build.VERSION.SDK_INT != 24; + } + + /** + * Due limitation in Android platform, the linear gradient in the following page will not be + * rounded if {@link Canvas#clipPath(Path)} of the parent view invoked when API level is lower + * than 21. + * http://dotwe.org/weex/963c9ade129f86757cecdd85651cd30e + * @param targetView + * @param borderDrawable + * @return + */ + private static boolean clipCanvasIfBackgroundImageExist(@NonNull View targetView, + @NonNull BorderDrawable borderDrawable) { + if (targetView instanceof ViewGroup) { + View child; + ViewGroup parent = ((ViewGroup) targetView); + int count = parent.getChildCount(); + for (int i = 0; i < count; i++) { + child = parent.getChildAt(i); + if (child.getBackground() instanceof BorderDrawable && + ((BorderDrawable) child.getBackground()).hasImage() && + Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + return false; + } } } + return true; } }