动画描述:
1.绘制圆形头像
2.头像图片缩小然后放大到远处(心跳动画)
3.头像缩小的同时,画一个和头像一样的圈,圈放大,透明度变化。(外面的圆圈向外扩散)
原理分析:
valueAnimator+invalidate()
方法二:
1.已经有了圆形头像。想通过组合的形式
继承Relalayouy.然后把原型图片位置放我,然后绘制一个外圆。
这样是不靠谱的,因为继承RelativeLayout不会再去实现ondraw方法。而是dispathDraw方法。!
方法三:
1.因为头像和圈是同一个控件,所以不能直接操作view
一直改变绘制头像的半径。导致图像缩放
小圆和大圆的中心点不变,变的只是半径!
2.扩散效果:再绘制一个圆,变大它的半径和透明度。
备注:
不能操作view就用这个valueAnimator。配合自定义绘制
ObjectAnimator:完全操控view
public class RoundImageViewextends AppCompatImageView {
private int borderColor;// 圆形头像的边框颜色
private int borderWidth;// 圆形头像的边框宽度
private PaintmBitmapPaint;// 绘制图像的Paint
private PaintmBorderPaint;
private MatrixmMatrix;// 图像矩阵,本身是一个3*3矩阵
private int mRadius;
private int mImgWidth;
private int centerX;
private int centerY;
/***
*
* @param context
* @param attrs
*/
private float smallInnerScaleRatio =1f;//变小
private float BigOutsideRatio =1f;
public RoundImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundImageView(Context context) {
this(context, null);
}
public RoundImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs);
mBitmapPaint =new Paint();
mBorderPaint =new Paint();
mMatrix =new Matrix();
mBitmapPaint.setAntiAlias(true);
mBorderPaint.setAntiAlias(true);
}
private void initAttrs(Context context, AttributeSet attrs) {
borderColor = Color.RED;
borderWidth =8;
postDelayed(new Runnable() {
@Override
public void run() {
startAnim();
}
}, 2000);
}
private void startAnim() {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(1f, 0.5f);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setDuration(500);
valueAnimator.setRepeatCount(-1);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
smallInnerScaleRatio = value;
BigOutsideRatio =1 + (1 - value);
invalidate();
}
});
valueAnimator.start();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//写好一个控件自定义View,写出一个能用的自定义View不易啊。。。
// 虽然测量这块儿寥寥几行代码,但是还得心细啊。。
int imgHeight = setMeasureHeight(heightMeasureSpec) - getPaddingTop() - getPaddingBottom() -borderWidth *2;
int imgWidth = setMeasureWidth(widthMeasureSpec) - getPaddingLeft() - getPaddingRight() -borderWidth *2;
if (imgHeight < imgWidth) {
mImgWidth = imgHeight;
mRadius =mImgWidth /2;
centerX =mRadius;
centerY =mRadius;
Log.d("Round", "imgHeight < imgWidth");
}else {//
mImgWidth = imgWidth;
mRadius =mImgWidth /4;//半径是图片的一半
centerX =mImgWidth /2;
centerY =centerX;
Log.d("Round", "imgHeight > imgWidth");
}
setMeasuredDimension(setMeasureWidth(widthMeasureSpec), setMeasureHeight(heightMeasureSpec));
}
private int setMeasureHeight(int heightMeasureSpec) {
int height =0;
int minHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 56,
getResources().getDisplayMetrics());
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
switch (specMode) {
case MeasureSpec.EXACTLY:
height = (specSize < minHeight ? minHeight : specSize);// 此处我是设置了EXACTLY的值,仅是圆形图片大小的值
break;
case MeasureSpec.AT_MOST:
height = minHeight + getPaddingTop() + getPaddingBottom();
break;
case MeasureSpec.UNSPECIFIED:
height = minHeight + getPaddingTop() + getPaddingBottom();
break;
}
return height;
}
private int setMeasureWidth(int widthMeasureSpec) {
int width =0;
int minWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 56,
getResources().getDisplayMetrics());
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
switch (specMode) {
case MeasureSpec.EXACTLY:
width = (specSize < minWidth ? minWidth : specSize);
break;
case MeasureSpec.AT_MOST:
width = minWidth + getPaddingLeft() + getPaddingRight();
break;
case MeasureSpec.UNSPECIFIED:
width = minWidth + getPaddingRight() + getPaddingLeft();
break;
}
return width;
}
@Override
protected void onDraw(Canvas canvas) {
this.setBackgroundColor(Color.WHITE);
if (getDrawable() ==null) {
return;
}
setShader();
float realRadiusBitmap =mRadius *smallInnerScaleRatio;//修改图片绘制的半径,而缩放
//中心点
float centerTempx =centerX +borderWidth + getPaddingLeft();
float centerTempy =centerY +borderWidth + getPaddingTop();
canvas.drawCircle(centerTempx, centerTempy,
realRadiusBitmap, mBitmapPaint);//绘制头像
mBorderPaint.setColor(borderColor);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setStrokeWidth(borderWidth /2);
canvas.drawCircle(centerX +borderWidth + getPaddingLeft(), centerY +borderWidth + getPaddingTop(),
mRadius +borderWidth /2, mBorderPaint);//绘制外圆
float realRadiusOut =mRadius *BigOutsideRatio;
mBorderPaint.setStrokeWidth(borderWidth /2);
mBorderPaint.setColor(Color.GREEN);
canvas.drawCircle(centerX +borderWidth + getPaddingLeft(), centerY +borderWidth + getPaddingTop(),
realRadiusOut +borderWidth /2, mBorderPaint);//绘制散动的圆
}
/**
* 初始化bitmapShader
* 图片缩放,通过矩阵进行。
* 在于矩阵先缩放,再移动
*/
private void setShader() {
Drawable drawable = getDrawable();
Bitmap bmp = drawableToBitmap(drawable);
BitmapShader mBitmapShader =new BitmapShader(bmp, TileMode.CLAMP, TileMode.CLAMP);
float scale =1.0f;
// 去取bitmap中宽度和高度中更小的,为了使图像缩放之后,可以填充满控件的空间,
// 此处切记要乘以1.0f,,这种低级错误写的时候又犯了一次。
scale =mImgWidth *1.0f / (Math.min(bmp.getWidth(), bmp.getHeight()));
// scale=scale*currentScaleRatio;
mMatrix.setScale(scale, scale);
mMatrix.postTranslate(getPaddingLeft() +borderWidth, getPaddingTop() +borderWidth);//这里使用了Matrix的后乘进行效果叠加,
// 使图像根据padding进行位移
mBitmapShader.setLocalMatrix(mMatrix);
mBitmapPaint.setShader(mBitmapShader);
}
/**
* 将Drawable转变为bitmap
*/
private BitmapdrawableToBitmap(Drawable drawable) {
if (drawableinstanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.getBitmap();
}
int h = drawable.getIntrinsicHeight();
int w = drawable.getIntrinsicWidth();
Bitmap bitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas =new Canvas(bitmap);// 建立对应的bitmap画布
drawable.setBounds(0, 0, w, h);// 此处的setBounds是指,drawable将在canvas的0,0,w,h矩形区域内
drawable.draw(canvas);// 将drawable的内容画到画布中去
return bitmap;
}
}
android 抖音头像缩放
https://blog.csdn.net/sange77/article/details/102597074
https://www.jianshu.com/p/daa6e2710e1c
动画效果:先放大,然后回到原来的效果
网友评论