android 中vector的用法

随着android L的发布,带来了VectorDrawable,矢量图的支持
矢量图在很久很久以前就已经应用起来了,是一种基于xml的图像,因为图片不提供具体的像素,只提供的是绘图的指令,所以好处是 占用内存非常小,性能高,可以任意缩放而不会失真,但是缺点也很明显,没有位图表达的色彩丰富。 
然而现在app风格越来越扁平, 拟物化已经成了过去,矢量图成了越来越多人的选择。

android在最新的支持包中,已经加入了向下兼容的库:VectorDrawableCompat和AnimatedDrawableCompat。今天我就围绕这个上代码,让未上车的猿们抓紧时间上车。
首先,去哪找合适的矢量图: 
阿里巴巴UX矢量库 传送门

找到你需要的图标,并下载svg

 
在android中打开vector assert

点击Local SVG 选择路径,并命名drawable文件名字

就在drawable目录生成了如下图

ok, 一张可以任意缩放的图片有了。 
接着看怎么引用, 
先讲解一下, android L 以后矢量图是以vectorDrawable的形式来使用了, 但是这个库只支持L以后的,于是谷歌出了一个兼容包: 
VectorDrawableCompat,AnimatedVectorDrawableCompat

As you may have seen on the Support Lib 23.2.0 blog post, we now have compatible vector drawable implementations in the support libraries: VectorDrawableCompat and Animated VectorDrawableCompat.

意思是说 在appcompat 23.2.0开始,提供了以上两种支持库一个用于兼容矢量图,但是这个支持库要使用的话,还得在app的gradle里面加个这样的配置:

//在gradle2.0及以上:
android {
  defaultConfig {
  vectorDrawables.useSupportLibrary = true
}}
//在gradle 1.5以前
android {
  defaultConfig {
    // Stops the Gradle plugin’s automatic rasterization of vectors
    generatedDensities = []
  }
  // Flag to tell aapt to keep the attribute ids around
  aaptOptions {
    additionalParameters "--no-version-vectors"
  }
}
ok , 配置完毕,下一步是怎么使用

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >

   <android.support.v7.widget.AppCompatImageView
       android:layout_width="42dp"
       android:layout_height="42dp"
       app:srcCompat="@drawable/icon_shopping"/>
</LinearLayout>
ok , 可以使用,试着改变下图标大小,会发现,完全一样,没有一点模糊 。 


这里要说到,这种的局限性: 
1.只能用于AppCompatImageView或者AppCompatImageButton或其子类,而且必须在app:srcCompat标签中,额,那我要用在TextView,Button上怎么办?我试试:

<android.support.v7.widget.AppCompatTextView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_marginTop="10dp"
       android:drawableLeft="@drawable/icon_shopping"
       android:text="我想要小图标"/>
 Caused by: android.content.res.Resources$NotFoundException: 
File res/drawable/icon_shopping.xml from drawable resource ID #0x7f02004d
                                                                              at android.content.res.Resources.loadDrawable(Resources.java:2101)
                                                                              at android.content.res.TypedArray.getDrawable(TypedArray.java:602)
                                                                              at android.widget.TextView.<init>(TextView.java:806)
                                                                              at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:60)
                                                                              at android.support.v7.widget.AppCompatTextView.<init>(AppCompatTextView.java:56)
嗯,除了一大堆错误,没有别的效果, 怎么办?

You don’t have to use StateListDrawable. It also works with InsetDrawable, LayerDrawable, LevelListDrawable and RotateDrawable containers. The only rule is that the vector needs to be in a separate file.

在android官方推文中找到这句话 , 意味着,我们要在普通控件上使用Vector,就必须依附于StateListDrawable,InsetDrawable,LayerDrawable,LevelListDrawable,RotateDrawable,所以我来试试?

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/icon_shopping"/>
</selector>


 <TextView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_marginTop="10dp"
       android:drawableLeft="@drawable/shopping_res"
       android:text="我想要小图标"/>
