return true;
case MotionEvent.ACTION_MOVE:
mDx = (int) event.getX();
mDy = (int) event.getY();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mDx = -1;
mDy = -1;
break;
}
postInvalidate();
return super.onTouchEvent(event);
}
最后重写onDraw函数
这里分成两步。第一步将图片mbitmapBG缩放到控件大小,以完全覆盖控件,否则就会使用BitmapShader的填充模式。
这里先新建一张空白的位图cavasbg,这张位图的大小与控件大小一致,然后对背景位图进行拉伸,画到这张空白的位图上。
第二步,在mDx、mDy都不是-1时,将新建的mBitmapBG作为BitmapShader设置给Paint,然后在手指所在的位置画圆,把圆圈部分的图像显示出来。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBitmapBG == null) {
mBitmapBG = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvasbg = new Canvas(mBitmapBG);
canvasbg.drawBitmap(mBitmap, null, new Rect(0, 0, getWidth(), getHeight()), mPaint);
}
if (mDx != -1 && mDy != -1) {
mPaint.setShader(new BitmapShader(mBitmapBG, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT));
canvas.drawCircle(mDx, mDy, 150, mPaint);
}
}
下面的示例来讲解生成不规则的头像。
首先初始化bitmap:
public AvatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.avator_xizuka);
mPaint = new Paint();
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
}
接下来,将BitmapShader缩放到与控件的宽、高一致(setScale),由于我们要画的是一幅圆形图像,所以必须将图像缩放成一个正方形,只要正方形的边长与控件的宽度一致即可。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Matrix matrix = new Matrix();
float scale = (float) getWidth() / mBitmap.getWidth();
matrix.setScale(scale, scale);
mBitmapShader.setLocalMatrix(matrix);
mPaint.setShader(mBitmapShader);
float half = getWidth() / 2;
canvas.drawCircle(half, half, getWidth() / 2, mPaint);
}
同样是缩放BitmapShader,这里使用Matrix进行缩放,而前面的望远镜示例则是通过新建一张位图来进行缩放,这两种缩放方式都可用。
在缩放BitmapShader以后,在控件的正中央画一个圆形,显示出一副圆形区域的图像。这就是我们想要的圆形头像。
通过LinearGradient可以实现渐变的效果
下面是构造函数
public LinearGradient(float x0,float y0,float x1,float y1,int color0,int color1,TileMode tile)
其中(x0,y0) (x1,y1)分别表示起点、终点坐标。color0、color1表示起点终点颜色,tile和BitmapShader一样。
其中color用0xAARRGGBB显示,AA不能少。
第二个构造函数为:
public LinearGradient(float x0,float y0,float x1,float y1,int colors[],float positions[],TileMode tile)
其中colors[]用于指定颜色值数值,同样用0xAARRGGBB形式。
positions[]与渐变的颜色相对应,取值是0-1的Float类型数据。表示color中的每种颜色在渐变线中百分比的位置。
示例:闪光文字效果
这里做一个跑马灯式的文字渐变效果。
原理是做一个渐变的图像,和一段文字,然后渐变头像在文字上进行移动,使文字发光,变换颜色。
该渐变图像移动两个文字长度的距离。
首先我们让View继承自TextView,因为TextView本身可以绘制文字,不需要我们自己处理,所以这样方便一点。
public ShimmerTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = getPaint();
int length = (int) mPaint.measureText(getText().toString());
createAnim(length);
createLinearGradient(length);
}
接下里就是创建动画,动画让LinearGradient去移动,所以动画的起始到终止值应该是(0,2*text_Length),每次有新进度则重绘文字:
private void createAnim(int length) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 2 * length);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mDx = (int) animation.getAnimatedValue();
postInvalidate();
}
});
valueAnimator.setRepeatMode(ValueAnimator.RESTART);
valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
valueAnimator.setDuration(2000);
valueAnimator.start();
}
然后创建LinearGradient,其大小和TextView大小一样
private void createLinearGradient(int length) {
mLinearGradient = new LinearGradient(-length, 0, 0, 0, new int[]{getCurrentTextColor(), 0xff00ff00, getCurrentTextColor()},
new float[]{0, 0.5f, 1}, Shader.TileMode.CLAMP);
}
最后重写onDraw方法,根据setTranslate(mDx,0)来让其移动:
@Override
protected void onDraw(Canvas canvas) {
Matrix matrix = new Matrix();
matrix.setTranslate(mDx,0);
mLinearGradient.setLocalMatrix(matrix);
mPaint.setShader(mLinearGradient);
super.onDraw(canvas);
}
效果如下:
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
dialGradient
RadialGradient就是放射源式的渐变,从一个中心点发散。
双色渐变构造函数如下: