不使用属性动画,通过反射设置Vector的属性

最近看到一篇文章介绍Vector兼容方案的。参考http://www.jianshu.com/p/e3614e7abc03

尝试写了下Demo感觉还不错,但是遇到一个问题,需要Vector的颜色需要动态调整,前面的文章里通过属性动画一步步是可以实现这个效果的,但我只是改个颜色又是要写xml又是要用动画,这有点大炮打蚊子了,而且动画持续时间设置多少算合适?属性动画肯定不是优雅的解决方案。属性动画无非就是反射,既然属性动画能修改的,那我们自己通过反射肯定也是可以修改的。
这篇文章就是介绍下如何避免使用属性动画,来修改VectorDrawable的属性。其实整个过程就是查找需要反射的属性路径的过程,只要知道什么是反射,基本没什么难度。

既然是反射,那怎么反射呢?既然有源码,跟进源码看看AnimatedVectorDrawable具体是如何操作的。

<code>
Drawable drawable = imageView.getDrawable();
if (drawable instanceof Animatable) {
((Animatable) drawable).start();
}
</code>

上面是前面文章给的开启Vector动画的代码。我们跟进start看看。很不幸是个接口。这时候怎么办?直接debug watch drawable的真实类,或者打印日志drawable.getClass().toString()看下真实的类。

Paste_Image.png

这里debug看到drawable其实是一个AnimatedVectorDrawable(注意这里Api21以前是兼容包的类,这里因为我的手机是6.0所以这里是AnimatedVectorDrawable,其实原理完全一样);
跟进AnimatedVectorDrawable的start方法
<code>
@Override
public void start() {
ensureAnimatorSet();
// If any one of the animator has not ended, do nothing.
if (isStarted()) {
return;
}
mAnimatorSet.start();
invalidateSelf();
}
</code>
东西全出来了。看见mAnimatorSet.start();写过属性动画,应该会非常熟悉。跟进ensureAnimatorSet方法
<code>
private void ensureAnimatorSet() {
if (!mHasAnimatorSet) {
mAnimatedVectorState.prepareLocalAnimators(mAnimatorSet, mRes);
mHasAnimatorSet = true;
mRes = null;
}
}
</code>
没什么好想的,继续跟进prepareLocalAnimators方法,
<code>
public void prepareLocalAnimators(@NonNull AnimatorSet animatorSet,
@Nullable Resources res) {
// Check for uninflated animators. We can remove this after we add
// support for Animator.applyTheme(). See comments in inflate().
if (mPendingAnims != null) {
// Attempt to load animators without applying a theme.
if (res != null) {
inflatePendingAnimators(res, null);
} else {
Log.e(LOGTAG, "Failed to load animators. Either the AnimatedVectorDrawable" + " must be created using a Resources object or applyTheme() must be" + " called with a non-null Theme object.");
}
mPendingAnims = null;
}
// Perform a deep copy of the constant state's animators.
final int count = mAnimators == null ? 0 : mAnimators.size();
if (count > 0) {
final Animator firstAnim = prepareLocalAnimator(0);
final AnimatorSet.Builder builder = animatorSet.play(firstAnim);
for (int i = 1; i < count; ++i) {
final Animator nextAnim = prepareLocalAnimator(i);
builder.with(nextAnim);
}
}
}
</code>
这时候如果眼睛亮的话,应该会直接看见这一行
<code>
final Animator firstAnim = prepareLocalAnimator(0);
</code>
prepareLocalAnimator这里返回了一个Animator,跟进prepareLocalAnimator方法。
<code>
private Animator prepareLocalAnimator(int index) {
final Animator animator = mAnimators.get(index);
final Animator localAnimator = animator.clone();
final String targetName = mTargetNameMap.get(animator);
final Object target = mVectorDrawable.getTargetByName(targetName);
localAnimator.setTarget(target);
return localAnimator;
}
</code>
一下子就豁然开朗了,
<code>
final Object target = mVectorDrawable.getTargetByName(targetName);
</code>
这一行IDE报了红线,表示这个方法不可访问。VectorDrawable里其实有这个方法
<code>
Object getTargetByName(String name) {
return mVectorState.mVPathRenderer.mVGTargetsMap.get(name);
}
</code>
好多层。我们跟到mVGTargetsMap那里看看那里有什么。可惜的是这个Map保存是Object类型,这时候我们可以继续debug watch这个Map查看里面的Object的运行时的实际类型,不过向下扫一眼看到了mVGTargetsMap所在的类叫VPathRenderer,这个类的构造方法是这个:
<code>
public VPathRenderer(VPathRenderer copy) {
mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
mPath = new Path(copy.mPath);
mRenderPath = new Path(copy.mRenderPath);
mBaseWidth = copy.mBaseWidth;
mBaseHeight = copy.mBaseHeight;
mViewportWidth = copy.mViewportWidth;
mViewportHeight = copy.mViewportHeight;
mOpticalInsets = copy.mOpticalInsets;
mChangingConfigurations = copy.mChangingConfigurations;
mRootAlpha = copy.mRootAlpha;
mRootName = copy.mRootName;
mTargetDensity = copy.mTargetDensity;
if (copy.mRootName != null) {
mVGTargetsMap.put(copy.mRootName, this);
}
}
</code>
倒数第三行put了this,这表示返回的target其实就是当前类。当前类保存在Map里,然后Map会通过
<code>
Object getTargetByName(String name) {
return mVectorState.mVPathRenderer.mVGTargetsMap.get(name);
}
</code>
返回作为Animator的tartget,这时候想到了什么?属性动画原理就是反射getset,那这个类非常可能就有mFillColor属性或者setFillColor方法。command+F12输入setfil

Paste_Image.png

好吧,终于发现你了。
<code>
@SuppressWarnings("unused")
void setFillColor(int fillColor) {
mFillColor = fillColor;
}
</code>
其实不光是fillColor其他的属性也全部都有。
<code>
int mStrokeColor = Color.TRANSPARENT;
float mStrokeWidth = 0;
int mFillColor = Color.TRANSPARENT;
float mStrokeAlpha = 1.0f;
int mFillRule;
float mFillAlpha = 1.0f;
float mTrimPathStart = 0;
float mTrimPathEnd = 1;
float mTrimPathOffset = 0;
Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
Paint.Join mStrokeLineJoin = Paint.Join.MITER;
float mStrokeMiterlimit = 4;
</code>
到这里剩下的应该就不用说了,思路基本已经有了,剩下的就简单了,无非就是敲键盘了。如果你不想敲也可以参考这里:
https://github.com/aesean/VectorHelper/blob/master/VectorHelper
保留作者,保留原始链接后,欢迎转载。原始链接:http://www.jianshu.com/p/2db6a5ce871b

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 1 背景 不能只分析源码呀,分析的同时也要整理归纳基础知识,刚好有人微博私信让全面说说Android的动画,所以今...
    未聞椛洺阅读 2,705评论 0 10
  • 属性动画的集成关系Paste_Image.png 看一段属性动画的使用代码 跟进ObjectAnimator.of...
    明朗__阅读 7,384评论 0 2
  • Animation Animation类是所有动画(scale、alpha、translate、rotate)的基...
    四月一号阅读 1,915评论 0 10
  • 学习力这东西也真的需要灵感!除了日常生活中已经习惯的各种学习力,想创新,还得要宝宝接受,真的很不容易! 今天么,宝...
    幽香_5126阅读 160评论 0 0
  • 济宁的天气很灿烂 早上搭载顺风车 沿途的春光很美 路过太白湖的时候觉得有时间的话到此一游还是极好的 …… 不过比欣...
    金澜爱写作阅读 144评论 0 0