Android - VectorDrawable

之前官方VectorDrawable只支持api 21以上,前不久android support libriry 23.2.0出来了,VectorDrawable终于可以向下兼容了。相比之前图片来说,矢量图可以解决不同尺寸手机图片失真问题,可以不用多套图片去适配不同尺寸手机,还可以减少apk体积.官方的icon全都提供svg的版本:material design icon

注意:矢量图形的初始加载可能花费比一般图像占用更多的CPU。之后内存使用和性能两者之间相似。官方建议矢量图像不要超过200×200dp.

使用很简单,下面提供几种svg转xml的方法:

直接在ImageView引用drawable即可:

1
2
3
4
5
6
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_share_black_24px"
/>
iv.setImageResource(R.drawable.ic_share_black_24px);

代码中使用:

1
iv.setImageResource(R.drawable.ic_share_black_24px);

一直好奇官方怎么向下兼容一些控件的,今天跟踪了下源码看看怎么兼容VerctorDrawable:
定位到:AppCompatImageView.java

public AppCompatImageView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(TintContextWrapper.wrap(context), attrs, defStyleAttr);

    final AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();

    mBackgroundTintHelper = new AppCompatBackgroundHelper(this, drawableManager);
    mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);

    mImageHelper = new AppCompatImageHelper(this, drawableManager);
    mImageHelper.loadFromAttributes(attrs, defStyleAttr);
}

@Override
public void setImageResource(@DrawableRes int resId) {
    // Intercept this call and instead retrieve the Drawable via the image helper
    mImageHelper.setImageResource(resId);
}

再看AppCompatImageHelper.java 的loadFromAttributes()

public void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
    TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
            R.styleable.AppCompatImageView, defStyleAttr, 0);
    try {

        Drawable d = a.getDrawableIfKnown(R.styleable.AppCompatImageView_android_src);
        if (d != null) {
            mView.setImageDrawable(d);
        }
        //AppCompatImageView 继承ImageView, 比ImageView多 app:srcCompat属性
        final int id = a.getResourceId(R.styleable.AppCompatImageView_srcCompat, -1);
        if (id != -1) {
            d = mDrawableManager.getDrawable(mView.getContext(), id);
            if (d != null) {
                mView.setImageDrawable(d);
            }
        }

        final Drawable drawable = mView.getDrawable();
        if (drawable != null) {
            DrawableUtils.fixDrawable(drawable);
        }
    } finally {
        a.recycle();
    }
}

AppCompatViewInflater.java 的 final View createView():

 View view = null;
// We need to 'inject' our tint aware Views in place of the standard framework versions
switch (name) {
    case "TextView":
        view = new AppCompatTextView(context, attrs);
        break;
    case "ImageView":
        view = new AppCompatImageView(context, attrs);
        break;
    case "Button":
        view = new AppCompatButton(context, attrs);
        break;

看到这里似乎懂了,低版本的布局文件里的ImageView会主动转成AppCompatImageView,
最后由AppCompatImageHelper处理兼容性问题.

更多内容参考:

Loading comments box needs to over the wall