美文网首页
android svg图片使用 vector

android svg图片使用 vector

作者: 有点健忘 | 来源:发表于2019-08-16 15:38 被阅读0次

    刚出来的时候好像用vector图片还得gradle配置,代码里配置,现在好像都不需要了,直接可以用了,简单复习下

    必须

    app的build.gradle里还是得加上这个
    不加的话虽然vector图片可以识别,可是发现会模糊

    defaultConfig{
    //...
    vectorDrawables.useSupportLibrary=true
    }
    
    1. 导入图片
      系统提供了一些默认的,也可以用自己写的svg文件
    image.png

    然后看到下图,有两种,
    默认系统的,点击红框的部分可以选择别的图片,点击local file就可以选择本地的svg图片,系统会自动转换的,完事next就ok


    image.png

    之后在drawable下就看到对应的xml文件

    你不想用系统的,也不想导入svg文件,也可以自己新建一个,自己修改xml文件


    image.png
    1. 简单分析下vector图片的属性
      下边就是个三角形
    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24"
        android:viewportHeight="24">
        <path
            android:fillColor="#000"
            android:pathData="M7,14 l5,-5 5,5z" />
    </vector>
    
    image.png

    width和heigth其实可以说是画布的大小。viewportWidth相当于把画布分为24份了。

    path,简单看下,fillcolor填充颜色没啥说的。

    pathData就是主要的。M移动到某个位子。如图x7y14,之后小写的l表示相对距离,x方向5,y方向-5也就是往上,之后又来个5,5其实是省略了一个小写的l。相同属性的可以省略,所以这里省略了l。最后一个z表示闭合。就是终点自动连接到起点完事。

    支持的指令:

    M = moveto(M X,Y) :将画笔移动到指定的坐标位置

    L = lineto(L X,Y) :画直线到指定的坐标位置

    H = horizontal lineto(H X):画水平线到指定的X坐标位置

    V = vertical lineto(V Y):画垂直线到指定的Y坐标位置

    C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY):三次贝赛曲线

    S = smooth curveto(S X2,Y2,ENDX,ENDY)

    Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY):二次贝赛曲线

    T = smooth quadratic Belzier curveto(T ENDX,ENDY):映射

    A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y):弧线

    Z = closepath():关闭路径

    使用原则:

    坐标轴为以(0,0)为中心,X轴水平向右,Y轴水平向下

    所有指令大小写均可。大写绝对定位,参照全局坐标系;小写相对定位,参照父容器坐标系

    指令和数据间的空格可以省略

    同一指令出现多次可以只用一个

    注意,'M'处理时,只是移动了画笔, 没有画任何东西。 它也可以在后面给出上同时绘制不连续线。

    1. 看另外一个demo
    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp" 
        android:viewportWidth="12"
        android:viewportHeight="12">
        <path
            android:fillColor="#DD6F6F"
            android:strokeColor="#C51DE2"
            android:strokeWidth="0.5"
            android:trimPathStart="0.2" //截掉path开头的一部分,从0到1,影响的是stroke,还有个trimPathOffset影响的是solid
            android:strokeLineCap="round"
            android:strokeLineJoin="bevel"
            android:pathData="M6,0 l6,6 -6,6 -6,-6z" />
    </vector>
    
    image.png

    这个viewoportWidth和width不一样,也就是24dp被分成了12份,而下边的path,数字大小也是对应这个12份的了,
    也就是x12就是最右边,y12就是最下边了。

    1. 其他的属性

    clip-path 对它后边的所有path起作用,效果类似交集

        <clip-path android:pathData="M3,3 h5 v5 h-5 z" android:name="xxxx"/>
        <path android:pathData="M6,2 h10 v10 h-10 v-10z" android:fillColor="#D31919"/>
    

    因为clip-path对它后边所有的path起作用,那咋办?
    group标签来了,这样就只对group里的生效了,另外group标签还带旋转,拉伸,平移属性可以操作

        <group >
            <clip-path android:pathData="M3,3 h5 v5 h-5 z" android:name="xxxx"/>
            <path android:pathData="M0,2 h10 v10 h-10 v-10z" android:fillColor="#D31919"/>
        </group>
    
        <path android:pathData="M6,6 h-5 v-3z" android:fillColor="#111111"/>
    
    1. Stroke
      下边这一堆是定义边框的属性了,Cap是首尾的处理,有3种,和paint里的一样
      Join也是paint里的属性,就是两条线交叉的地方咋处理,bevel尖角,round圆角,miter
            android:strokeWidth="1"
            android:strokeColor="#f00"
            android:strokeAlpha="0.5"
            android:strokeLineCap="round"
            android:strokeLineJoin="bevel"
    

    下边这个干啥的,和上边的Join有关联的,LineJoin是bevel的时候

    android:strokeMiterLimit="1"
    

    如下,正常这样的


    image.png

    设置了android:strokeMiterLimit="1"以后这样了,当然了,如果这个值很大,超出了默认的尖角范围的话,那没啥作用了,只有弄个小的值,才能裁掉多余的尖角,额,这个值好像最小值是1?


    image.png
    1. name
      还都可以起个名字,动画的时候可以根据名字处理path下的某个属性
    android:name="xxx"
    
    1. trim
      简单来讲就是对原始path进行裁剪,offset是从起点开始的偏移量,TrimPathStart就是从哪里开始裁剪,得加上offset的量, trimPathEnd一样的道理,结束位置, 范围都是从0到1的,就是整个path的百分比
            android:trimPathStart="0.2"
            android:trimPathEnd="0.5"
            android:trimPathOffset="0.3"
    

    举个例子
    path是个半圆弧,从左到右的

        <path android:pathData="m10,20c0,5.523,4.477,10,10,10c5.523,0,10,-4.477,10,-10"
            android:strokeWidth="1"
            android:strokeColor="#f00"
            android:strokeAlpha="0.5"
            android:strokeLineCap="round"
            android:strokeLineJoin="bevel"
            android:fillAlpha="0.5"
            android:fillColor="@color/colorPrimary"
            android:fillType="evenOdd"/>
    
    image.png

    然后,我们加上trim属性,效果图就变了,很小的一段了,从圆弧的(0.3+0.2)开始,到(0.3+0.5)结束,我背景画了条绿色的半圆作为参考

            android:trimPathStart="0.2"
            android:trimPathEnd="0.5"
            android:trimPathOffset="0.3"
    
    image.png
    trim的作用比较大了,动画的时候动态修改这个,就可以显示隐藏path了,也可以动态的一点一点的显示出来.
    注意
    这里的trimPath 是有限制的,它只作用于path的第一段,如果pathData里有断开的多个path的话,那么是按第一段来算的。
    如下图,trimPathEnd是0.5结果就是第一段的一半
    image.png
    代码也很简单,path是由4段断开的圆弧组成的
    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="146dp"
        android:height="146dp"
        android:viewportWidth="146"
        android:viewportHeight="146">
    
        <path
            android:name="pathBg"
            android:pathData="M76,9c33.672,0,61,27.328,61,61
             M137,76c0,33.672,-27.328,61,-61,61
             M70,137c-33.672,0,-61,-27.328,-61,-61
             M9,70c0,-33.672,27.328,-61,61,-61"
            android:strokeWidth="18"
            android:strokeColor="@color/light_gray_bg" />
        <path
            android:name="pathFill"
            android:pathData="M76,9c33.672,0,61,27.328,61,61
             M137,76c0,33.672,-27.328,61,-61,61
             M70,137c-33.672,0,-61,-27.328,-61,-61
             M9,70c0,-33.672,27.328,-61,61,-61"
            android:trimPathEnd="0.5"
            android:strokeWidth="18"
            android:strokeColor="@color/colorPrimary" />
    
    </vector>
    

    使用中的问题

    1. 无法获取bitmap
      下边这种获取到的bitmap是null
      6.0如果有fillType的话,能获取到,其他版本获取不到
    Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.drawable.ic_vector_pic);
    

    解决办法:
    ① 换回png图片
    ②通过canvas画出来,后边有提供方法

    1. progress的图片一闪一闪的
      图片旋转一圈左右就会消失一瞬间,看着不舒服
            <ProgressBar
                android:id="@+id/pb_show"
                android:indeterminateDrawable="@drawable/simple_loading"
                android:layout_width="65dp"
                android:layout_height="65dp"/>
    
    <?xml version="1.0" encoding="utf-8"?>
    <animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/ic_loading"
        android:pivotX="50%"
        android:pivotY="50%"/>
    

    解决办法,
    ①把vectorDrawables.useSupportLibrary = false设置为false,然后发现图片正常不会闪一下了,
    不过不靠谱,没有这属性的话,无法让vector图片拉伸不模糊,所以只能使用png图片
    或者:
    android:indeterminateDrawable直接使用静态的ic_loading图片,完事我们开启一个动画旋转progressbar
    ②靠谱的解决办法:
    https://www.jianshu.com/p/9f3221179e3c
    vector loading图片稍作修改,增加group标签,方便旋转,如下
    ic_loading.xml

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="65dp"
        android:height="65dp"
        android:viewportWidth="65"
        android:viewportHeight="65">
        <group
            android:name="root"
            android:pivotX="32.5"
            android:pivotY="32.5">
            <path
                android:fillColor="#76FFE5"
                android:pathData="M32.24,11.96c-1.768,0 -3.12,-1.352 -3.12,-3.12V3.12c0,-1.768 1.352,-3.12 3.12,-3.12s3.12,1.352 3.12,3.12v5.72c0,1.664 -1.352,3.12 -3.12,3.12z" />
            <path
                android:fillColor="#0DBFBA"
                android:pathData="M32.24,64.48c-1.768,0 -3.12,-1.352 -3.12,-3.12v-5.72c0,-1.768 1.352,-3.12 3.12,-3.12s3.12,1.352 3.12,3.12v5.72c0,1.768 -1.352,3.12 -3.12,3.12z" />
            <path
                android:fillColor="#BBFFF2"
                android:pathData="M20.488,15.08c-1.04,0 -2.08,-0.52 -2.704,-1.56l-2.808,-4.888c-0.832,-1.456 -0.312,-3.432 1.144,-4.264 1.456,-0.832 3.432,-0.312 4.264,1.144l2.808,4.888c0.832,1.456 0.312,3.432 -1.144,4.264 -0.416,0.208 -1.04,0.416 -1.56,0.416z" />
            <path
                android:fillColor="#1BCEB8"
                android:pathData="M46.8,60.528c-1.04,0 -2.08,-0.52 -2.704,-1.56l-2.808,-4.888c-0.832,-1.456 -0.312,-3.432 1.144,-4.264 1.456,-0.832 3.432,-0.312 4.264,1.144l2.808,4.888c0.832,1.456 0.312,3.432 -1.144,4.264 -0.52,0.312 -1.04,0.416 -1.56,0.416z" />
            <path
                android:fillColor="#E1FFF9"
                android:pathData="M11.96,23.608c-0.52,0 -1.04,-0.104 -1.56,-0.416l-4.888,-2.808c-1.456,-0.832 -1.976,-2.808 -1.144,-4.264 0.832,-1.456 2.808,-1.976 4.264,-1.144l4.888,2.808c1.456,0.832 1.976,2.808 1.144,4.264 -0.624,1.04 -1.664,1.56 -2.704,1.56z" />
            <path
                android:fillColor="#26DBC0"
                android:pathData="M57.512,49.92c-0.52,0 -1.04,-0.104 -1.56,-0.416l-4.992,-2.808c-1.456,-0.832 -1.976,-2.808 -1.144,-4.264 0.832,-1.456 2.808,-1.976 4.264,-1.144l4.888,2.808c1.456,0.832 1.976,2.808 1.144,4.264 -0.52,1.04 -1.56,1.56 -2.6,1.56z" />
            <path
                android:fillColor="#F3FFFD"
                android:pathData="M8.84,35.36H3.12C1.352,35.36 0,34.008 0,32.24s1.352,-3.12 3.12,-3.12h5.72c1.768,0 3.12,1.352 3.12,3.12s-1.456,3.12 -3.12,3.12z" />
            <path
                android:fillColor="#2EE5C6"
                android:pathData="M61.36,35.36h-5.72c-1.768,0 -3.12,-1.352 -3.12,-3.12s1.352,-3.12 3.12,-3.12h5.72c1.768,0 3.12,1.352 3.12,3.12s-1.352,3.12 -3.12,3.12z" />
            <path
                android:fillColor="#11AEBA"
                android:pathData="M6.968,49.92c-1.04,0 -2.08,-0.52 -2.704,-1.56 -0.832,-1.456 -0.312,-3.432 1.144,-4.264l4.888,-2.808c1.456,-0.832 3.432,-0.312 4.264,1.144 0.832,1.456 0.312,3.432 -1.144,4.264l-4.888,2.808c-0.416,0.312 -0.936,0.416 -1.56,0.416z" />
            <path
                android:fillColor="#3BEDCB"
                android:pathData="M52.52,23.608c-1.04,0 -2.08,-0.52 -2.704,-1.56 -0.832,-1.456 -0.312,-3.432 1.144,-4.264l4.888,-2.808c1.456,-0.832 3.432,-0.312 4.264,1.144 0.832,1.456 0.312,3.432 -1.144,4.264l-4.888,2.808c-0.52,0.312 -1.04,0.416 -1.56,0.416z" />
            <path
                android:fillColor="#0FB8BC"
                android:pathData="M17.68,60.528c-0.52,0 -1.04,-0.104 -1.56,-0.416 -1.456,-0.832 -1.976,-2.808 -1.144,-4.264l2.808,-4.888c0.832,-1.456 2.808,-1.976 4.264,-1.144 1.456,0.832 1.976,2.808 1.144,4.264l-2.808,4.888c-0.624,1.04 -1.664,1.56 -2.704,1.56z" />
            <path
                android:fillColor="#57F7D8"
                android:pathData="M43.992,15.08c-0.52,0 -1.04,-0.104 -1.56,-0.416 -1.456,-0.832 -1.976,-2.808 -1.144,-4.264l2.808,-4.888c0.832,-1.456 2.808,-1.976 4.264,-1.144 1.456,0.832 1.976,2.808 1.144,4.264l-2.808,4.888c-0.624,0.936 -1.664,1.56 -2.704,1.56z" />
        </group>
    </vector>
    

    添加动画loading_vector_rotate.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <objectAnimator
            android:duration="2000"
            android:interpolator="@android:anim/linear_interpolator"
            android:propertyName="rotation"
            android:repeatCount="-1"
            android:valueFrom="0"
            android:valueTo="720"
            android:valueType="floatType" />
    </set>
    

    使用animated-vector添加 loading_vector.xml如下
    target里的name 就是我们vector图片里的属性,这里就是我们新加的group的名字,然后animation就是给这个group标签里的属性添加动画,我们这里就加了个旋转动画,还可以有拉伸和平移的动画可以添加

    <?xml version="1.0" encoding="utf-8"?>
    <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/ic_loading_d">
        <target
            android:name="root"
            android:animation="@anim/loading_vector_rotate" />
    </animated-vector>
    

    当然了,target还可以添加别的,比如vector里的某个path标签属性,我们可以修改stroke,fillColor,trim属性等等.
    这样一个简单的自动旋转的Progressbar的图片就ok了

        <ProgressBar
            android:id="@+id/pb_show"
            android:layout_width="65dp"
            android:layout_height="65dp"
            android:indeterminateDrawable="@drawable/loading_vector"
    

    如下图效果


    image.png
    1. 图片缺失一部分
      代码如下
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="45dp"
        android:height="66dp"
        android:viewportWidth="45"
        android:viewportHeight="66">
      <path
          android:pathData="M36.805,8.445C32.89,4.529 28.165,2.57 22.631,2.57c-5.534,0 -10.259,1.958 -14.174,5.874 -3.915,3.915 -5.873,8.64 -5.873,14.174 0,2.845 0.43,5.181 1.292,7.009l14.291,30.306a4.51,4.51 0,0 0,1.821 2.035,5.03 5.03,0 0,0 2.643,0.745 5.03,5.03 0,0 0,2.643 -0.745,4.75 4.75,0 0,0 1.86,-2.035l14.252,-30.306c0.861,-1.828 1.292,-4.164 1.292,-7.01 0,-5.533 -1.957,-10.258 -5.873,-14.173zM29.718,29.705c-1.958,1.958 -4.32,2.937 -7.087,2.937 -2.767,0 -5.13,-0.979 -7.087,-2.936 -1.958,-1.958 -2.937,-4.32 -2.937,-7.087 0,-2.767 0.98,-5.13 2.937,-7.087 1.958,-1.958 4.32,-2.937 7.087,-2.937 2.767,0 5.13,0.979 7.087,2.937 1.957,1.957 2.936,4.32 2.936,7.087 0,2.766 -0.979,5.128 -2.936,7.087z"
          android:fillColor="#FF5D5A"
          android:fillType="nonZero"/>
    </vector>
    

    预览图正常


    image.png

    可实际在app看到的长这样


    image.png
    使用的地方有两个
    ImageView dropPin = new ImageView (getContext());
        dropPin.setImageResource(R.drawable.ic_pin);
    

    还有个是拿到drawable,拿到bitmap,呆会要修改就不帖了
    最开始的解决办法:因为app里还有别的颜色的这种图片,长得差不多,不过整体宽高是一样的,就替换成别的图片的pathData了,发现没问题,根源应该还是这图有问题

    然后今天突发灵感,想到试下兼容的ImageView,也就是AppCompatImageView,结果真的可行

        ImageView dropPin = new AppCompatImageView(getContext());
        dropPin.setImageResource(R.drawable.ic_pin);
    

    获取bitmap的工具类也改了下
    修改了Drawable drawable = context.getDrawable(resId);

        public static Bitmap getDrawableBitmap(final Context context, int resId) {
            final Bitmap bitmap;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    //下边这行修改了,使用的是AppCompatImageView里用到的方法
                Drawable drawable = AppCompatResources.getDrawable(context,resId);
                bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
                        drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(bitmap);
                drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
                drawable.draw(canvas);
            } else {
                bitmap = BitmapFactory.decodeResource(context.getResources(), resId);
            }
            return bitmap;
        }
    

    课外知识

    咋画一个圆?里用三阶贝塞尔曲线
    下边的文章分析了原理,我们用结果就行
    https://www.jianshu.com/p/5198d8aa80c1
    記住红框里的数字即可。魔法数值0.551915024494 四舍五入我们用0.552就行了。

    image.png
    下边小圆是ui给的,半圆是我们里用上边的魔法值0.552自己画的
    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="45dp"
        android:height="45dp"
        android:viewportWidth="40"
        android:viewportHeight="40">
        <path
            android:pathData="h40,0v0,40,h-40,0v0,40z"
            android:strokeWidth="1"
            android:strokeColor="@color/colorPrimary" />
        <path
            android:fillColor="#C33131"
            android:fillType="evenOdd"
            android:pathData="M24,9.1c-0.5,1.5,0.3,3.1,1.8,3.6c1.5,0.5,3.1-0.3,3.6-1.8c0.5-1.5-0.3-3.1-1.8-3.6C26.1,6.8,24.5,7.6,24,9.1z" />
    
        <path android:pathData="m10,20c0,5.523,4.477,10,10,10c5.523,0,10,-4.477,10,-10"
            android:fillColor="@color/colorPrimary"
            android:fillType="evenOdd"/>
    </vector>
    
    image.png
    参考
    https://www.jianshu.com/p/9f3221179e3c

    相关文章

      网友评论

          本文标题:android svg图片使用 vector

          本文链接:https://www.haomeiwen.com/subject/rsgfsctx.html