package com.bilibili.magicasakura.utils; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; import android.os.Build; import android.util.AttributeSet; import com.bilibili.magicasakura.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author xyczero617@gmail.com * @time 16/11/6 */ public class RippleDrawableInflateImpl extends LayerDrawableInflateImpl { private static Method sAddLayer; private static Method sEnsurePadding; @Override public Drawable inflateDrawable(Context context, XmlPullParser parser, AttributeSet attrs) throws IOException, XmlPullParserException { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { final int innerDepth = parser.getDepth() + 1; int type; int depth; int markIndex = -1; int layerAttrUseCount = 0; int drawableUseCount = 0; int space = STEP; //L,T,R,B,S,E,id int[][] childLayersAttrs = new int[space][ATTRS.length]; Drawable[] drawables = new Drawable[space]; ColorStateList csl = DrawableUtils.getTintColorList(context, attrs, android.R.attr.color); if (csl == null) { return null; } while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) { if (type != XmlPullParser.START_TAG) { continue; } if (depth > innerDepth || !parser.getName().equals("item")) { continue; } if (layerAttrUseCount >= childLayersAttrs.length) { int[][] dstInt = new int[drawables.length + STEP][ATTRS.length]; System.arraycopy(childLayersAttrs, 0, dstInt, 0, childLayersAttrs.length); childLayersAttrs = dstInt; } updateLayerAttrs(context, attrs, childLayersAttrs[layerAttrUseCount]); layerAttrUseCount++; Drawable drawable = DrawableUtils.getAttrDrawable(context, attrs, android.R.attr.drawable); if (DrawableUtils.getAttrResourceId(context, attrs, android.R.attr.id, 0) == android.R.id.mask) { markIndex = layerAttrUseCount - 1; } // If the layer doesn't have a drawable or unresolved theme // attribute for a drawable, attempt to parse one from the child // element. if (drawable == null) { while ((type = parser.next()) == XmlPullParser.TEXT) { } if (type != XmlPullParser.START_TAG) { throw new XmlPullParserException(parser.getPositionDescription() + ": <item> tag requires a 'drawable' attribute or " + "child tag defining a drawable"); } drawable = DrawableUtils.createFromXmlInner(context, parser, attrs); } else { final ColorStateList cls = DrawableUtils.getTintColorList(context, attrs, R.attr.drawableTint); if (cls != null) { drawable = ThemeUtils.tintDrawable(drawable, cls, DrawableUtils.getTintMode(context, attrs, R.attr.drawableTintMode)); } } if (drawable != null) { if (drawableUseCount >= drawables.length) { Drawable[] dst = new Drawable[drawables.length + STEP]; System.arraycopy(drawables, 0, dst, 0, drawables.length); drawables = dst; } drawables[drawableUseCount] = drawable; drawableUseCount++; } } if (drawables[0] == null || drawableUseCount != layerAttrUseCount) { return null; } else { RippleDrawable rippleDrawable; rippleDrawable = new RippleDrawable(csl, null, markIndex >= 0 ? drawables[markIndex] : null); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { int radius = DrawableUtils.getAttrDimensionPixelSize(context, attrs, android.R.attr.radius, RippleDrawable.RADIUS_AUTO); rippleDrawable.setRadius(radius); } for (int i = 0; i < drawables.length; i++) { if (i == markIndex) { continue; } addLayer(rippleDrawable, drawables[i]); int[] childLayersAttr = childLayersAttrs[i]; if (childLayersAttr[0] != 0 || childLayersAttr[1] != 0 || childLayersAttr[2] != 0 || childLayersAttr[3] != 0) { rippleDrawable.setLayerInset(i, childLayersAttr[0], childLayersAttr[1], childLayersAttr[2], childLayersAttr[3]); } if (childLayersAttr[4] != 0) { rippleDrawable.setId(i, childLayersAttr[4]); } } return rippleDrawable; } } return null; } private void addLayer(RippleDrawable rippleDrawable, Drawable drawable) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { rippleDrawable.addLayer(drawable); } else { try { if (sAddLayer == null) { sAddLayer = Class.forName("android.graphics.drawable.LayerDrawable") .getDeclaredMethod("addLayer", Drawable.class, int[].class, int.class, int.class, int.class, int.class, int.class); sAddLayer.setAccessible(true); } sAddLayer.invoke(rippleDrawable, drawable, null, 0, 0, 0, 0, 0); if (sEnsurePadding == null) { sEnsurePadding = Class.forName("android.graphics.drawable.LayerDrawable").getDeclaredMethod("ensurePadding"); sEnsurePadding.setAccessible(true); } sEnsurePadding.invoke(rippleDrawable); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } }