Android-UI-03-图形绘制-Canvas-drawable案列

Drawable:

Drawable就是一个可画的对象,表示一种可以在Canvas上进行绘制的抽象的概念,其可能是一张(BitmapDrawable),也可能是一个图形(ShapeDrawable),还有可能是一个图层(LayerDrawable),我们根据画图的需求,创建相应的可画对象,就可以将这个可画对象当作一块“画布(Canvas)”,在其上面操作可画对象,并最终将这种可画对象显示在画布上,有点类似于“内存画布“。

HorizontalScrollView+Drawable 实现案列:

自定义drawable

 

大体思路:

1>在HorizontalScrollView的onTouch()中监听ACTION_MOVE事件  

2>getScrollX()得到HorizontalScrollView滑动距离找到两张渐变的图片的下标

3>HorizontalScrollView中设置图片的level  会在Drawable的onLevelChange()方法中监听到level变化 

4>level变化  调用invalidateSelf()重新绘制 调用Drawable自身draw()

5>最后抠图绘制到屏幕上 抠图api  Gravity.apply(......)
 //从一个已有的bounds矩形边界范围中抠出一个矩形r
                Gravity.apply(
                        gravity,//从左边还是右边开始抠
                        w,//目标矩形的宽
                        h, //目标矩形的高
                        bounds, //被抠出来的rect
                        r);//目标rect

                canvas.save();//保存画布
                canvas.clipRect(r);//切割
                mUnselectedDrawable.draw(canvas);//画
                canvas.restore();//恢复之前保存的画布

完整代码:

RevealDrawable.java

package com.dn_alan.myapplication;

import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.Gravity;

public class RevealDrawable extends Drawable {

    private static final String TAG = "Reveal";
    private final Rect mTmpRect = new Rect();
    private Drawable mUnselectedDrawable;
    private Drawable mSelectedDrawable;
    private int mOrientation;
    public static final int HORIZONTAL = 1;
    public static final int VERTICAL = 2;

    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
            /**
             * 将画板切割成两块-左边和右边
             */
            final Rect r = mTmpRect;
            //得到当前自身Drawable的矩形区域
            Rect bounds = getBounds();
            {
                //1.先绘制灰色部分
                //level 0~5000~10000
                //比例
                //4680 / 5000   -1f
                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();//恢复之前保存的画布
            }
            {
                //2.再绘制彩色部分
                //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);
        Log.d(TAG, "w = " + bounds.width());
    }

    @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 i) {

    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {

    }

    @SuppressLint("WrongConstant")
    @Override
    public int getOpacity() {
        return 0;
    }
}
GallaryHorizonalScrollView.java
package com.dn_alan.myapplication;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class GallaryHorizonalScrollView extends HorizontalScrollView implements OnTouchListener {
	private static final String TAG = "scrollView";
	private LinearLayout container;
	private int centerX;
	private int icon_width;

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

	public GallaryHorizonalScrollView(Context context) {
		super(context);
		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);
	}
	
	@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);
		icon_width = v.getWidth();
		Log.d(TAG, "icon_width = " + icon_width);
		//得到hzv的中间x坐标
		centerX = getWidth()/2;
		Log.d(TAG, "centerX = " + centerX);
		//处理下,中心坐标改为中心图片的左边界
		centerX = centerX - icon_width/2;
		//给LinearLayout和hzv之间设置边框距离
		container.setPadding(centerX, 0, centerX, 0);
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		if(event.getAction()== MotionEvent.ACTION_MOVE){
			//渐变图片
			reveal();
		}
		
		return false;
	}
	
	private void reveal() {
		// 渐变效果
		//得到hzv滑出去的距离
		int scrollX = getScrollX();
		Log.d(TAG, scrollX + "");
		//找到两张渐变的图片的下标--左,右
		int index_left = scrollX/icon_width;
		Log.d(TAG, index_left + "index_left");
		int index_right = index_left + 1;
		//设置图片的level
		for (int i = 0; i < container.getChildCount(); i++) {
			if(i==index_left||i==index_right){
				//变化
				//比例:

				float ratio = 5000f/icon_width;
				ImageView iv_left = (ImageView) container.getChildAt(index_left);
				//scrollX%icon_width:代表滑出去的距离
				//滑出去了icon_width/2  icon_width/2%icon_width
				iv_left.setImageLevel(
						//代表的是,我滑动之后的距离在5000份当中的份额
								(int)(5000-scrollX%icon_width*ratio)
						);
				//右边
				if(index_right<container.getChildCount()){
					ImageView iv_right = (ImageView) container.getChildAt(index_right);
					//scrollX%icon_width:代表滑出去的距离
					//滑出去了icon_width/2  icon_width/2%icon_width
					iv_right.setImageLevel(
							(int)(10000-scrollX%icon_width*ratio)
							);
				}
			}else{
				//灰色
				ImageView iv = (ImageView) container.getChildAt(i);
				iv.setImageLevel(0);
			}
		}
	}

	//添加图片的方法
	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);
	}

}
MainActivity.java
package com.dn_alan.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.widget.ImageView;

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

            R.drawable.avft,
            R.drawable.box_stack,
            R.drawable.bubble_frame,
            R.drawable.bubbles,
            R.drawable.bullseye,
            R.drawable.circle_filled,
            R.drawable.circle_outline
    };
    private int[] mImgIds_active = new int[]{
            R.drawable.avft_active, R.drawable.box_stack_active, R.drawable.bubble_frame_active,
            R.drawable.bubbles_active, R.drawable.bullseye_active, R.drawable.circle_filled_active,
            R.drawable.circle_outline_active,
            R.drawable.avft_active, R.drawable.box_stack_active, R.drawable.bubble_frame_active,
            R.drawable.bubbles_active, R.drawable.bullseye_active, R.drawable.circle_filled_active,
            R.drawable.circle_outline_active
    };

    public Drawable[] revealDrawables;
    protected int level = 5000;
    private GallaryHorizonalScrollView hzv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
    }

    private void initView() {
        hzv = (GallaryHorizonalScrollView) findViewById(R.id.hsv);
    }

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

        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;
        }
        hzv.addImageViews(revealDrawables);
    }


}

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页