From 4c8b6f8b3d673948900accfeb8d8bfc3af38e59f Mon Sep 17 00:00:00 2001 From: maxli Date: Tue, 8 Mar 2022 23:08:31 +0800 Subject: [PATCH] refactor(android): ripple impl --- .../tencent/mtt/hippy/dom/node/NodeProps.java | 1 + .../mtt/hippy/uimanager/DrawableFactory.java | 92 ++++++++ .../hippy/views/view/HippyDrawableHelper.java | 92 -------- .../views/view/HippyViewGroupController.java | 201 +++++++++--------- .../views/asyncimage/AsyncImageView.java | 146 +++++-------- 5 files changed, 240 insertions(+), 292 deletions(-) create mode 100644 android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/DrawableFactory.java delete mode 100644 android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyDrawableHelper.java diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/NodeProps.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/NodeProps.java index dee86ae6ae0..603abf868ca 100644 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/NodeProps.java +++ b/android/sdk/src/main/java/com/tencent/mtt/hippy/dom/node/NodeProps.java @@ -167,6 +167,7 @@ public class NodeProps { public static final String VISIBLE = "visible"; public static final String REPEAT_COUNT = "repeatCount"; public static final String ATTRIBUTES = "attributes"; + public static final String BACKGROUND_RIPPLE = "nativeBackgroundAndroid"; private static final HashSet JUST_LAYOUT_PROPS = new HashSet<>( Arrays.asList(ALIGN_SELF, ALIGN_ITEMS, COLLAPSABLE, FLEX, FLEX_DIRECTION, FLEX_WRAP, diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/DrawableFactory.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/DrawableFactory.java new file mode 100644 index 00000000000..07ae2704596 --- /dev/null +++ b/android/sdk/src/main/java/com/tencent/mtt/hippy/uimanager/DrawableFactory.java @@ -0,0 +1,92 @@ +/* Tencent is pleased to support the open source community by making Hippy available. + * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. + * + * 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.tencent.mtt.hippy.uimanager; + +import static android.graphics.drawable.RippleDrawable.RADIUS_AUTO; + +import android.content.res.ColorStateList; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.RippleDrawable; +import android.os.Build; + +import com.tencent.mtt.hippy.annotation.HippyMethod; +import com.tencent.mtt.hippy.common.HippyMap; +import com.tencent.mtt.hippy.utils.PixelUtil; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; + +import java.util.Map; + +public class DrawableFactory { + + private static final String PROPERTY_RIPPLE_COLOR = "color"; + private static final String PROPERTY_RIPPLE_RADIUS = "rippleRadius"; + private static final String PROPERTY_RIPPLE_BORDERLESS = "borderless"; + + public enum DrawableType { + DRAWABLE_TYPE_RIPPLE + } + + @Nullable + public static Drawable createDrawable(DrawableType type, @Nullable HippyMap params) { + Drawable drawable = null; + switch (type) { + case DRAWABLE_TYPE_RIPPLE: + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + drawable = createRippleDrawable(params); + } + break; + default: + } + + return drawable; + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @NonNull + private static Drawable createRippleDrawable(@Nullable HippyMap params) { + int color = Color.BLUE; + int radius = 0; + Drawable mask = null; + if (params != null) { + if (params.containsKey(PROPERTY_RIPPLE_COLOR) + && !params.isNull(PROPERTY_RIPPLE_COLOR)) { + color = params.getInt(PROPERTY_RIPPLE_COLOR); + } + if (params.containsKey(PROPERTY_RIPPLE_RADIUS)) { + double rd = params.getDouble(PROPERTY_RIPPLE_RADIUS); + radius = (int) (PixelUtil.dp2px(rd) + 0.5); + } + if (!params.containsKey(PROPERTY_RIPPLE_BORDERLESS) + || params.isNull(PROPERTY_RIPPLE_BORDERLESS) + || !params.getBoolean(PROPERTY_RIPPLE_BORDERLESS)) { + mask = new ColorDrawable(Color.WHITE); + } + } + ColorStateList colorStateList = + new ColorStateList(new int[][]{new int[]{}}, new int[]{color}); + RippleDrawable drawable = new RippleDrawable(colorStateList, null, mask); + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && radius > 0) { + drawable.setRadius(radius); + } + return drawable; + } +} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyDrawableHelper.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyDrawableHelper.java deleted file mode 100644 index 941ae039baa..00000000000 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyDrawableHelper.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.tencent.mtt.hippy.views.view; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.RippleDrawable; -import android.os.Build; - -import com.tencent.mtt.hippy.common.HippyMap; -import com.tencent.mtt.hippy.utils.PixelUtil; - -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; - -public class HippyDrawableHelper { - - @RequiresApi(api = Build.VERSION_CODES.M) - public static Drawable createDrawableFromJSDescription(Context context, HippyMap drawableDescriptionDict) { - RippleDrawable rd = null; - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - rd = getRippleDrawable(context, drawableDescriptionDict); - return setRadius(drawableDescriptionDict, rd); - } - return null; - } - - /** - * set radius of ripple - * @param drawableDescriptionDict - * @param drawable - * @return RippleDrawable - */ - public static Drawable setRadius(HippyMap drawableDescriptionDict, Drawable drawable) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M - && drawableDescriptionDict.containsKey("rippleRadius") - && drawable instanceof RippleDrawable) { - RippleDrawable rippleDrawable = (RippleDrawable) drawable; - double rippleRadius = drawableDescriptionDict.getDouble("rippleRadius"); - rippleDrawable.setRadius((int) PixelUtil.dp2px(rippleRadius)); - } - return drawable; - } - - /** - * get instance of RippleDrawable - * @param context - * @param drawableDescriptionDict - * @return RippleDrawable - */ - @RequiresApi(api = Build.VERSION_CODES.M) - private static RippleDrawable getRippleDrawable( - Context context, HippyMap drawableDescriptionDict) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { - int color = getColor(drawableDescriptionDict); - Drawable mask = getMask(drawableDescriptionDict); - ColorStateList colorStateList = - new ColorStateList(new int[][] { new int[]{} }, new int[] {color}); - - return new RippleDrawable(colorStateList, null, mask); - } - return null; - } - - /** - * color parser - * @param drawableDescriptionDict - * @return Color - */ - private static int getColor(HippyMap drawableDescriptionDict) { - if (drawableDescriptionDict.containsKey("color") - && !drawableDescriptionDict.isNull("color")) { - return drawableDescriptionDict.getInt("color"); - } - return Color.BLUE; - } - - /** - * set mask if borderless is null or false - * @param drawableDescriptionDict - * @return ColorDrawable - */ - private static @Nullable Drawable getMask(HippyMap drawableDescriptionDict) { - if (!drawableDescriptionDict.containsKey("borderless") - || drawableDescriptionDict.isNull("borderless") - || !drawableDescriptionDict.getBoolean("borderless")) - return new ColorDrawable(Color.WHITE); - - return null; - } -} diff --git a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyViewGroupController.java b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyViewGroupController.java index 70836830f20..e45f471b2ac 100644 --- a/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyViewGroupController.java +++ b/android/sdk/src/main/java/com/tencent/mtt/hippy/views/view/HippyViewGroupController.java @@ -13,8 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.tencent.mtt.hippy.views.view; +import static com.tencent.mtt.hippy.dom.node.NodeProps.BACKGROUND_RIPPLE; +import static com.tencent.mtt.hippy.uimanager.DrawableFactory.DrawableType.DRAWABLE_TYPE_RIPPLE; + import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Build; @@ -27,6 +31,7 @@ import com.tencent.mtt.hippy.common.HippyArray; import com.tencent.mtt.hippy.common.HippyMap; import com.tencent.mtt.hippy.dom.node.NodeProps; +import com.tencent.mtt.hippy.uimanager.DrawableFactory; import com.tencent.mtt.hippy.uimanager.HippyGroupController; import com.tencent.mtt.hippy.utils.LogUtils; import com.tencent.mtt.hippy.utils.PixelUtil; @@ -40,118 +45,102 @@ @HippyController(name = HippyViewGroupController.CLASS_NAME) public class HippyViewGroupController extends HippyGroupController { - public static final String CLASS_NAME = "View"; - - private static final String TAG = "HippyViewGroupController"; - - public static final WeakHashMap mZIndexHash = new WeakHashMap<>(); - - - public static void setViewZIndex(View view, int zIndex) { - mZIndexHash.put(view, zIndex); - } - - public static void removeViewZIndex(View view) { - mZIndexHash.remove(view); - } - - public static Integer getViewZIndex(View view) { - return mZIndexHash.get(view); - } - - @Override - protected View createViewImpl(Context context) { - return new HippyViewGroup(context); - } - - @HippyControllerProps(name = NodeProps.OVERFLOW, defaultType = HippyControllerProps.STRING, defaultString = "visible") - public void setOverflow(HippyViewGroup hippyViewGroup, String overflow) { - hippyViewGroup.setOverflow(overflow); - } - - @HippyControllerProps(name = NodeProps.BACKGROUND_IMAGE, defaultType = HippyControllerProps.STRING) - public void setBackgroundImage(HippyViewGroup hippyViewGroup, String url) { - hippyViewGroup.setUrl(getInnerPath((HippyInstanceContext)hippyViewGroup.getContext(), url)); - } - - @HippyControllerProps(name = NodeProps.BACKGROUND_SIZE, defaultType = HippyControllerProps.STRING, defaultString = "origin") - public void setBackgroundImageSize(HippyImageView hippyImageView, String resizeModeValue) { - if ("contain".equals(resizeModeValue)) { - // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都小于等于容器视图的尺寸 - // 这样图片完全被包裹在容器中,容器中可能留有空白 - hippyImageView.setScaleType(HippyImageView.ScaleType.CENTER_INSIDE); - } else if ("cover".equals(resizeModeValue)) { - // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都大于等于容器视图的尺寸 - // 这样图片完全覆盖甚至超出容器,容器中不留任何空白 - hippyImageView.setScaleType(HippyImageView.ScaleType.CENTER_CROP); - } else if ("center".equals(resizeModeValue)) { - // 居中不拉伸 - hippyImageView.setScaleType(HippyImageView.ScaleType.CENTER); - } else if ("origin".equals(resizeModeValue)) { - // 不拉伸,居左上 - hippyImageView.setScaleType(HippyImageView.ScaleType.ORIGIN); - } else { - // stretch and other mode - // 拉伸图片且不维持宽高比,直到宽高都刚好填满容器 - hippyImageView.setScaleType(HippyImageView.ScaleType.FIT_XY); + public static final String CLASS_NAME = "View"; + private static final String FUNC_SET_PRESSED = "setPressed"; + private static final String FUNC_SET_HOTSPOT = "setHotspot"; + private static final WeakHashMap mZIndexHash = new WeakHashMap<>(); + + public static void setViewZIndex(View view, int zIndex) { + mZIndexHash.put(view, zIndex); + } + + public static void removeViewZIndex(View view) { + mZIndexHash.remove(view); } - } - - @HippyControllerProps(name = NodeProps.BACKGROUND_POSITION_X, defaultType = HippyControllerProps.NUMBER) - public void setBackgroundImagePositionX(HippyViewGroup hippyViewGroup, int positionX) { - hippyViewGroup.setImagePositionX((int) PixelUtil.dp2px(positionX)); - } - - @HippyControllerProps(name = NodeProps.BACKGROUND_POSITION_Y, defaultType = HippyControllerProps.NUMBER) - public void setBackgroundImagePositionY(HippyViewGroup hippyViewGroup, int positionY) { - hippyViewGroup.setImagePositionY((int) PixelUtil.dp2px(positionY)); - } - - @RequiresApi(api = Build.VERSION_CODES.M) - @HippyControllerProps(name = "nativeBackgroundAndroid", defaultType = HippyControllerProps.MAP) - public void setNativeBackground(final HippyViewGroup hippyViewGroup, final HippyMap rippleConfig) { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { - Drawable rd = HippyDrawableHelper.createDrawableFromJSDescription(hippyViewGroup.getContext(), rippleConfig); - hippyViewGroup.setTranslucentBackgroundDrawable(rippleConfig.size() == 0 ? null : rd); + + public static Integer getViewZIndex(View view) { + return mZIndexHash.get(view); + } + + @Override + protected View createViewImpl(Context context) { + return new HippyViewGroup(context); + } + + @HippyControllerProps(name = NodeProps.OVERFLOW, defaultType = HippyControllerProps.STRING, defaultString = "visible") + public void setOverflow(HippyViewGroup hippyViewGroup, String overflow) { + hippyViewGroup.setOverflow(overflow); } - } - - @Override - public void dispatchFunction(HippyViewGroup view, String functionName, HippyArray params) { - super.dispatchFunction(view, functionName, params); - switch (functionName) { - case "setPressed": { - this.handleSetPressed(view, params); - break; - } - case "setHotspot": { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - this.handSetHotspot(view, params); + + @HippyControllerProps(name = NodeProps.BACKGROUND_IMAGE, defaultType = HippyControllerProps.STRING) + public void setBackgroundImage(HippyViewGroup hippyViewGroup, String url) { + hippyViewGroup + .setUrl(getInnerPath((HippyInstanceContext) hippyViewGroup.getContext(), url)); + } + + @HippyControllerProps(name = NodeProps.BACKGROUND_SIZE, defaultType = HippyControllerProps.STRING, defaultString = "origin") + public void setBackgroundImageSize(HippyImageView hippyImageView, String resizeModeValue) { + if ("contain".equals(resizeModeValue)) { + // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都小于等于容器视图的尺寸 + // 这样图片完全被包裹在容器中,容器中可能留有空白 + hippyImageView.setScaleType(HippyImageView.ScaleType.CENTER_INSIDE); + } else if ("cover".equals(resizeModeValue)) { + // 在保持图片宽高比的前提下缩放图片,直到宽度和高度都大于等于容器视图的尺寸 + // 这样图片完全覆盖甚至超出容器,容器中不留任何空白 + hippyImageView.setScaleType(HippyImageView.ScaleType.CENTER_CROP); + } else if ("center".equals(resizeModeValue)) { + // 居中不拉伸 + hippyImageView.setScaleType(HippyImageView.ScaleType.CENTER); + } else if ("origin".equals(resizeModeValue)) { + // 不拉伸,居左上 + hippyImageView.setScaleType(HippyImageView.ScaleType.ORIGIN); + } else { + // stretch and other mode + // 拉伸图片且不维持宽高比,直到宽高都刚好填满容器 + hippyImageView.setScaleType(HippyImageView.ScaleType.FIT_XY); } - break; - } - default: - break; } - } - public void handleSetPressed(HippyViewGroup view, HippyArray params) { - if (params == null || params.size() == 0) { - LogUtils.e(TAG, "Illegal number of arguments for 'setPressed' command"); - return; + @HippyControllerProps(name = NodeProps.BACKGROUND_POSITION_X, defaultType = HippyControllerProps.NUMBER) + public void setBackgroundImagePositionX(HippyViewGroup hippyViewGroup, int positionX) { + hippyViewGroup.setImagePositionX((int) PixelUtil.dp2px(positionX)); } - view.setPressed(params.getBoolean(0)); - } - - @RequiresApi(api = Build.VERSION_CODES.M) - public void handSetHotspot(HippyViewGroup view, HippyArray params) { - if (params == null || params.size() == 0) { - LogUtils.e(TAG, "Illegal number of arguments for 'setHotspot' command"); - return; + + @HippyControllerProps(name = NodeProps.BACKGROUND_POSITION_Y, defaultType = HippyControllerProps.NUMBER) + public void setBackgroundImagePositionY(HippyViewGroup hippyViewGroup, int positionY) { + hippyViewGroup.setImagePositionY((int) PixelUtil.dp2px(positionY)); } - float x = PixelUtil.dp2px(params.getDouble(0)); - float y = PixelUtil.dp2px(params.getDouble(1)); - view.drawableHotspotChanged(x, y); - } + @RequiresApi(api = Build.VERSION_CODES.M) + @HippyControllerProps(name = BACKGROUND_RIPPLE, defaultType = HippyControllerProps.MAP) + public void setNativeBackground(HippyViewGroup hippyViewGroup, HippyMap params) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && params.size() > 0) { + Drawable drawable = DrawableFactory.createDrawable(DRAWABLE_TYPE_RIPPLE, params); + if (drawable != null) { + hippyViewGroup.setRippleDrawable(drawable); + } + } + } + + @Override + public void dispatchFunction(HippyViewGroup viewGroup, String functionName, HippyArray params) { + super.dispatchFunction(viewGroup, functionName, params); + switch (functionName) { + case FUNC_SET_PRESSED: { + boolean pressed = params.getBoolean(0); + viewGroup.setPressed(pressed); + break; + } + case FUNC_SET_HOTSPOT: { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + double x = params.getDouble(0); + double y = params.getDouble(1); + viewGroup.drawableHotspotChanged(PixelUtil.dp2px(x), PixelUtil.dp2px(y)); + } + break; + } + default: + break; + } + } } diff --git a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/AsyncImageView.java b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/AsyncImageView.java index a197b5b183f..bf663fc2008 100644 --- a/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/AsyncImageView.java +++ b/android/sdk/src/main/java/com/tencent/mtt/supportui/views/asyncimage/AsyncImageView.java @@ -36,7 +36,7 @@ import android.view.ViewGroup; import java.util.ArrayList; -import androidx.annotation.Nullable; +import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; /** @@ -66,8 +66,7 @@ public class AsyncImageView extends ViewGroup implements Animator.AnimatorListen protected int mTintColor; protected ScaleType mScaleType; protected Drawable mContentDrawable; - - protected Drawable mRippleDrawable; + protected Drawable mRippleDrawable; private boolean mIsAttached; protected IImageLoaderAdapter mImageAdapter; @@ -229,10 +228,6 @@ public void setImagePositionY(int positionY) mImagePositionY = positionY; } - public void setRippleDrawable(Drawable mRippleDrawable) { - this.mRippleDrawable = mRippleDrawable; - } - protected void onFetchImage(String url) { @@ -458,54 +453,17 @@ protected Bitmap getBitmap() return null; } -protected void setContent(int sourceType) -{ - if (mContentDrawable != null) - { - if (!shouldSetContent()) - { - return; - } - - onSetContent(mUrl); - updateContentDrawableProperty(sourceType); - - setMultiLevelBackgroundDrawable(mBGDrawable, mContentDrawable, mRippleDrawable); - afterSetContent(mUrl); - } -} - - /** - * set multiple level background to avoid covering by each other - * @param mBGDrawable - * @param mContentDrawable - * @param mRippleDrawable - */ - protected void setMultiLevelBackgroundDrawable(BackgroundDrawable mBGDrawable, Drawable mContentDrawable, Drawable mRippleDrawable) { - if (mBGDrawable != null) - { - if (mContentDrawable instanceof ContentDrawable) - { - ((ContentDrawable) mContentDrawable).setBorder(mBGDrawable.getBorderRadiusArray(), mBGDrawable.getBorderWidthArray()); - ((ContentDrawable) mContentDrawable).setShadowOffsetX(mBGDrawable.getShadowOffsetX()); - ((ContentDrawable) mContentDrawable).setShadowOffsetY(mBGDrawable.getShadowOffsetY()); - ((ContentDrawable) mContentDrawable).setShadowRadius(mBGDrawable.getShadowRadius()); - } - if (mRippleDrawable != null) { - setBackgroundDrawable(new LayerDrawable(new Drawable[] { mBGDrawable, mContentDrawable, mRippleDrawable })); - } else { - setBackgroundDrawable(new LayerDrawable(new Drawable[] { mBGDrawable, mContentDrawable })); - } - } - else - { - if (mRippleDrawable != null) { - setBackgroundDrawable(new LayerDrawable(new Drawable[] { mContentDrawable, mRippleDrawable })); - } else { - setBackgroundDrawable(mContentDrawable); - } - } -} + protected void setContent(int sourceType) { + if (mContentDrawable != null) { + if (!shouldSetContent()) { + return; + } + onSetContent(mUrl); + updateContentDrawableProperty(sourceType); + resetBackgroundDrawable(); + afterSetContent(mUrl); + } + } protected void updateContentDrawableProperty(int sourceType) { if (!(mContentDrawable instanceof ContentDrawable)) { @@ -526,6 +484,17 @@ protected void updateContentDrawableProperty(int sourceType) { ((ContentDrawable) mContentDrawable).setImagePositionX(mImagePositionX); ((ContentDrawable) mContentDrawable).setImagePositionY(mImagePositionY); } + if (mBGDrawable != null) { + ((ContentDrawable) mContentDrawable) + .setBorder(mBGDrawable.getBorderRadiusArray(), + mBGDrawable.getBorderWidthArray()); + ((ContentDrawable) mContentDrawable) + .setShadowOffsetX(mBGDrawable.getShadowOffsetX()); + ((ContentDrawable) mContentDrawable) + .setShadowOffsetY(mBGDrawable.getShadowOffsetY()); + ((ContentDrawable) mContentDrawable) + .setShadowRadius(mBGDrawable.getShadowRadius()); + } } protected void handleGetImageStart() @@ -726,44 +695,33 @@ private BackgroundDrawable getBackGround() return mBGDrawable; } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public void setRippleDrawable(@NonNull Drawable rippleDrawable) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + mRippleDrawable = rippleDrawable; + resetBackgroundDrawable(); + } + } - @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) - public void setTranslucentBackgroundDrawable(@Nullable Drawable background) { - // it's required to call setBackground to null, as in some of the cases we may set new - // background to be a layer drawable that contains a drawable that has been setup - // as a background previously. This will not work correctly as the drawable callback logic is - // messed up in AOSP - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { - return; - } - updateBackgroundDrawable(null); - if (mContentDrawable != null && background != null) { - setMultiLevelBackgroundDrawable(mBGDrawable, mContentDrawable, background); - } else if (background != null) { - if (mBGDrawable != null) - { - // while mContentDrawable is null but mBGDrawable is not null - updateBackgroundDrawable(new LayerDrawable(new Drawable[] { mBGDrawable, background })); - } - else - { - updateBackgroundDrawable(background); // set ripple drawable - } - } - setRippleDrawable(background); // is used to avoid covering the ripple layer by setBackgroundImage - } - - /** - * Set the background for the view or remove the background. It calls {@link - * #setBackground(Drawable)} or {@link #setBackgroundDrawable(Drawable)} based on the sdk version. - * - * @param drawable {@link Drawable} The Drawable to use as the background, or null to remove the - * background - */ - @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) - private void updateBackgroundDrawable(Drawable drawable) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - super.setBackground(drawable); - } - } + private void resetBackgroundDrawable() { + ArrayList drawableList = new ArrayList<>(); + if (mBGDrawable != null) { + drawableList.add(mBGDrawable); + } + if (mContentDrawable != null) { + drawableList.add(mContentDrawable); + } + if (mRippleDrawable != null) { + drawableList.add(mRippleDrawable); + } + if (drawableList.size() > 0) { + super.setBackground(null); + Drawable[] drawables = new Drawable[drawableList.size()]; + for (int i = 0; i < drawableList.size(); i++) { + drawables[i] = drawableList.get(i); + } + LayerDrawable layerDrawable = new LayerDrawable(drawables); + super.setBackground(layerDrawable); + } + } }