多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
#### 6.2.8 ScaleDrawable ScaleDrawable对应于`<scale>`标签,它可以根据自己的等级(level)将指定的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:scaleGravity的含义等同于shape中的android:gravity,而android:scaleWidth和android:scaleHeight分别表示对指定Drawable宽和高的缩放比例,以百分比的形式表示,比如25%。 ScaleDrawable有点费解,要理解它,我们首先要明白等级对ScaleDrawable的影响。等级0表示ScaleDrawable不可见,这是默认值,要想ScaleDrawable可见,需要等级不能为0,这一点从源码中可以得出。来看一下ScaleDrawable的draw方法,如下所示。 public void draw(Canvas canvas) { if (mScaleState.mDrawable.getLevel() ! = 0) mScaleState.mDrawable.draw(canvas); } 很显然,由于ScaleDrawable的等级和mDrawable的等级是保持一致的,所以如果ScaleDrawable的等级为0,那么它内部的mDrawable的等级也必然为0,这时mDrawable就无法绘制出来,也就是ScaleDrawable不可见。下面再看一下ScaleDrawable的onBoundsChange方法,如下所示。 protected void onBoundsChange(Rect bounds) { final Rect r = mTmpRect; final boolean min = mScaleState.mUseIntrinsicSizeAsMin; int level = getLevel(); int w = bounds.width(); if (mScaleState.mScaleWidth > 0) { final int iw = min ? mScaleState.mDrawable.getIntrinsicWidth() : 0; w -= (int) ((w - iw) * (10000- level) * mScaleState.mScaleWidth / 10000); } int h = bounds.height(); if (mScaleState.mScaleHeight > 0) { final int ih = min ? mScaleState.mDrawable.getIntrinsicHeight() : 0; h -= (int) ((h - ih) * (10000- level) * mScaleState.mScaleHeight / 10000); } final int layoutDirection = getLayoutDirection(); Gravity.apply(mScaleState.mGravity, w, h, bounds, r, layoutDirection); if (w > 0 && h > 0) { mScaleState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom); } } 在ScaleDrawable的onBoundsChange方法中,我们可以看出mDrawable的大小和等级以及缩放比例的关系,这里拿宽度来说,如下所示。 final int iw = min ? mScaleState.mDrawable.getIntrinsicWidth() : 0; w -= (int) ((w - iw) * (10000- level) * mScaleState.mScaleWidth / 10000); 由于iw一般都为0,所以上面的代码可以简化为:w -= (int) (w * (10000- level) *mScaleState.mScaleWidth / 10000)。由此可见,如果ScaleDrawable的级别为最大值10000,那么就没有缩放的效果;如果ScaleDrawable的级别(level)越大,那么内部的Drawable看起来就越大;如果ScaleDrawable的XML中所定义的缩放比例越大,那么内部的Drawable看起来就越小。另外,从ScaleDrawable的内部实现来看,ScaleDrawable的作用更偏向于缩小一个特定的Drawable。在下面的例子中,可以近似地将一张图片缩小为原大小的30%,代码如下所示。 // res/drawable/scale_drawable.xml <? 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" /> 直接使用上面的drawable资源是不行的,还必须设置ScaleDrawable的等级为大于0且小于等于10000的值,如下所示。 View testScale = findViewById(R.id.test_scale); ScaleDrawable testScaleDrawable = (ScaleDrawable) testScale.getBackground(); testScaleDrawable.setLevel(1); 经过上面的两步可以正确地缩放一个Drawable,如果少了设置等级这一步,由于Drawable的默认等级为0,那么ScaleDrawable将无法显示出来。我们可以武断地将Drawable的等级设置为大于10000的值,比如20000,虽然也能正常工作,但是不推荐这么做,这是因为系统内部约定Drawable等级的范围为0到10000。