领略千变万化的Android Drawable (二)

版权声明:本文为博主原创文章,请尊重原创,未经博主允许禁止转载,保留追究权 https://blog.csdn.net/javazejian/article/details/52247337

转载请注明出处(万分感谢!):
http://blog.csdn.net/javazejian/article/details/52247337
出自【zejian的博客

关联文章:
领略千变万化的Android Drawable (一)
领略千变万化的Android Drawable (二)

  hello,上篇我们已经分析6种Drawable的使用方法,本篇咱们就继续剩下的Drawable~,闲话莫多说,那就直接开始吧。

7、TransitionDrawable

  很多时候我们在实现渐变的动画效果时,都会使用到animation,但实际上我们有既简单又完美的解决方法,没错,它就是TransitionDrawable啦,TransitionDrawable用于实现两个Drawable之间的淡入淡出的效果,它对应的是<transition&gt标签;其语法如下:

<?xml version="1.0" encoding="utf-8"?>
<transition
xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:drawable="@[package:]drawable/drawable_resource"
        android:id="@[+][package:]id/resource_name"
        android:top="dimension"
        android:right="dimension"
        android:bottom="dimension"
        android:left="dimension" />
</transition>

  语法中的属性比较简单,其中 android:top,android:bottom,android:left,android:right分别表示Drawable四周的偏移量。
android:id
  资源ID,drawable资源的唯一标识。使用”@+id/name”方式来给这个item定义一个新的资源ID。可以使用View.findViewById()或者 Activity.findViewById()等方式检索和修改这个item。
同样,我们来看一个实例:

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

引用如下:

<ImageView                                           
    android:id="@+id/image"                          
    android:layout_width="wrap_content"              
    android:layout_height="wrap_content"             
    android:layout_centerInParent="true"             
    android:background="@drawable/transition_drawable"      
/> 

  通过它的startTransition和reverseTransition方法实现淡入淡出效果,代码如下:

TransitionDrawable drawable= (TransitionDrawable) imageView.getBackground();
drawable.startTransition(4000);   

  如果在imageView设置的src属性

<ImageView                                           
    android:id="@+id/image"                          
    android:layout_width="wrap_content"              
    android:layout_height="wrap_content"             
    android:layout_centerInParent="true"             
    android:src="@drawable/transition_drawable"      
/> 

  代码控制为:

TransitionDrawable drawable= (TransitionDrawable) imageView.getDrawable();
drawable.startTransition(4000);   

  最终效果:

最后我们给出代码实现的方式,比较简单,这里不过多分析:

ImageView imageView= (ImageView) findViewById(R.id.tranImage);

Bitmap bitmap1= BitmapFactory.decodeResource(getResources(), R.drawable.image1);
Bitmap bitmap2= BitmapFactory.decodeResource(getResources(), R.drawable.image2);
final TransitionDrawable td = new TransitionDrawable(new Drawable[] {  new BitmapDrawable(getResources(), bitmap1),
        new BitmapDrawable(getResources(), bitmap2) });
imageView.setImageDrawable(td);
td.startTransition(4000);

8、InsetDrawable

  有时候我们可能需要为一个全屏的LinearLayout布局指定背景图,但我们不想让背景图充满屏幕,这时我们就需要使用到InsetDrawable了,InsetDrawable对应<inset>标签,它可以将其他Drawable内嵌到自己当中,并可以在四周预留出一定的间距。当我们希望View的背景比实际区域小时,就可以采用InsetDrawable来实现,个人认为这个效果并没有什么特殊之处,因为layerDrawable也是可以达到相同的预期效果的。其语法如下:

<?xml version="1.0" encoding="utf-8"?>
<inset
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/drawable_resource"
    android:insetTop="dimension"
    android:insetRight="dimension"
    android:insetBottom="dimension"
    android:insetLeft="dimension" />

属性解释:

