Canvas的实际使用

来源:互联网 发布:ubuntu syslog函数 编辑:程序博客网 时间:2024/05/21 14:03

这里写图片描述
这个就是一个大致的实现效果,左右滑动用的是一个自定义的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方法进行摆放

@Overrideprotected 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进行事件处理

@Overridepublic 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