Canvas的实际使用

这里写图片描述
这个就是一个大致的实现效果,左右滑动用的是一个自定义的HorizontalScrollView,图片渐变用的是一个自定义Drawable;

1、自定义HorizontalScrollView实现实现左右滑动
1.1、extends HorizontalScrollView 并进行相应的初始化

public class GallaryHorizonalScrollView extends HorizontalScrollView implements View.OnTouchListener {
    private LinearLayout container;
    private int iconWidth;
    private int centerX;

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

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

    public GallaryHorizonalScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        //在ScrollView里面放置一个水平线性布局,再往里面放置很多的ImageView
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT
        );
        container = new LinearLayout(getContext());
        container.setLayoutParams(params);
        setOnTouchListener(this);
    }
}

1.2、重写onLayout方法进行摆放

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);
    //得到某一张图片的宽度
    View v = container.getChildAt(0);
    iconWidth = v.getWidth();
    //得到中间x坐标
    centerX = getWidth() / 2;
    //处理中心坐标改成中心图片的左边界
    centerX = centerX - iconWidth / 2;
    //给LinearLayout和HorizontalScrollView之间设置边框距离
    container.setPadding(centerX, 0, centerX, 0);
}

1.3、设置setOnTouchListener进行事件处理

@Override
public boolean onTouch(View v, MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_MOVE) {
        //处理移动
        //渐变图片
        reveal();
    }
    return false;
}

private void reveal() {
    //渐变效果
    //得到HorizontalScrollView滑出去的距离
    int scrollX = getScrollX();
    //找到两张渐变的图片的下标--左  右
    int indexLeft = scrollX / iconWidth;
    int indexRight = indexLeft + 1;
    //设置图片的level
    for (int i = 0; i < container.getChildCount(); i++) {
        if (i == indexLeft || i == indexRight) {
            //变化
            //比例
            float ratio = 5000f / iconWidth;
            ImageView ivLeft = (ImageView) container.getChildAt(indexLeft);
            //scrollX%icon_width:代表滑出去的距离
            //滑出去了icon_width/2  icon_width/2%icon_width
            ivLeft.setImageLevel((int) (5000 - scrollX % iconWidth * ratio));
            //右边
            if (indexRight < container.getChildCount()) {
                ImageView ivRight = (ImageView) container.getChildAt(indexRight);
                //scrollX%icon_width:代表滑出去的距离
                //滑出去了icon_width/2  icon_width/2%icon_width
                ivRight.setImageLevel(
                    (int) (10000 - scrollX % iconWidth * ratio)
                );
            }
        } else {
            //灰色
            ImageView iv = (ImageView) container.getChildAt(i);
            iv.setImageLevel(0);
        }

    }
}

这里只需要对ACTION_MOVE进行处理,对应的提供了一个添加图片数据源的方法;

/**
  * 添加图片
  *
  * @param revealDrawables 传入的Drawable数组资源
  */
public void addImageViews(Drawable[] revealDrawables) {
    for (int i = 0; i < revealDrawables.length; i++) {
        ImageView img = new ImageView(getContext());
        img.setImageDrawable(revealDrawables[i]);
        container.addView(img);
        if (i == 0) {
            img.setImageLevel(5000);
        }
    }
    addView(container);
}

2、自定义Drawable对图片进行处理
图片的渐变效果其实利用了Canvas的裁剪,将画布裁剪成两个区域,左边为未选状态,右边为已选状态,根据滑动的距离去做相应的显示;

public class RevealDrawable extends Drawable {
    //未被选
    private Drawable mUnselectedDrawable;
    //被选
    private Drawable mSelectedDrawable;
    //显示方向
    private int mOrientation;
    //横向
    public static final int HORIZONTAL = 1;
    //纵向
    public static final int VERTICAL = 2;
    //绘制和裁剪的矩形区域
    private final Rect mTmpRect = new Rect();

    public RevealDrawable(Drawable unselected, Drawable selected, int orientation) {
        mUnselectedDrawable = unselected;
        mSelectedDrawable = selected;
        mOrientation = orientation;
    }

