上下扫描以及扩散扫描

效果图


思路

        显示图片,所以继承ImageView。

        图片有两种状态:一种是正常状态,一种是有较暗状态。较暗状态是将按一定的透明度比例绘制正常的图片即可。

代码

public class DakaImageView extends ImageView {
    /**
     * 从上往下刷新
     */
    private static final int ANIM_UP_DOWN = 1;
    /**
     * 波纹扩散
     */
    private static final int ANIM_SPREAD = 2;
    /**
     * 没有动画执行
     */
    private static final int ANIM_NO = 3;
    private static final String TAG = DakaImageView.class.getSimpleName();
    private int mCurrAnim = ANIM_NO;
    private ValueAnimator mUpdownAnim, mSpreadAnim;
    private Paint mUpdownPaint;
    private float mMaskOffsetY = 0, mMaskoffsetRadius = 0;
    private Bitmap mUpdownMaskBitmap, mSpreadMaskBitmap, mUnmaskBitmap;
    private static final float ALPHA = 0.3f;
    private Path path;

    public DakaImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        setLayerType(LAYER_TYPE_SOFTWARE, null);
        mUpdownPaint = new Paint();
        mUpdownPaint.setAntiAlias(true);
        mUpdownPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //设置死宽高
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.makeMeasureSpec(getDrawable().getIntrinsicWidth(),MeasureSpec.EXACTLY);
        int height = MeasureSpec.makeMeasureSpec(getDrawable().getIntrinsicHeight(),MeasureSpec.EXACTLY);
        setMeasuredDimension(width,height);
    }

    @Override
    protected void onDetachedFromWindow() { //回收相应的资源文件
        super.onDetachedFromWindow();
        stopAndRecyclerAnim(mUpdownAnim);
        stopAndRecyclerAnim(mSpreadAnim);
        recyclerBitmap(mUpdownMaskBitmap);
        recyclerBitmap(mUnmaskBitmap);
        recyclerBitmap(mSpreadMaskBitmap);
        mUpdownPaint = null;
    }

    private void recyclerBitmap(Bitmap bitmap) {
        if (bitmap != null && !bitmap.isRecycled()) {
            bitmap.recycle();
        }
        bitmap = null;
    }

    private void stopAndRecyclerAnim(ValueAnimator animator) {
        if (animator != null && animator.isRunning()) {
            animator.cancel();
        }
        animator = null;
        if(mSpreadAnim == null && mUpdownAnim == null){//两个动画都停止后,恢复成正常状态
            mCurrAnim = ANIM_NO;
            invalidate();
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        switch (mCurrAnim) {
            case ANIM_NO:
                drawUnmask(canvas);
                break;
            case ANIM_UP_DOWN:
                drawUpDown(canvas);
                break;
            case ANIM_SPREAD:
                drawSpread(canvas);
                break;
        }
    }

    private void drawUnmask(Canvas canvas) {
        Bitmap bitmap = getUnmaskBitmap();
        canvas.drawBitmap(bitmap, 0, 0, null);
        recyclerBitmap(mUpdownMaskBitmap);
        recyclerBitmap(mSpreadMaskBitmap);
    }

    private void drawUpDown(Canvas canvas) {
        //绘制底图
        Bitmap unmaskBitmap = getUnmaskBitmap();
        canvas.drawBitmap(unmaskBitmap, 0, 0, null);
        //绘制阴影部分
        Bitmap maskBitmap = getUpdownMaskBitmap();
        mUpdownPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        int top = mMaskOffsetY - getHeight() < 0 ? 0 : (int) mMaskOffsetY - getHeight();
        canvas.drawBitmap(maskBitmap, new Rect(0, top, unmaskBitmap.getWidth(), (int) mMaskOffsetY), new Rect(0, top, getWidth(), (int) mMaskOffsetY), mUpdownPaint);
        mUpdownPaint.setXfermode(null);
    }

    /**
     * 绘制水波纹
     */
    private void drawSpread(Canvas canvas) {
        //绘制水波纹
        Bitmap maskBitmap = getSpreadMaskBitmap();
        canvas.drawBitmap(maskBitmap, 0, 0, null);
    }

    private Bitmap getUnmaskBitmap() { //获取正常情况下的bitmap
        if (mUnmaskBitmap != null)
            return mUnmaskBitmap;
        int width = getWidth();
        int height = getHeight();
        mUnmaskBitmap = createBitmapAndGcIfNecessary(width, height);
        Canvas canvas = new Canvas(mUnmaskBitmap);
        Drawable drawable = getDrawable();
        drawable.setAlpha(255); //正常情况下,不透明。用drawable绘制到自己指定的canvas上,就会将drawable转换成bitmap
        drawable.draw(canvas);
        return mUnmaskBitmap;
    }

    private Bitmap getUpdownMaskBitmap() {
        int width = getWidth();
        int height = getHeight();
        if (mUpdownMaskBitmap == null)
            mUpdownMaskBitmap = createBitmapAndGcIfNecessary(width, height);
        Canvas canvas = new Canvas(mUpdownMaskBitmap);
        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
        canvas.clipRect(0, 0, width, mMaskOffsetY); //截取一部分区域,这样在绘制半透明的区域时就会只绘制截取到的部分
        Drawable drawable = getDrawable();
        drawable.setAlpha((int) (255 * ALPHA));
        drawable.draw(canvas);
        return mUpdownMaskBitmap;
    }

    private Bitmap getSpreadMaskBitmap() {
        int width = getWidth();
        int height = getHeight();
        if (mSpreadMaskBitmap == null) {
            mSpreadMaskBitmap = createBitmapAndGcIfNecessary(width, height);
        }
        Canvas canvas = new Canvas(mSpreadMaskBitmap);
        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
        //画原来未变暗的图
        Drawable drawable = getDrawable();
        drawable.setAlpha(255);
        drawable.draw(canvas);
        int max = Math.max(getWidth(), getHeight()) / 2;
        if(path == null) {
            path = new Path();
        }else{
            path.reset();
        }
        if (mMaskoffsetRadius < max) { //从内往外扩散的是半透明的
            path.addCircle(getWidth() / 2, getHeight() / 2, mMaskoffsetRadius, Path.Direction.CCW);
            canvas.clipPath(path); //截取一个圆环,然后用drawable绘制,这样绘制的drawable就是一个半透明的的圆环了。
            canvas.drawColor(0, PorterDuff.Mode.CLEAR);
            drawable.setAlpha((int) (255 * ALPHA));
            drawable.draw(canvas);
        } else {//从内往外扩散的是不透明的
            //外圈阴影  。首先绘制外圈半透明的
            path.reset();
            path.addCircle(getWidth() / 2, getHeight() / 2, max, Path.Direction.CCW);
            canvas.clipPath(path);
            canvas.drawColor(0, PorterDuff.Mode.CLEAR);
            drawable.setAlpha((int) (255 * ALPHA));
            drawable.draw(canvas);
            //内圈正常
            path.reset();
            path.addCircle(getWidth() / 2, getHeight() / 2, mMaskoffsetRadius - max, Path.Direction.CCW);
            canvas.clipPath(path);
            canvas.drawColor(0, PorterDuff.Mode.CLEAR);
            drawable.setAlpha(255);
            drawable.draw(canvas);
        }
        return mSpreadMaskBitmap;
    }

    private Bitmap createBitmapAndGcIfNecessary(int width, int height) {
        try {
            return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        } catch (OutOfMemoryError e) {
            System.gc();
            return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        }
    }

    //----------------------------------------提供出去的方法---------------------------------
    public void startUpDown() {
        mCurrAnim = ANIM_UP_DOWN;
        stopAndRecyclerAnim(mSpreadAnim);
        mUpdownAnim = ValueAnimator.ofInt(0, getHeight() * 2);
        mUpdownAnim.setDuration(2000);
        mUpdownAnim.setRepeatCount(ValueAnimator.INFINITE);
        mUpdownAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mMaskOffsetY = (int) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        mUpdownAnim.start();
    }

    public void stopUpDown() {
        if (null != mUpdownAnim)
            stopAndRecyclerAnim(mUpdownAnim);
    }

    public void startSpread() {
        stopAndRecyclerAnim(mUpdownAnim);
        mCurrAnim = ANIM_SPREAD;
        int radius = Math.max(getWidth(), getHeight()) / 2;
        mSpreadAnim = ValueAnimator.ofInt(0, radius * 2);
        mSpreadAnim.setDuration(1000);
        mSpreadAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                mMaskoffsetRadius = (int) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });
        mSpreadAnim.setRepeatCount(2);
        mSpreadAnim.start();
    }

    public boolean isAnimming() {
        return mCurrAnim == ANIM_SPREAD || mCurrAnim == ANIM_UP_DOWN;
    }
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值