属性 含义
android:insetTop 图像距离上边的距离
android:insetRight 图像距离右边的距离
android:insetBottom 图像距离底边的距离
android:insetLeft 图像距离左边的距离

  直接看个例子吧,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetBottom="10dp"
    android:drawable="@drawable/transition_bg_1"
    android:insetTop="10dp"
    android:insetLeft="10dp"
    android:insetRight="10dp"
    >
</inset>                                           

  直接作为根布局的背景

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/inset_drawable"
    tools:context="com.zejian.drawble.MainActivity">

</RelativeLayout>

  效果如下:

9、ScaleDrawable

  ScaleDrawable对应<scale>标签,主要基于当前的level,对指定的Drawable进行缩放操作。有点需要特别注意的是我们如果定义好了ScaleDrawable,要将其显示出来的话,必须给ScaleDrawable设置一个大于0小于10000的等级(级别越大Drawable显示得越大,等级为10000时就没有缩放效果了),否则将无法正常显示。我们可以看看其draw函数的源码:

  @Override
  public void draw(Canvas canvas) {
      final Drawable d = getDrawable();
      if (d != null && d.getLevel() != 0) {
          d.draw(canvas);
      }
  }

  很明显d.getLevel() != 0才会去把当前drawable画在画布上然后显示在屏幕上,我们知道这点后再来看看其语法:

<?xml version="1.0" encoding="utf-8"?>
<scale
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/drawable_resource"
    android:scaleGravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
                          "fill_vertical" | "center_horizontal" | "fill_horizontal" |
                          "center" | "fill" | "clip_vertical" | "clip_horizontal"]
    android:scaleHeight="percentage"
    android:scaleWidth="percentage" />

android:gravity
  当图片小于容器尺寸时,设置此选项可以对图片经典定位,这个属性比较多,不同选项可以使用‘|’来组合使用。

可选项 含义
top 将图片放在容器顶部,不改变图片大小
bottom 将图片放在容器底部,不改变图片大小
left 将图片放在容器左侧,不改变图片大小
right 将图片放在容器右侧,不改变图片大小
center_vertical 图片竖直居中,不改变图片大小
fill_vertical 图片竖直方向填充容器
center_horizontal 图片水平居中,不改变图片大小
fill_horizontal 图片水平方向填充容器
center 使图片在水平方向和竖直方向同时居中,不改变图片大小
fill 图片填充容器,默认值
clip_vertical 竖直方向剪切,很少使用
clip_horizontal 水平方向剪切,很少使用

android:scaleHeight
表示Drawable的高的缩放比例,值越大,内部Drawable的高度显示得越小,例如android:scaleHeight=”70%”,那么显示时Drawable的高度只有原来的30%。
android:scaleWidth
表示Drawable的宽的缩放比例,值越大,内部Drawable的宽显示得越小,例如android:scaleWidth=”70%”,那么显示时Drawable的宽度只有原来的30%。
直接来看个例子呗,我们设置两组宽高分别缩放70%和30%,然后来对比一下情况

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/image1"
    android:scaleHeight="70%"
    android:scaleWidth="70%"
    android:scaleGravity="center"
    >
</scale>
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/image1"
    android:scaleHeight="30%"
    android:scaleWidth="30%"
    android:scaleGravity="center"
    >
</scale>

  必须在java调用设置level(默认为0)的代码才可以正常显示:

ImageView scaleImage= (ImageView) findViewById(R.id.scaleImage);
ScaleDrawable scale= (ScaleDrawable) scaleImage.getBackground();
scale.setLevel(1);

  效果对比如下:

  我们再来对比一下宽高同等缩放比例(50%)下,level对Drawable的影响效果,分别设置level等级为1,5000,10000.

10、ClipDrawable

  ClipDrawable是通过设置一个Drawable的当前显示比例来裁剪出另一张Drawable,我们可以通过调节这个比例来控制裁剪的宽高,以及裁剪内容占整个View的权重,通过ClipDrawable的setLevel()方法控制显示比例,ClipDrawable的level值范围在[0,10000],level的值越大裁剪的内容越少,当level为10000时则完全显示,而0表示完全裁剪,不可见。需要注意的是在给clip元素中android:drawable属性设置背景图片时,图片不能是9图,因为这涉及到裁剪这张图片,如果设置为九图,裁剪的实际情况会与想要的效果不一样。ClipDrawable对应xml的<clip>标签,其语法如下:

 <?xml version="1.0" encoding="utf-8"?>
 <clip
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:drawable="@drawable/drawable_resource"
 android:clipOrientation=["horizontal" | "vertical"]
 android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
                  "fill_vertical" | "center_horizontal" | "fill_horizontal" |
                  "center" | "fill" | "clip_vertical" | "clip_horizontal"] />

  其中android:clipOrientation和android:gravity属性共同控制Drawable被裁剪的方向,其中clipOrientation表示裁剪的方向(水平和垂直两种),gravity比较复杂必须和clipOrientation一起才能起作用,同样的我们可以通过“|”来组合使用gravity的属性值。gravity属性值说明如下:

属性值 描述
top 将这个对象放在容器的顶部,不改变其大小。当clipOrientation 是”vertical”,裁剪从底部开始
bottom 将这个对象放在容器的底部,不改变其大小。当clipOrientation 是 “vertical”,裁剪从顶部(top)开始
left 将这个对象放在容器的左部,不改变其大小。当clipOrientation 是 “horizontal”,裁剪从drawable的右边(right)开始,默认值
right 将这个对象放在容器的右部,不改变其大小。当clipOrientation 是 “horizontal”,裁剪从drawable的左边(left)开始
center_vertical 将对象放在垂直中间,不改变其大小,如果clipOrientation 是 “vertical”,那么从上下同时开始裁剪
fill_vertical 垂直方向上不发生裁剪。(除非drawable的level是 0,才会不可见,表示全部裁剪完)
center_horizontal 将对象放在水平中间,不改变其大小,clipOrientation 是 “horizontal”,那么从左右两边开始裁剪
fill_horizontal 水平方向上不发生裁剪。(除非drawable的level是 0,才会不可见,表示全部裁剪完)
center 将这个对象放在水平垂直坐标的中间,不改变其大小。当clipOrientation 是 “horizontal”裁剪发生在左右。当clipOrientation是”vertical”,裁剪发生在上下。
fill 填充整个容器,不会发生裁剪。(除非drawable的level是 0,才会不可见,表示全部裁剪完)。
clip_vertical 附加选项,表示竖直方向的裁剪,很少使用
clip_horizontal 附加选项,表示水平方向的裁剪,很少使用

  ClipDrawable属性介绍完了,直接来个实战吧,

<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/image1"
    android:clipOrientation="horizontal"
    android:gravity="right"
    >
</clip>

  在上面的xml中我们实现了左侧裁剪的效果,因此应将clipOrientation设置为水平方向裁剪,gravity要设置为right。然后应用到我的ImageView上代码如下:

<ImageView                                             
    android:id="@+id/clipImage"                        
    android:layout_width="wrap_content"                
    android:layout_height="wrap_content"               
    android:layout_centerInParent="true"               
    android:background="@drawable/clip_drawable"       
    />                                                 

  接着在代码中设置ClipDrawable的等级,代码如下:

ImageView clipImage= (ImageView) findViewById(R.id.clipImage);
ClipDrawable clip= (ClipDrawable) clipImage.getBackground();
clip.setLevel(6000);

  因为这里我们在xml引用时设置的是背景图所以使用clipImage.getBackground(),如果在xml引用时使用的是src,那么就使用clipImage.getDrawable()即可。前面我们已经提到过,ClipDrawable的等级范围是[0,10000],而且level越大裁剪区域越少,当level=10000时,表示不裁剪,我们在这里设置了level为6000则表示裁剪40%的区域,效果如下:

  最后我们来实现一个案例,在实际开发中经常会使用到动画来实现一些特殊效果,比如我们可能需要实现一个徐徐展开的图片,这时我们的ClipDrawable就派上用场了,接着我们就是利用ClipDrawable来实现一个拥有徐徐展开效果的图片
