您的位置:首页 > 移动开发 > Android开发

android模仿支付宝生活圈下拉加载控件TriangleLoadingView

2015-11-17 00:18 537 查看

前言

之前看到支付宝做的loading的效果感觉很棒的UI设计,于是就来模仿一个,模仿的效果一般。

支付宝的loading的效果朋友们可以自己看看,这里就不放出来了,下面是loading的模样



正题

先上一张模仿之后的效果图



现在开始我的模仿的一个想法和,首先是要对于这个形状进行模仿,由于是一个六边形,其中包含六个三角形

对于三角形的绘制,由于三角形里面还有一层扇形,同时三角形属于圆角三角形,所以必须注意各个点的绘制。弧形绘制的时候采用的赛贝尔曲线绘制的,渐变利用linearGradient,主要的方法是利用path进行路径绘制,图形如下:



初始化顶点主要方法是在TriangleLoadingView.java里面的方法中进行的,只要确定了六个顶点,那么其余的点都好计算。

protected void initTopPoints(int x, int y) {
topPoints = new int[TRIANGLE_NUM][2];
topPoints[0][0] = x - DISTANCE / 2;
topPoints[0][1] = y;
topPoints[1][0] = (int) (topPoints[0][0] - LENGTH * SIN60) - DISTANCE;
topPoints[1][1] = topPoints[0][1] + LENGTH / 2 + DISTANCE;
topPoints[2][0] = topPoints[1][0] + DISTANCE;
topPoints[2][1] = topPoints[1][1] + LENGTH + DISTANCE;
topPoints[3][0] = topPoints[0][0] + DISTANCE + DISTANCE / 2;
topPoints[3][1] = topPoints[0][1] + LENGTH * 2 + DISTANCE * 2;
topPoints[4][0] = (int) (topPoints[2][0] + 2 * LENGTH * SIN60) + 2 * DISTANCE;
topPoints[4][1] = topPoints[2][1] - DISTANCE;
topPoints[5][0] = (int) (topPoints[1][0] + 2 * LENGTH * SIN60) + 2 * DISTANCE + DISTANCE / 2;
topPoints[5][1] = topPoints[1][1] - DISTANCE;
}


在Triangle.java里面实现了绘制三角形的方法,主要计算四个点(三个顶点加一个扇形的角点)由于考虑到不能不断的计算移动或旋转时候的位置点,所以,采用的解决方法是,在六个主要顶点绘制相同大小方向角度的三角形,然后通过canvas.rotate的方式来进行绘制,这样绘制的效果更佳。主要方法是drawSelf()这个方法

public class Triangle{
public final static float TAN30 = 0.5773f;
public final static int SHIFT = -TriangleLoadingView.HEIGHT_DEFAULT;
private int dev = SHIFT;
private int ax;
private int ay;
private int bx;
private int by;
private int cx;
private int cy;
private int dx;
private int dy;
private int bgColor, topColor;
private Path path;
private int length = 40;
private int rotateDegree;
private int rate = 3;
private LinearGradient linearGradient;

public Triangle(int bx, int by, int rotateDegree, int topColor, int bgColor) {
this.length = TriangleLoadingView.LENGTH;
this.rate = 3 * length / 40;
this.ax = bx - length;
this.ay = by;
this.bx = bx;
this.by = by;
this.cx = bx;
this.cy = (int) (by + length * TAN30);
this.dx = bx - (cy - by);
this.dy = (int) (by + (cy - by) * TAN30);
this.bgColor = bgColor;
this.topColor = topColor;
this.rotateDegree = rotateDegree;
path = new Path();
linearGradient = new LinearGradient(bx, by, dx, dy, topColor, bgColor, Shader.TileMode.CLAMP);
}

public void drawSelf(Canvas canvas, Paint paint){
paint.setColor(bgColor);
path.moveTo(ax + rate, ay);
path.lineTo(bx - rate, by);
path.quadTo(bx, by, cx, by + rate);
path.lineTo(cx, cy - rate);
path.quadTo(cx, cy, cx - rate, cy - rate * TAN30);
path.quadTo(ax, ay, ax + rate, ay);
path.close();
canvas.save();
canvas.translate(0, dev);
canvas.rotate(rotateDegree, bx, by);
canvas.drawPath(path, paint);
path.reset();
path.moveTo(cx, cy - rate);
path.lineTo(cx, by + rate / 2);
path.quadTo(cx - length * TAN30 * TAN30, by, cx - length * TAN30 * TriangleLoadingView.SIN60, cy - length * TAN30 * 0.5f);
path.lineTo(cx - rate, cy - rate * TAN30);
path.quadTo(cx, cy, cx, cy - rate);
path.close();
paint.setShader(linearGradient);
paint.setColor(Color.GRAY);
canvas.drawPath(path, paint);
canvas.restore();
paint.setShader(null);
}

public void moveVertically(int des){
dev = des;
}

public void moveUp(){
dev -= 3;
}

}
完成了图形的模样之后,接着是三角形的移动,移动主要是根据你的滑动距离来进行的,在Triangle绘制的时候让Canvas.translate()一个偏移量,这样就可以达到一个移动的效果,同时又不用改变三角形的所有点的坐标。接着就是一些边缘的判断和一些特殊情况的处理。

在这个项目进行当中遇到的一个问题就对于一个View的一个default大小应该怎么设置的问题,如果对于View的初始化有一定的了解,那么相信这个问题应该是不难解决的,主要的方法在于重写onMeasure()这个方法,然后使得View具有默认的大小。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = measureDimension(WIDTH_DEFAULT, widthMeasureSpec);
int height = measureDimension(HEIGHT_DEFAULT, heightMeasureSpec);
setMeasuredDimension(width, height);
}

public int measureDimension(int defaultSize, int measureSpec) {
int result;

int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);

if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = defaultSize;   //UNSPECIFIED
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}


如果对于这个项目有兴趣,也想了解下里面的实现的话,可以下载下源码源码在github上
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: