BounceCusImageView

这个点击后会弹性变大变小的,其实就是使用facebook的开源动画库 com.facebook.rebound 

这个网站里可以看看示例:http://facebook.github.io/rebound/

代码如下:

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;
import com.facebook.rebound.Spring;
import com.facebook.rebound.SpringConfig;
import com.facebook.rebound.SpringListener;
import com.facebook.rebound.SpringSystem;

/**
 * Created by deadline on 2015/2/2.
 *
 * question:
 *          1.图片过大比如1900X1200的图片wrap_content就会显示不完全
 *          2.动态更改形状问题 CIRCLE--->>ROUND_CORNER    true
 *                           CIRCLE--->>NORMAL          true
 *                           NORMAL--->>CIRCLE          false
 *                           NORMAL--->>ROUND_CORNER    true
 *                           ROUND_CORNER--->>CIRCLE    false
 *                           ROUND_CORNER--->>NORMAL    true
 */
public class BounceCusImageView extends ImageView implements SpringListener{

    private static final int DEFAULT_RADIUS = 20;
    private static final double DEFAULT_TENSION = 200;
    private static final double DEFAULT_FRICTION = 10;

    /**
     * com.facebook.rebound
     */
    private SpringSystem springSystem;
    private Spring spring;

    /**
     * paint
     */
    private Paint mBitMapPaint;

    /**
     * BitMap
     */
    private Bitmap bitmap;

    private BitmapShader bitmapShader;

    private Matrix matrix;

    /**
     * record left/right/top/bottom information
     */
    private RectF rectF = new RectF();

    /**
     * shape
     */
    private SHAPE shape = SHAPE.CIRCLE;

    /**
     * degree of radius
     */
    private int mRadius = DEFAULT_RADIUS;

    /**
     * tension
     */
    private double tension = DEFAULT_TENSION;

    /**
     * friction
     */
    private double friction = DEFAULT_FRICTION;

    /**
     * should bounce?
     */
    private boolean IsBounce = true;

    /**
     * BitMap Radius
     */
    private int mBitMapRadius;

    /**
     * if the bitmap is not square or circle,
     * mWidth = Math.min(width, height);
     */
    private int mWidth;

    /**
     * different shape
     */
    public enum SHAPE{
        NORMAL,
        CIRCLE,
        ROUND_CORNER;
    }

    public BounceCusImageView(Context context) {
        this(context, null);
    }

