Android直播头像动画,Android 抖音头像缩放特效 直播间特效 100%高度还原

原理分析:

public class DouYinHeaderView extends View {

private Bitmap bitmap;

BitmapShader bitmapShader;

Paint paint;

Matrix matrix;

private float currentScaleRatio = 1f;

private float minScaleRation = 0.9f;

private Paint circlePaint;

private int countDown;

boolean change;

Bitmap[] bitmaps = new Bitmap[2];

private int currentBitmapIndex;

private int padding;

private int expandOutside = (int) (getResources().getDisplayMetrics().density * 12 + 0.5f);

private boolean drawOutsideCirle;

private float outSideRatio;

private int unMoveCirlceStrokeWidth = (int) (getResources().getDisplayMetrics().density * 2 + 0.5f);

private int moveCircleStrokeWidth = (int) (getResources().getDisplayMetrics().density * 0.8f + 0.5f);

private Paint outsideCirclePaint;

public DouYinHeaderView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

paint = new Paint(Paint.ANTI_ALIAS_FLAG);

circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);

outsideCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);

outsideCirclePaint.setStyle(Paint.Style.STROKE);

outsideCirclePaint.setStrokeWidth(moveCircleStrokeWidth);

outsideCirclePaint.setColor(ContextCompat.getColor(getContext(), R.color.colorAccent));

padding += unMoveCirlceStrokeWidth * 2;

padding += expandOutside;

circlePaint.setStrokeWidth(unMoveCirlceStrokeWidth);

circlePaint.setStyle(Paint.Style.STROKE);

circlePaint.setColor(ContextCompat.getColor(getContext(), R.color.colorAccent));

matrix = new Matrix();

postDelayed(new Runnable() {

@Override

public void run() {

final ValueAnimator valueAnimator = ValueAnimator.ofFloat((float) Math.PI);

valueAnimator.setDuration(800);

valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

float currentValue = (Float) animation.getAnimatedValue();

currentScaleRatio = (float) (1f - Math.sin(currentValue) * (countDown == 5 ? 1 : (1f - minScaleRation)));

//sin(Pi/2)时等于1用于检测缩小到最小临界点

if (currentValue >= ((float) Math.PI) * 0.5f) {

drawOutsideCirle = false;

//在第五次缩小到最小时进行头像切换

if (countDown == 5 && !change) {

change = true;

currentBitmapIndex = (++currentBitmapIndex) % 2;

bitmap = bitmaps[currentBitmapIndex];

bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

paint.setShader(bitmapShader);

}

} else {

//是缩小动画因此设置画外圆标志位并计算外圆扩散动画因子outSideRatio

drawOutsideCirle = true;

outSideRatio = (float) Math.sin(currentValue);

}

invalidate();

}

});

valueAnimator.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationRepeat(Animator animation) {

countDown++;

if (countDown == 6) {

countDown = 1;

change = false;

}

super.onAnimationRepeat(animation);

}

@Override

public void onAnimationStart(Animator animation) {

super.onAnimationStart(animation);

countDown++;

}

});

valueAnimator.setRepeatMode(ValueAnimator.RESTART);

valueAnimator.setRepeatCount(ValueAnimator.INFINITE);

valueAnimator.start();

}

}, 2000);

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

decodeBitmap(R.drawable.test1, w - padding, h - padding);

bitmaps[0] = bitmap;

decodeBitmap(R.drawable.test2, w, h);

bitmaps[1] = bitmap;

bitmap = bitmaps[0];

bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

paint.setShader(bitmapShader);

}

private void fillMatrix() {

matrix.reset();

float sourceWidth = bitmap.getWidth();

float sourceHeight = bitmap.getHeight();

float targetWidth = (getWidth() - padding) * currentScaleRatio;

float targetHeight = (getHeight() - padding) * currentScaleRatio;

float wRatio = targetWidth / sourceWidth;

float hRatio = targetHeight / sourceHeight;

float scale = Math.max(wRatio, hRatio);

float translationX = 0f;

float translationY = 0f;

if (wRatio > hRatio) {

translationY = (targetHeight - sourceHeight * scale) * 0.5f;

} else if (wRatio < hRatio) {

translationX = (targetWidth - sourceWidth * scale) * 0.5f;

}

matrix.setScale(scale, scale);

matrix.postTranslate(translationX, translationY);

bitmapShader.setLocalMatrix(matrix);

}

@Override

protected void onDraw(Canvas canvas) {

canvas.translate(getWidth() * 0.5f, getHeight() * 0.5f);

canvas.save();

canvas.translate(-(getWidth() - padding) * currentScaleRatio * 0.5f, -(getHeight() - padding) * currentScaleRatio * 0.5f);

fillMatrix();

//画头像

canvas.drawCircle((getWidth() - padding) * currentScaleRatio * 0.5f, (getHeight() - padding) * currentScaleRatio * 0.5f, (getWidth() - padding) * currentScaleRatio * 0.5f, paint);

canvas.restore();

//画静止的圆

canvas.drawCircle(0, 0, getWidth() * 0.5f - padding * 0.5f + unMoveCirlceStrokeWidth * 0.5f, circlePaint);

//当头像缩小时我们根据缩小因子做外圆扩散动画以及透明度变化

if (drawOutsideCirle) {

float totalExpand = padding * 0.5f - unMoveCirlceStrokeWidth * 0.5f - moveCircleStrokeWidth * 0.5f;

/* int alpha = (int) (255 * (1 - outSideRatio));

outsideCirclePaint.setAlpha(alpha);*/

canvas.drawCircle(0, 0, getWidth() * 0.5f - padding * 0.5f + unMoveCirlceStrokeWidth * 0.5f + totalExpand * outSideRatio, outsideCirclePaint);

}

}

private void decodeBitmap(int resourceId, int targetWidth, int targetHeight) {

BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true;

BitmapFactory.decodeResource(getResources(), resourceId, options);

int sourceWidth = options.outWidth;

int sourceHeight = options.outHeight;

int sample = downSample(sourceWidth, sourceHeight, targetWidth, targetHeight);

options.inJustDecodeBounds = false;

options.inSampleSize = sample;

options.inPreferredConfig = Bitmap.Config.RGB_565;

bitmap = BitmapFactory.decodeResource(getResources(), resourceId, options);

}

private int downSample(int sourceWidth, int sourceHeight, int targetWidth, int targetHeight) {

int sample = 0;

while (true) {

if (sourceWidth / Math.pow(2, sample + 1) > targetWidth && sourceHeight / Math.pow(2, sample + 1) > targetHeight) {

sample++;

} else {

return (int) Math.pow(2, sample);

}

}

}

}

private static void startAni(Object object) {

ObjectAnimator objectAnimatorBig = ObjectAnimator.ofFloat((Button)object, "scaleX", 1, 1.5f,1);

ObjectAnimator objectAnimatorSmall = ObjectAnimator.ofFloat((Button)object, "scaleY", 1f, 1.5f, 1f);

objectAnimatorBig.setRepeatCount(-1);

objectAnimatorSmall.setRepeatCount(-1);

AnimatorSet animSet = new AnimatorSet();

animSet.play(objectAnimatorBig).with(objectAnimatorSmall);

animSet.setDuration(2000);

animSet.start();

}

android 抖音头像缩放

https://blog.csdn.net/sange77/article/details/102597074

https://www.jianshu.com/p/daa6e2710e1c

动画效果:先放大,然后回到原来的效果

https://blog.csdn.net/u010632547/article/details/107204254/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值