转载请注明出处:王亟亟的大牛之路
上周5因为要出去玩所以礼拜4基本没干活然后写了个垃圾桶的demo觉得蛮好玩的,准备做的深一点,但是文章还是一篇一篇发,省的有些小伙伴搞不清楚实现
还是先安利,地址如下:https://github.com/ddwhan0123/Useful-Open-Source-Android 最近把Rx和下拉刷新做了细分,方便大家查”裤”
先看下运行效果
就是一个垃圾桶然后用户点击按钮之后 盖子盖上去(可以用到项目里那种拖动到垃圾桶删除的效果)
首先讲下实现思路
首先我在https://icomoon.io/app/#/select里找了个垃圾桶的icon然后照着那个样子考虑我该怎么画(这网站还是不错的,不过现在都用iconfont了吧?)
因为 垃圾桶的桶身部分是不需要动画的,所以就先画桶身再画桶盖,桶盖用ValueAnimator
解决旋转问题就好了
知识点
要画自定义控件,首先要知道view的绘画流程,具体理论知识就不说了以前说过,这里再点下
要自定义View 你要先实现onMeasure
再是onDraw
onMeasure决定尺寸 onDraw决定具体ui展现
如果你是viewgroup的话还需要再实现onLayout
来操作子视图间的位置关系
安卓的坐标系,跟我们数学的数轴不太一样,数轴有4个象限,而安卓只有一个。
屏幕左上角为(0,0)点,那右下角必然是最大点了。
越向右 x越大,越向下y越大。
ok,简单的道理讲完了,就开始贴代码看吧
代码实现
public class GabageCan extends View {
private Paint paint;
private Path path;
private int viewWidth, viewHeight, picWidth, picHeight;
private Float canBAnimProgress;
private ValueAnimator animator;
public GabageCan(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public GabageCan(Context context) {
super(context);
init();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(getResources().getColor(R.color.colorAccent));
//设置画笔
paint.setStrokeWidth(5f);
// canvas.drawColor(Color.WHITE);
//创建下半部分的路径和三条线
createCanBPath();
//画路径和线
canvas.drawPath(path, paint);
//动画判断是否刷新视图
if (animator != null && animator.isRunning()) {
//动画执行过程中具体帧值
canBAnimProgress = (Float) animator.getAnimatedValue();
drawCan(0, canvas);
drawCan(1, canvas);
drawCan(2, canvas);
invalidate();
} else if (animator != null && !animator.isRunning()) {
drawCan(1, canvas);
drawCan(2, canvas);
}
}
public void startAnimator() {
animator = ValueAnimator.ofFloat(1f, 0f);
animator.setDuration(2000);
animator.start();
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMySize(100, widthMeasureSpec);
int height = getMySize(100, heightMeasureSpec);
if (width < height) {
height = width;
} else {
width = height;
}
setMeasuredDimension(width, height);
Log.d("--->", "width " + width + " height " + height);
viewWidth = width > 0 ? width : 0;
viewHeight = height > 0 ? height : 0;
if (viewWidth > 0) {
picWidth = viewWidth / 3;
}
if (viewHeight > 0) {
picHeight = viewHeight / 3;
}
}
//初始化画笔
private void init() {
paint = new Paint();
path = new Path();
paint.setStyle(Paint.Style.STROKE);
}
private void drawCan(int type, Canvas canvas) {
switch (type) {
case 0:
canvas.rotate(canBAnimProgress * 30, viewWidth / 2 + (picHeight / 2), viewHeight / 2 - (picWidth / 2));
break;
case 1:
canvas.drawLine(viewWidth / 2 - (picWidth / 2) - 20, viewHeight / 2 - (picWidth / 2) - (picHeight / 8),
viewWidth / 2 + (picHeight / 2) + 20, viewHeight / 2 - (picWidth / 2) - (picHeight / 8), paint);
break;
case 2:
canvas.drawRect(viewWidth / 2 - (picWidth / 9), viewHeight / 2 - (picWidth / 2) - (picHeight / 4), viewWidth / 2 + (picHeight / 9),
viewHeight / 2 - (picHeight / 2) - (picHeight / 8), paint);
break;
case 3:
break;
}
}
private void createCanBPath() {
if (path == null) {
path = new Path();
}
//画轮廓
path.moveTo(viewWidth / 2 - (picWidth / 2), viewHeight / 2 - (picWidth / 2));
path.lineTo(viewWidth / 2 - (picWidth / 3), viewHeight / 2 + (picHeight / 2));
path.lineTo(viewWidth / 2 + (picHeight / 3), viewHeight / 2 + (picHeight / 2));
path.lineTo(viewWidth / 2 + (picHeight / 3), viewHeight / 2 + (picHeight / 2));
path.lineTo(viewWidth / 2 + (picHeight / 2), viewHeight / 2 - (picWidth / 2));
//画里面的竖线
path.moveTo(viewWidth / 2 - (picWidth / 5), viewHeight / 2 - (picWidth / 3));
path.lineTo(viewWidth / 2 - (picWidth / 5), viewHeight / 2 + (picHeight / 3));
path.moveTo(viewWidth / 2 + (picWidth / 5), viewHeight / 2 - (picWidth / 3));
path.lineTo(viewWidth / 2 + (picWidth / 5), viewHeight / 2 + (picHeight / 3));
path.moveTo(viewWidth / 2, viewHeight / 2 - (picWidth / 3));
path.lineTo(viewWidth / 2, viewHeight / 2 + (picHeight / 3));
}
private int getMySize(int defaultSize, int measureSpec) {
int mySize = defaultSize;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
switch (mode) {
case MeasureSpec.UNSPECIFIED: {//如果没有指定大小,就设置为默认大小
mySize = defaultSize;
break;
}
case MeasureSpec.AT_MOST: {//如果测量模式是最大取值为size
//我们将大小取最大值,你也可以取其他值
mySize = size;
break;
}
case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改变它
mySize = size;
break;
}
}
return mySize;
}
}
整体实现不难,只是提供个思路吧,写着玩,哈哈哈哈
源码地址:https://github.com/ddwhan0123/BlogSample/blob/master/GabageCan.class
之后可能写个拽入垃圾桶的动画,到时候再说吧。。。
作者:ddwhan0123 发表于2016/12/19 17:57:04 原文链接
阅读:381 评论:1 查看评论