结果,相信有些哥们也尝试到这里了, 仍然是一大堆的错误。。。嗯,不是说包在那几个drawable里面就可以用了吗?忽悠人?这个帖子就此结束? 
不不不。

First up, this functionality was originally released in 23.2.0, but then we found some memory usage and Configuration updating issues so we it removed in 23.3.0. In 23.4.0 (technically a fix release)* we’ve re-added the same functionality but behind a flag which you need to manually enable.*

我英文不太好, 应该是说,在23.2.0中放出了这个功能,但是后来发现了一些bug ,在23.3.0里面又移除了,后来在23.4.0中修复这些bug , 但是我们没有默认开启了,你需要通过一个标志来启用,呵呵哒。。这就是报错的原因了。。

If you want re-enable this, just stick this at the top of your Activity:

static {
  AppCompatDelegate.setCompatVectorFromSourcesEnabled(true);
}
嗯,这句话简单, 就是说,你要想再用上, 就在你的activity里面加上这句来启用vector , 
结果怎样呢?

ok ~问题解决。嗯,到了这一步,我们已经可以自由的使用矢量图标了呢, 
那怎么改变图标颜色呢?这个我要说声抱歉,我还没有想在xml里面设置图标背景的方法, 有人会说drawableTint,这个可以,但是只支持api23以上,嗯,所以: 
1.对于vector,我只想到了在xml里面改变fillColor来改变颜色,但这样就不好了,几个颜色就要几个图片, 
2.可以用代码在合适的位置设置:

 VectorDrawableCompat a = VectorDrawableCompat.create(getResources(), R.drawable.icon_shopping, getTheme());
        a.setTint(Color.RED); //设置单一的颜色
        a.setTintList(ColorStateList.valueOf(Color.RED));//设置状态性的,比如点击一个颜色,未点击一个颜色 
DrawableCompat.setTint(a,Color.RED); //用这个v4提供的也可,这个适用于任意的drawable着色
3.可以在AnimatedVectorDrawable中用动画来改变vector的颜色 , 

前面所说的这个矢量图只能用在AppcomatImageView,AppcompatImageButton, 
但实际上,用ImageView,ImageButton加上app:srcCompat也行, 为什么?因为你用了appcomat后,它会自动的把你的一部分控件转成AppCompatXxx的控件。

总结一下,这个矢量图的缺点吧:

1.麻烦, 需要下载->vector asset转换->用在非imageview中还要再写一个xml包裹起来才可用
2.不能随心所欲的在xml布局中任意切换图标颜色 , 如果在vector的xml里面改fillcolor,则这个图标就不好复用了。我的意思则是一处创建,随意使用。
3.支持库正在更新的过程中, 可能出现各种各样bug,也可能出现前面改动api实现而掉坑的情况。
那怎么办?怎么办? 
前面介绍的 :

阿里巴巴UX矢量库 传送门

对,就是它。后面要介绍的

iconfont

它的原理是,把你想要的矢量图标打包成一个ttf,在android中应用这个ttf,就可以随心所欲了,怎么个随心所欲? 
用TextView的setText设置图标, setTextSize设置大小, 用TextColor设置图标颜色 ,只要能显示String的控件,都可以用,这样说来如何 ?

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >

   <android.support.v7.widget.AppCompatImageView
       android:layout_width="42dp"
       android:layout_height="42dp"
       app:srcCompat="@drawable/icon_shopping"/>

   <android.support.v7.widget.AppCompatTextView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_marginTop="10dp"
       android:drawableLeft="@drawable/shopping_res"
       android:text="我想要小图标"/>

   <com.example.liufan.demo1.IconfontView
       android:layout_width="wrap_content"
       android:layout_marginTop="10dp"
       android:textSize="60sp"
       android:textColor="#f00"
       android:text=""
       android:layout_height="wrap_content" />
</LinearLayout>