    @Override
    public void draw(Canvas canvas) {
        //绘制
        int level = getLevel();//from 0 (minimum) to 10000
        //右边区域和左边区域--设置成灰色
        if (level == 10000 || level == 0) {
            mUnselectedDrawable.draw(canvas);
        } else if (level == 5000) {
            //全部选中  设置成彩色
            mSelectedDrawable.draw(canvas);
        } else {
            //混合效果的Drawable
            /**
             * 将画板切割成两块--左边和右边
             */
            Rect r = mTmpRect;
            //得到当前自身Drawable的矩形区域
            Rect bounds = getBounds();
            {
                //先绘制灰色部分   level 0--5000--10000
                //比例
                float ratio = (level / 5000f) - 1f;
                int w = bounds.width();
                if (mOrientation == HORIZONTAL) {
                    w = (int) (w * Math.abs(ratio));
                }
                int h = bounds.height();
                if (mOrientation == VERTICAL) {
                    h = (int) (h * Math.abs(ratio));
                }
                int gravity = ratio < 0 ? Gravity.LEFT : Gravity.RIGHT;
                //从一个已有的bounds矩形边界范围中抠出一个矩形r
                Gravity.apply(
                        gravity,//从左边还是从右边开始抠
                        w,//目标矩形的宽度
                        h,//目标矩形的高度
                        bounds,//被抠出来的rect
                        r//目标rect
                );
                //保存当前画布
                canvas.save();
                //进行切割
                canvas.clipRect(r);
                //进行绘制
                mUnselectedDrawable.draw(canvas);
                //恢复之前的画布
                canvas.restore();
            }
            {
                //绘制彩色部分   level 0--5000--10000
                //比例
                float ratio = (level / 5000f) - 1f;
                int w = bounds.width();
                if (mOrientation == HORIZONTAL) {
                    w -= (int) (w * Math.abs(ratio));
                }
                int h = bounds.height();
                if (mOrientation == VERTICAL) {
                    h -= (int) (h * Math.abs(ratio));
                }
                int gravity = ratio < 0 ? Gravity.RIGHT : Gravity.LEFT;
                //从一个已有的bounds矩形边界范围中抠出一个矩形r
                Gravity.apply(
                        gravity,//从左边还是从右边开始抠
                        w,//目标矩形的宽度
                        h,//目标矩形的高度
                        bounds,//被抠出来的rect
                        r//目标rect
                );
                //保存当前画布
                canvas.save();
                //进行切割
                canvas.clipRect(r);
                //进行绘制
                mSelectedDrawable.draw(canvas);
                //恢复之前的画布
                canvas.restore();
            }
        }
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        //定义好两个Drawable图片的宽高--边界bounds
        mUnselectedDrawable.setBounds(bounds);
        mSelectedDrawable.setBounds(bounds);
    }

    @Override
    public int getIntrinsicWidth() {
        //得到Drawable的实际宽度
        return Math.max(mSelectedDrawable.getIntrinsicWidth(),
                mUnselectedDrawable.getIntrinsicWidth());
    }

    @Override
    public int getIntrinsicHeight() {
        //得到Drawable的实际高度
        return Math.max(mSelectedDrawable.getIntrinsicHeight(),
                mUnselectedDrawable.getIntrinsicHeight());
    }

    @Override
    protected boolean onLevelChange(int level) {
        //当设置level的时候就会回调该方法
        //进行重新绘制
        invalidateSelf();
        return true;
    }

    @Override
    public void setAlpha(int alpha) {

    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {

    }

    @Override
    public int getOpacity() {
        return PixelFormat.UNKNOWN;
    }
}

3、使用

public class MainActivity extends AppCompatActivity {
    private int[] mImgIds = new int[] { //7个
            R.mipmap.avft,
            R.mipmap.box_stack,
            R.mipmap.bubble_frame,
            R.mipmap.bubbles,
            R.mipmap.bullseye,
            R.mipmap.circle_filled,
            R.mipmap.circle_outline,

            R.mipmap.avft,
            R.mipmap.box_stack,
            R.mipmap.bubble_frame,
            R.mipmap.bubbles,
            R.mipmap.bullseye,
            R.mipmap.circle_filled,
            R.mipmap.circle_outline
    };
    private int[] mImgIds_active = new int[] {
            R.mipmap.avft_active, R.mipmap.box_stack_active, R.mipmap.bubble_frame_active,
            R.mipmap.bubbles_active, R.mipmap.bullseye_active, R.mipmap.circle_filled_active,
            R.mipmap.circle_outline_active,
            R.mipmap.avft_active, R.mipmap.box_stack_active, R.mipmap.bubble_frame_active,
            R.mipmap.bubbles_active, R.mipmap.bullseye_active, R.mipmap.circle_filled_active,
            R.mipmap.circle_outline_active
    };
    public Drawable[] revealDrawables;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();
    }

    private void initView() {
        for (int i = 0; i < mImgIds.length; i++) {
            RevealDrawable rd=new RevealDrawable(
                    getResources().getDrawable(mImgIds[i]),
                    getResources().getDrawable(mImgIds_active[i]),
                    RevealDrawable.HORIZONTAL
            );
            revealDrawables[i]=rd;
        }
        GallaryHorizonalScrollView hsv = (GallaryHorizonalScrollView) findViewById(R.id.hsv);
        hsv.addImageViews(revealDrawables);
    }

    private void initData() {
        revealDrawables=new Drawable[mImgIds.length];
    }
}

源码地址:
http://download.csdn.net/download/wangwo1991/9971873

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值