根据Shader的自定义View和放大镜
前期学习了很多关于Paint的基础用法,重要用来做点什么,否则的话很快就会忘记的,这篇文章就先来实现个简单的Shader的用法,下面还会再来一篇。
当我们在学习Shader的时候就看到了他的定义,Shader是用来在绘制的过程中把相应的颜色绘制出来,比如说一张图片有很多的像素值,那么在用这个设置了BitmapShader的Paint对象绘制任何图形的时候都会在相应的位置绘制出相应的像素。好了,我们理解了这一点那么接下来的工作就比较简单了。
先看效果
下面就看看该如何实现上面的效果,首先肯定是一张白色的背景图,然后监听我们手指的触摸的位置,然后在相应的位置画个圆出来,那么问题就在于如何把这个图片相应的像素值设置给画笔,这时候就会用到我们的BitmapShader.
public class PaintShaderView extends View {
private Paint mPaint;
private Bitmap mBitmap;
private float dx,dy;
public PaintShaderView(Context context) {
this(context,null);
}
public PaintShaderView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public PaintShaderView(Context context, AttributeSet attrs, int defStyleAttr) {
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.girl);
initPaint();
}
private void initPaint() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStrokeWidth(5);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
BitmapShader shader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
mPaint.setShader(shader);
if(dx != 0 && dy != 0)
canvas.drawCircle(dx,dy,150,mPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
dx = 0;
dy = 0;
invalidate();
return true;
case MotionEvent.ACTION_MOVE:
dx = event.getX();
dy = event.getY();
invalidate();
return true;
case MotionEvent.ACTION_UP:
dx = 0;
dy = 0;
break;
}
invalidate();
return super.onTouchEvent(event);
}
}
根据Shader制作放大器自定义View
通过实现上面的Shader的自定义View,下面我来做个放大镜的自定义View,也是基于Shader,需求是这样的,当我们先是一张图片时,当用手指按下相应的位置时,这个时候能够跳出一个放大的效果的圆形。
先看一下效果图,
通过学习Paint和Matrix我们来实现这个效果应该还是比较简单的,先说一下思路,假设我们要做一个放大了三倍的效果的放大镜,那么这个时候就需要把原来的图片放大三倍,通过Matrix变换平移到相应的位置,然后实例化出相应的BitmapShader,设置给Paint,接着画出圆。下面看看怎么实现。
public class PaintShaderPracticeImageView extends View {
private Paint mPaint;
private Bitmap mBitmap;
private static final int FACTOR = 3 ;
private static final int RADIUS = 100 ;
private Matrix mMatrix;
private BitmapShader mShader;
public PaintShaderPracticeImageView(Context context) {
this(context,null);
}
public PaintShaderPracticeImageView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public PaintShaderPracticeImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.girl);
Bitmap bmp = mBitmap;
mMatrix = new Matrix();
bmp = Bitmap.createScaledBitmap(bmp,mBitmap.getWidth() * FACTOR ,mBitmap.getHeight() * FACTOR,true);
mShader = new BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(mShader);
}
private void initPaint() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, 0, 0, null);
//画制作好的圆形图片
if(!(dx == 0 && dy ==0 ) && dx< getWidth()&&dy<getHeight() ) {
Matrix matrix = new Matrix();
//这里时关键点,计算结果自己在本子自己画一遍
matrix.setTranslate(-dx * (FACTOR - 1) , -dy * (FACTOR -1 ) );
mShader.setLocalMatrix(matrix);
mPaint.setShader(mShader);
canvas.drawCircle(dx,dy,RADIUS,mPaint);
}
}
private int dx,dy;
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
dx = (int) event.getX();
dy = (int) event.getY();
break;
case MotionEvent.ACTION_UP:
dx = 0;
dy = 0;
break;
}
invalidate();
return true;
}
}
完整的代码已经贴出来了,上面的这个自定义View就有一个比较难一点的就是Matrix的平移的计算,这个计算不是很难,但是我也是花了一点时间的,因为我的第一印象时平移(-dx *FACTOR,-dy*FACTOR), 但是这个时候这个放大镜画的地方总是有点误差,在纸上画了一下发现是
matrix.setTranslate(-dx * (FACTOR - 1) , -dy * (FACTOR -1 ) );
好了这篇文章就这样,介绍了两个关于Shader的自定义View,应该能让大家对于Shader和Matrix有比较深刻的了解。下面会继续介绍一下Canvas。