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

前言

之前看到支付宝做的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上



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值