    public BounceCusImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BounceCusImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initCusImageView();

    }


    private void initCusImageView(){
        this.setScaleType(ScaleType.CENTER_CROP);
        springSystem = SpringSystem.create();
        spring = springSystem.createSpring();
        spring.setSpringConfig(SpringConfig.fromOrigamiTensionAndFriction(50, 1));
        setUpCusImageView();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        spring.addListener(this);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        spring.removeListener(this);
    }

    @Override
    public void onSpringUpdate(Spring spring) {
        float value = (float) spring.getCurrentValue();
        float scale = 1f - (value * 0.5f);
        setScaleX(scale);
        setScaleY(scale);
    }
    @Override
    public void onSpringAtRest(Spring spring) {
        spring.setSpringConfig(new SpringConfig(tension, friction));
    }

    @Override
    public void onSpringActivate(Spring spring) {}

    @Override
    public void onSpringEndStateChange(Spring spring) {}

    private void changeTensionFriction(){
        if(IsBounce) {
            spring.setAtRest();
        }
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if(IsBounce) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    spring.setEndValue(1f);
                    return true;
                case MotionEvent.ACTION_UP:
                    spring.setEndValue(0f);
                    return true;
            }
        }
        return super.dispatchTouchEvent(event);
    }

    private void setUpCusImageView() {

        if(shape == SHAPE.NORMAL){
            invalidate();
            return;
        }

        if(shape == null){
            shape = SHAPE.CIRCLE;
        }

        if(bitmap == null){
            return;
        }

        matrix = new Matrix();
        mBitMapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        float scale = 1.0f;
        if(shape == SHAPE.CIRCLE)
        {
            /**
             * getMeasureHeight()/getMeasureWidth() 的min num / bitmap min num
             */
            scale = mWidth * 1.0f /  Math.min(bitmap.getWidth(), bitmap.getHeight());
            mBitMapRadius = Math.min(getMeasuredHeight(), getMeasuredWidth())/2;

        }else if(shape == SHAPE.ROUND_CORNER)
        {
            scale = Math.max(getWidth() * 1.0f / bitmap.getWidth(), getHeight()
                    * 1.0f / bitmap.getHeight());
            rectF.set(0, 0, getWidth(), getHeight());
        }

        matrix.setScale(scale,scale);
        bitmapShader.setLocalMatrix(matrix);
        mBitMapPaint.setShader(bitmapShader);
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (shape == SHAPE.CIRCLE)
        {
            mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {

        switch (shape){
            case NORMAL:
                super.onDraw(canvas);
                break;
            case CIRCLE:
                canvas.drawCircle(getWidth()/2, getHeight()/2, mBitMapRadius, mBitMapPaint);
                break;
            case ROUND_CORNER:
                canvas.drawRoundRect(rectF, mRadius, mRadius, mBitMapPaint);
                break;
            default:
                canvas.drawCircle(getWidth()/2, getHeight()/2, mBitMapRadius, mBitMapPaint);
                break;
        }

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        setUpCusImageView();
    }

    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        bitmap = bm;
        setUpCusImageView();
    }

    @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        bitmap = getBitMapFromDrawable(drawable);
        setUpCusImageView();
    }

    @Override
    public void setImageURI(Uri uri) {
        super.setImageURI(uri);
        bitmap = getBitMapFromDrawable(getDrawable());
        setUpCusImageView();
    }

    @Override
    public void setImageResource(int resId) {
        super.setImageResource(resId);
        bitmap = getBitMapFromDrawable(getDrawable());
        setUpCusImageView();
    }

    private Bitmap getBitMapFromDrawable(Drawable drawable){
        if(drawable == null){
            return null;
        }
        if(drawable instanceof BitmapDrawable){
            return ((BitmapDrawable) drawable).getBitmap();
        }

        return getBlankBitMap(drawable);
    }

    private Bitmap getBlankBitMap(Drawable drawable){
        try {
            Bitmap bitmap;
            bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            return bitmap;
        } catch (OutOfMemoryError e) {
            return null;
        }

    }

    public int getRadius() {
        return mRadius;
    }

    public void setRadius(int mRadius) {
        this.mRadius = mRadius;
    }

    public boolean isBounce() {
        return IsBounce;
    }

    public void setBounce(boolean isBounce) {
        IsBounce = isBounce;
    }

    public SHAPE getShape() {
        return shape;
    }

    public void setShape(SHAPE shape) {
        this.shape = shape;
        if(shape == SHAPE.CIRCLE) {
            shape = null;
            setUpCusImageView();
        }
    }

    public double getTension() {
        return tension;
    }

    public void setTension(double tension) {
        this.tension = tension;
        changeTensionFriction();
    }

    public double getFriction() {
        return friction;
    }

    public void setFriction(double friction) {
        this.friction = friction;
        changeTensionFriction();
    }
}

主要说说这个库

首先在以下两个方法中注册和解除了SpringListener接口

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        spring.addListener(this);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        spring.removeListener(this);
    }

然后在disPatchTouchListener中setEndValue

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if(IsBounce) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    spring.setEndValue(1f);
                    break;
                case MotionEvent.ACTION_UP:
                    spring.setEndValue(0f);
                    break;
            }
        }
        return super.dispatchTouchEvent(event);
    }

spring.setEndValue(); 会循环调用onSpringUpdate();

我让这个类继承了SpringListener 接口,所以这个接口必须实现四个方法,主要看onSpringUpdate(); 和onSpringAtRest();

    @Override
    public void onSpringUpdate(Spring spring) {
        float value = (float) spring.getCurrentValue();
        float scale = 1f - (value * 0.5f);
        setScaleX(scale);
        setScaleY(scale);
    }
    @Override
    public void onSpringAtRest(Spring spring) {
        spring.setSpringConfig(new SpringConfig(tension, friction));
    }


    @Override
    public void onSpringActivate(Spring spring) {}


    @Override
    public void onSpringEndStateChange(Spring spring) {}

onSpringUpdate 不断改变view的大小,但是scale值最小为0.5f所以图片不会小到看不到

onSpringAtRest其实就是重新配置spring对象的tension,friction


其他的都是如何实现圆形的ImageView / 圆角的ImageView / 和正常的ImageView(即样式不变但是可以有弹跳效果)有兴趣的可以看看


还有,看代码最上方,还有一些小问题,我也是新手,如果谁知道为什么不妨告诉我,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值