Android 动态设置Shape
来源:互联网 发布:wnba赛果数据 编辑:程序博客网 时间:2024/04/28 00:15
引言:之前涉及到设置view背景的地方几乎都是通过写<shape>
标签的方式实现的。慢慢的,项目里的xml越来越多,命名都成问题了!于是就想用动态设置shape的方式来替换静态配置shape标签。
静态配置shape
这个不多说了,梯子备好了,自行前往!
https://developer.android.google.cn/guide/topics/resources/drawable-resource.html#Shape
里面有非常详细的介绍。包括shape 等标签参数介绍、使用规则、映射的Drawaable。
这里对形状可绘制对象的描述感觉有点出入,写的是创建ShapeDrawable,但是进入对应的条目后发现是GradientDrawable.
动态设置shape
想要动态配置,首先需要知道在xml中写的<shape>
,<selector>
,<level-list>
等标签的映射对象是什么。这里有个插曲,最开始我也以为<shape>
标签对应的就是ShapeDrawable呢,写的时候发现没法描边(Stroke), 试了两种方案 1.通过设置描边画笔,给paint设置宽度和颜色;2.用LevelListDrawable 通过设置多个层一个填充层,一个描边层来组合。结果这两种方法都不行,后来才去翻的源码。从view.setBackgroundResource()开始追。
Resources.java
public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme) throws NotFoundException { final TypedValue value = obtainTempTypedValue(); try { final ResourcesImpl impl = mResourcesImpl; impl.getValue(id, value, true); // 从这里开始加载Drawable return impl.loadDrawable(this, value, id, theme, true); } finally { releaseTempTypedValue(value); } }
ResourcesImpl.java
@Nullable Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme, boolean useCache) throws NotFoundException { try { ...... final Drawable.ConstantState cs; if (isColorDrawable) { cs = sPreloadedColorDrawables.get(key); } else { cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key); } Drawable dr; if (cs != null) { dr = cs.newDrawable(wrapper); } else if (isColorDrawable) { dr = new ColorDrawable(value.data); } else { // 从xml或者资源流中加载Drawable dr = loadDrawableForCookie(wrapper, value, id, null); } return dr; } catch (Exception e) { ...... } }
/** * Loads a drawable from XML or resources stream. * 从xml或者数据流中加载Drawable */ private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id, Resources.Theme theme) { final String file = value.string.toString(); ...... final Drawable dr; Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file); try { if (file.endsWith(".xml")) { // ok,我们看下这里,通过解析器把xml文件解析成Drawable对象 final XmlResourceParser rp = loadXmlResourceParser( file, id, value.assetCookie, "drawable"); dr = Drawable.createFromXml(wrapper, rp, theme); rp.close(); } else { // 流的解析 final InputStream is = mAssets.openNonAsset( value.assetCookie, file, AssetManager.ACCESS_STREAMING); dr = Drawable.createFromResourceStream(wrapper, value, is, file, null); is.close(); } } catch (Exception e) { ...... } Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); return dr; }
Drawable.java
// 使用可选的theme从XML文档中创建drawable对象。 public static Drawable createFromXml(Resources r, XmlPullParser parser, Theme theme) throws XmlPullParserException, IOException { AttributeSet attrs = Xml.asAttributeSet(parser); ...... // 从xml内部以指定主题创建一个Drawable对象 Drawable drawable = createFromXmlInner(r, parser, attrs, theme); if (drawable == null) { throw new RuntimeException("Unknown initial tag: " + parser.getName()); } return drawable; }
// 从xml内部以指定主题创建一个Drawable对象 public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { return r.getDrawableInflater().inflateFromXml(parser.getName(), parser, attrs, theme); }
追到这里发现是从Resources 中调用了一个方法。在Resources.java 中搜索getDrawableInflater()这个方法,出现了DrawableInflater这个类。
Resources.java
// 该inflater用于创建Drawable对象 public final DrawableInflater getDrawableInflater() { if (mDrawableInflater == null) { mDrawableInflater = new DrawableInflater(this, mClassLoader); } return mDrawableInflater; }
没法直接追下去了,既然这样我们在源码中直接搜索DrawableInflater.java这个类,然后查看它里面的inflateFromXml() 方法。(注:我这里的源码版本是android-25)
DrawableInflater.java
@NonNull @SuppressWarnings("deprecation") private Drawable inflateFromTag(@NonNull String name) { switch (name) { case "selector": return new StateListDrawable(); case "animated-selector": return new AnimatedStateListDrawable(); case "level-list": return new LevelListDrawable(); case "layer-list": return new LayerDrawable(); case "transition": return new TransitionDrawable(); case "ripple": return new RippleDrawable(); case "color": return new ColorDrawable(); case "shape": return new GradientDrawable(); case "vector": return new VectorDrawable(); case "animated-vector": return new AnimatedVectorDrawable(); case "scale": return new ScaleDrawable(); case "clip": return new ClipDrawable(); case "rotate": return new RotateDrawable(); case "animated-rotate": return new AnimatedRotateDrawable(); case "animation-list": return new AnimationDrawable(); case "inset": return new InsetDrawable(); case "bitmap": return new BitmapDrawable(); case "nine-patch": return new NinePatchDrawable(); default: return null; } }
到这里总该明白与xml中的标签(shape等标签)相对应的对象是哪些了吧。项目中用的最多的就是圆角矩形背景了,然后有的会有描边,还有选择器的效果。我们就用GradientDrawable 来实现。GradientDrawable可以用来设置shape类型、shape填充色、描边色和矩形的边角弧度。
动态设置shape代码
以圆角矩形为例:
/** * 获得一个指定填充色,边框宽度、颜色的圆角矩形drawable。 * Android 中 在xml中写的"shape"标签映射对象就是GradientDrawable。 * 通过设置solidColors 和strokeColors 可实现选择器的效果 * * @param solidColors 填充色 * @param strokeColors 描边色 * @param strokeWidth 描边线宽度 * @param dashWidth 虚线(破折线)的长度(以像素为单位) * @param dashGap 虚线(破折线)间距,当dashGap=0dp时,为实线 * @param radius 圆角角度 * @return GradientDrawable */ public static Drawable getShapeDrawable(ColorStateList solidColors, ColorStateList strokeColors, int strokeWidth, float dashWidth, float dashGap, float radius) { GradientDrawable gradientDrawable = new GradientDrawable(); gradientDrawable.setShape(GradientDrawable.RECTANGLE); gradientDrawable.setCornerRadius(radius); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { gradientDrawable.setColor(solidColors); //显示一条虚线,破折线的宽度为dashWith,破折线之间的空隙的宽度为dashGap,当dashGap=0dp时,为实线 gradientDrawable.setStroke(strokeWidth, strokeColors, dashWidth, dashGap); } else { gradientDrawable.setColor(solidColors.getDefaultColor()); //显示一条虚线,破折线的宽度为dashWith,破折线之间的空隙的宽度为dashGap,当dashGap=0dp时,为实线 gradientDrawable.setStroke(strokeWidth, strokeColors.getDefaultColor(), dashWidth, dashGap); } return gradientDrawable; } /** * 获得一个指定填充色,指定描边色的圆角矩形drawable * * @param solidColor 填充色 * @param strokeColor 描边色 * @param strokeWidth 描边线宽度 * @param dashWidth 虚线(破折线)宽度 * @param dashGap 虚线(破折线)间距,当dashGap=0dp时,为实线 * @param radius 圆角角度 * @return GradientDrawable */ public static Drawable getShapeDrawable(@ColorInt int solidColor, @ColorInt int strokeColor, int strokeWidth, float dashWidth, float dashGap, float radius) { return getShapeDrawable(ColorStateList.valueOf(solidColor), ColorStateList.valueOf(strokeColor), strokeWidth, dashWidth, dashGap, radius); } /** * 获得一个选择器Drawable. * Android 中 在xml中写的"selector"标签映射对象就是StateListDrawable 对象 * * @param defaultDrawable 默认时显示的Drawable * @param pressedDrawable 按下时显示的Drawable * @return 选择器Drawable */ public static StateListDrawable getSelectorDrawable(Drawable defaultDrawable, Drawable pressedDrawable) { if (defaultDrawable == null) return null; if (pressedDrawable == null) pressedDrawable = defaultDrawable; int[][] state = {{-android.R.attr.state_pressed}, {android.R.attr.state_pressed}}; StateListDrawable stateListDrawable = new StateListDrawable(); stateListDrawable.addState(state[0], defaultDrawable); stateListDrawable.addState(state[1], pressedDrawable); return stateListDrawable; } /** * 获得一个选择器Drawable. * Android 中 在xml中写的"selector"标签映射对象就是StateListDrawable 对象 * * @param defaultColor 默认时显示的颜色 * @param pressedColor 按下时显示的颜色 * @return 选择器Drawable */ public static StateListDrawable getSelectorDrawable(int defaultColor, int pressedColor, float radius) { Drawable defaultDrawable = getSolidShapeDrawable(defaultColor, radius); Drawable pressedDrawable = getSolidShapeDrawable(pressedColor, radius); return getSelectorDrawable(defaultDrawable, pressedDrawable); }
更多功能参考Drawable工具类:http://blog.csdn.net/JM_beizi/article/details/77433558
- Android动态设置Shape
- Android 动态设置Shape
- shape 动态颜色设置
- Android 动态修改shape
- android 设置shape不起作用
- Android 设置bitmap、selector、shape
- Android 怎么动态设置shape定义的控件的背景色
- 动态修改shape颜色值 android开发
- Android 代码中动态改变Shape
- Android使用Shape进行渐变设置
- android shape 常用到属性的设置
- Android代码设置Shape,corners,Gradient
- Android代码设置Shape,corners,Gradient
- android shape corners 设置无效的解决
- android使用shape设置下边框
- Android代码设置Shape渐变色
- android-shape设置圆角方法
- Android代码设置Shape,corners,Gradient
- 决策树的特性及优缺点
- Python3之进程、线程
- 线性可分SVM与硬间隔最大化
- Tomcat和SpringMVC结果梳理和请求处理流程小结
- pthon连接mysql和sqlserver
- Android 动态设置Shape
- 在服务器上设置mongodb分片集群开机自启动
- C和指针习题4.14.1
- IO多路复用机制
- Mac 上的 MySQL 管理工具 -- Sequel Pro
- Centos更换yum源
- 农民网红“大米哥”的中医养生观
- (斐波那契数列博弈)取石子游戏--HDOJ
- 杂项