[TOC]
Shader的基本使用不多说了,请参考blog.csdn.net/iispring/ar…,这里我们只讲解shader使用过程中的小细节或误区。
BitmapShader
BitmapShader加载的原图如下:
测试代码如下:
public class BitmapShaderView extends View {
private Paint mPaint;
private BitmapShader mShader;
private int mWidth;
private int mHeight;
private int mBitmapWidth;
private int mBitmapHeight;
private Matrix mMatrix;
private int mViewMin;
private int mBitmapMin;
public BitmapShaderView(Context context) {
this(context, null);
}
public BitmapShaderView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public BitmapShaderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mPaint = new Paint();
mPaint.setAntiAlias(true);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_test);
mBitmapWidth = bitmap.getWidth();
mBitmapHeight = bitmap.getHeight();
mMatrix = new Matrix();
mShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mWidth = getWidth();
mHeight = getHeight();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//测试调用函数
testX(canvas);
}
}
XML中定义如下:
<com.example.robincxiao.androidcanvas.shader.BitmapShaderView
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginTop="10dp" />
为了进行测试,我们将BitmapShaderView的宽高都定义为200dp,这个值大于Bitmap的原始宽高。
绘制图形大小与Bitmap大小关系
1.绘制图形大小与Bitmap大小相等
用如下方法替换上面的testX方法
private void test0(Canvas canvas) {
canvas.drawColor(Color.GRAY);
mPaint.setShader(mShader);
canvas.drawRect(0, 0, mBitmapWidth, mBitmapHeight, mPaint);
}
此时绘制的Rect与Bitmap的实际大小一致,得到如下效果:
2.绘制图形大小大于Bitmap实际大小
我们将test0中代码修改如下
private void test0(Canvas canvas) {
canvas.drawColor(Color.GRAY);
mPaint.setShader(mShader);
canvas.drawRect(0, 0, mWidth, mHeight, mPaint);
}
此时绘制的Rect大小是整个View,远大于Bitmap的实际大小,得到如下效果:
对比“1.绘制图形大小与Bitmap大小相等”的结果,此时发现BitmapShader的第2、3个参数有作用了
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
小结:当绘制的图形区域大于Bitmap实际大小时(其实这个说法不准备,具体看后面分析),会按照BitmapShader的第2、3个参数的设置进行着色。
3.绘制图形大小小于Bitmap实际大小
我们将test0中代码修改如下
private void test0(Canvas canvas) {
canvas.drawColor(Color.GRAY);
mPaint.setShader(mShader);
canvas.drawRect(0, 0, mBitmapWidth/2, mBitmapHeight/2, mPaint);
}
此时绘制的Rect大小是只有Bitmap实际大小的一般,得到如下效果:
对比“1.绘制图形大小与Bitmap大小相等”的结果,发现源图像只有左上角2/3区域被显示出来了。
总结:在使用BitmapShader进行着色时,要理解绘制图形大小与Bitmap实际大小最终对着色结果的影响。
坐标系对BitmapShader的影响
private void test0(Canvas canvas) {
canvas.drawColor(Color.GRAY);
mPaint.setShader(mShader);
canvas.translate(mWidth/2, mHeight/2);
canvas.drawRect(0, 0, mBitmapWidth, mBitmapHeight, mPaint);
}
我们将坐标系远点移动到BitmapShaderView的中心,得到的结果如下:
发现源Bitmap绘制的启动已经转移到BitmapShaderView的中心,但这还说明不了什么,因为drawRect的启动也是从中心开始的,得到上图所示的结果也是理所当然的。下面我们再修改test0代码如下:
private void test0(Canvas canvas) {
canvas.drawColor(Color.GRAY);
mPaint.setShader(mShader);
canvas.translate(mWidth/2, mHeight/2);
canvas.drawRect(-mBitmapWidth/2, -mBitmapHeight/2, mBitmapWidth/2, mBitmapHeight/2, mPaint);
}
我们以BitmapShaderView的中心为中心画一个正方形,这个正方形的大小与源Bitmap大小是一致的,得到的结果如下:
(注:BitmapShader的第2、3个参数为REPEAT)
得到这样的结果可能会让很多人觉得奇怪,按照“1.绘制图形大小与Bitmap大小相等”的分析,得到的结果应该与“1.绘制图形大小与Bitmap大小相等”的结果是一致的。这就是我想讲清楚的关键点:
- BitmapShader所加载的Bitmap,显示的规则是:从当前坐标系的圆点从左到右、从上到下的显示;因此Bitmap的绘制是受坐标系影响的;
- canvas实际绘制区域成为A,Bitmap自身绘制的区域B;A与B相交的区域显示B的内容,A中其它区域将按照BitmapShader的第二、三参数显示;
LinearGradient、RadialGradient、SweepGradient的使用过程中,同样要注意上面的问题。