新视频开发动画

3.Android 抖音直播头像动画 头像动效缩放特效

2021-06-17  本文已影响0人  鹏城十八少

动画描述:

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

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

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

上一篇 下一篇

猜你喜欢

热点阅读