这个IconfontView,是继承自TextView,在初始化的时候加载了字体而已, 
& # xe725; 这个是上图图标的代码。 
嗯,这个并不算是什么高科技, 只是一个字体而已, 我就不长篇大论了, 下面贴出获取的流程吧,图从官网拿的:

 
选中一堆需要的图标并加入购物车, 然后再这里点下载到本地,

 
其中iconfont.ttf就是我们需要的字体了, 其他的那些在web上用的, 可以忽略。把[* .ttf, .eot, .svg , *.woff]复制到项目中assets中,然后,

public class IconfontView extends TextView {

    private static Typeface __cachedTypeFace = null;

    public IconfontView(Context context) {
        super(context);
        initFont();
    }

    public IconfontView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initFont();
    }

    public IconfontView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initFont();
    }

    private void initFont() {
        if (__cachedTypeFace == null) {
            final Typeface iconfont = Typeface.createFromAsset(getContext().getAssets(), "iconfont/iconfont.ttf");
            __cachedTypeFace = iconfont;
        }
        setTypeface(__cachedTypeFace);
    }
}
这里就是初始化的时候指定一下字体 , 这个iconfont什么的, 这个我由于写的是demo就写死的, 这里可以自定义一个属性,用来指定具体要用的字体 。

ok , 现在打开解压目录的demo.html

每个图标下的& #xe000就是这个图标的代码, 可以在IconfontView的text中设置了, 看下效果,


    <com.example.liufan.demo1.IconfontView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="&#xe60b;"
        android:textColor="#f00"
        android:textSize="200sp" />

    <com.example.liufan.demo1.IconfontView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="&#xe60b;"
        android:textColor="#f0f"
        android:textSize="200sp" />

假设你有一个 C++ 的 `std::vector` 对象,你可以使用 JNI 将其转换为 Java 的 `ArrayList` 对象。 下面是一个示例代码: ```c++ #include <jni.h> #include <vector> extern "C" JNIEXPORT jobject JNICALL Java_com_example_MyClass_convertVectorToArrayList(JNIEnv *env, jobject obj, jobject vectorObj) { jclass arrayListClass = env->FindClass("java/util/ArrayList"); jmethodID arrayListConstructor = env->GetMethodID(arrayListClass, "<init>", "()V"); jobject arrayListObj = env->NewObject(arrayListClass, arrayListConstructor); jclass vectorClass = env->GetObjectClass(vectorObj); jmethodID vectorSizeMethod = env->GetMethodID(vectorClass, "size", "()I"); jmethodID vectorGetMethod = env->GetMethodID(vectorClass, "get", "(I)Ljava/lang/Object;"); int size = env->CallIntMethod(vectorObj, vectorSizeMethod); for (int i = 0; i < size; i++) { jobject element = env->CallObjectMethod(vectorObj, vectorGetMethod, i); env->CallBooleanMethod(arrayListObj, env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z"), element); env->DeleteLocalRef(element); } env->DeleteLocalRef(arrayListClass); env->DeleteLocalRef(vectorClass); return arrayListObj; } ``` 在上面的代码,我们定义了一个名为 `convertVectorToArrayList` 的 JNI 函数,它接受一个 `std::vector` 对象并返回一个 `ArrayList` 对象。 首先,我们获取 `ArrayList` 类的引用,并使用其无参构造函数创建一个新的 `ArrayList` 对象。 然后,我们获取 `vector` 对象的类引用,并使用 `size` 和 `get` 方法来遍历 `vector` 对象的元素。对于每个元素,我们将其添加到 `ArrayList` 对象。 最后,我们释放所有局部引用并返回 `ArrayList` 对象。 在你的 Java 代码,你可以像这样调用 `convertVectorToArrayList` 函数: ```java MyClass myObj = new MyClass(); ArrayList<Integer> arrayList = myObj.convertVectorToArrayList(myVector); ``` 其,`myVector` 是你的 `std::vector` 对象。注意,这里我们假设 `myVector` 的元素类型是 `Integer`。如果你的元素类型不同,你需要相应地更改代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值