思路:
  因为ClipDrawable的setLevel(int level)可以控制截取图片的部分,因此我们可以设置一个定时器,让程序每隔一段时间就调用ClipDrawable的setLevel(int level)方法即可实现图片徐徐展开效果。
  我们首先来实现一个clip_drawable_image.xml,并设置clipOrientation=”horizontal”,即水平剪切,以及设置gravity=”center”,即左右同时裁剪,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/image1"
    android:clipOrientation="horizontal"
    android:gravity="center">
</clip>

接着在activity_clip.xml文件布局中引用:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:scaleType="fitStart"
        android:src="@drawable/clip_drawable_image"
        />
</RelativeLayout>

代码调用如下:

package com.zejian.drawble;

import android.app.Activity;
import android.graphics.drawable.ClipDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by zejian
 * Time 16/8/19.
 * Description:
 */
public class Clip_Activity extends Activity {
    private final static int IS_CONTUNUE=0x22;
    private  ClipDrawable drawable;
    private  ImageView imageView;
    Timer timer = new Timer();

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {

            if (msg.what == IS_CONTUNUE) {
                /**setlevel()设置图片截取的大小
                 * 修改ClipDrawable的level值,level值为0--10000;
                 * 10000:截取图片大小为空白,0:截取图片为整张图片;
                 */
                drawable.setLevel(drawable.getLevel() + 200);
            }
        }

    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_clip);

        imageView = (ImageView) findViewById(R.id.image);
        //获取图片所显示的ClipDrawable对象
        drawable = (ClipDrawable) imageView.getDrawable();
        //定时器
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                Message msg = new Message();
                msg.what = IS_CONTUNUE;
                handler.sendMessage(msg);
                if (drawable.getLevel() >= 10000) {
                    timer.cancel();
                }
            }
        }, 0, 200);

    }
}

效果如下:

11、ColorDrawable

  ColorDrawable 是最简单的Drawable,它实际上是代表了单色可绘制区域,它包装了一种固定的颜色,当ColorDrawable被绘制到画布的时候会使用颜色填充Paint,在画布上绘制一块单色的区域。 在xml文件中对应<color>标签,它只有一个android:color属性,通过它来决定ColorDrawable的颜色。
xml实现如下:

<?xmlversion="1.0" encoding="utf-8"?>
<color xmlns:android="http://schemas.android.com/apk/res/android"
  android:color="@color/normal"
/>

  也可以使用代码实现,注意传入的颜色值为16进制的数字:

ColorDrawable cd = new ColorDrawable(0xff000000);
ImageView iv = (ImageView)findViewById(...);
iv.setImageDrawable(cd);

12、GradientDrawable

  GradientDrawable 表示一个渐变区域,可以实现线性渐变、发散渐变和平铺渐变效果,实际上这个我们在上一篇的shapeDrawable中就已经分析过了,忘了可以回头复习一下哈~,其对应的标签为<gtadient>一般都是配置shapeDrawable来使用,为其实现渐变颜色。这里给出简单案例如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >

    <gradient android:angle="90"
        android:startColor="@color/colorPrimary"
        android:centerColor="#fff"
        android:endColor="@color/color_state"
        android:type="linear"
        />
</shape>

   当然GradientDrawable也可以作为View的背景图,案例代码实现如下:

//分别为开始颜色,中间夜色,结束颜色
int colors[] = { 0xff255779 , 0xff3e7492, 0xffa6c0cd };
GradientDrawable gd = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors);

  最后设置给View的背景图即可。

setBackgroundDrawable(gd);

  代码实现GradientDrawable还可以设置边框,圆角,边框宽度等等,这里我们就不深究了,感兴趣可以自行研究一下。
  到此,常用的Drawable我们已经全部介绍完了,告一段落了哈~,下一篇我们将继续分享如何实现自定义Drawable,欢迎关注。

领略千变万化的Android Drawable (一)
领略千变万化的Android Drawable (二)

主要参考资料:
《android开发艺术探索》
《google android官网》

阅读更多

没有更多推荐了,返回首页