您的位置:首页 > 其它

Canvas的实际使用

2017-09-10 10:46 190 查看


这个就是一个大致的实现效果,左右滑动用的是一个自定义的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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  canvas 图片 horizon