package com.loaderman.customviewdemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View; import static com.loaderman.customviewdemo.AlipayView.State.FINISH;
import static com.loaderman.customviewdemo.AlipayView.State.IDLE; /**
* Created by MQ on 2017/1/20.
*/ public class AlipayView extends View {
private Paint mPaint;
private RectF mRectF;
private int mCenterX, mCenterY;
private State state = IDLE;
private int firstProgress;//第一个圆弧进度
private int secondProgress;//第二个圆弧进度
private Path mPath;
private boolean isEndPay;//是否支付完成
private Line firstLine;//对勾第一条线
private Line secondLine;//对勾第二条线
private float lineProgress;//打对勾的进度
private int sweepLength;//正在支付状态的圆弧长度
private float xDis3to1, xDis2to1;//xDis3to1为对勾的横向长度 xDis2to1为第二个坐标到第一个坐标的横向长度
private float x1, y1, x2, y2, x3, y3;//构成对勾的3个坐标(x1,y1)(x2,y2)(x3,y3) private int radius = 150;//旋转圆的半径(修改此值可以改变圆的大小)
private float increaseDis = 10f;//对勾增长速率(修改此值可以改变打对勾的速率)
private float circleIncRate = 10f;//圆圈增长速率(修改此值可以改变画圆的速率)
private int sweepMaxAngle = 200;//正在支付状态的最大圆弧长度(修改此值可以改变最大圆弧的长度) public AlipayView(Context context) {
this(context, null);
} public AlipayView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public AlipayView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
} private void init() {
//初始化画笔
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(10f);
mPaint.setColor(getResources().getColor(R.color.holo_blue_light));
//绘制范围
mRectF = new RectF();
mPath = new Path();
} @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mCenterX = w / 2;
mCenterY = h / 2;
x1 = mCenterX - radius / 3 * 2;
y1 = mCenterY + radius / 8;
x2 = mCenterX - radius / 5;
y2 = mCenterY + radius / 3 * 2;
x3 = mCenterX + radius / 4 * 3;
y3 = mCenterY - radius / 4;
firstLine = new Line(new PointF(x1, y1), new PointF(x2, y2));
secondLine = new Line(new PointF(x2, y2), new PointF(x3, y3));
xDis3to1 = x3 - x1;
xDis2to1 = x2 - x1;
} @Override
protected void onDraw(Canvas canvas) {
mRectF.set(mCenterX - radius, mCenterY - radius, mCenterX + radius, mCenterY + radius);
switch (state) {
case IDLE:
canvas.drawArc(mRectF, -90f, 360f, false, mPaint);
mPath.moveTo(firstLine.startPoint.x, firstLine.startPoint.y);
mPath.lineTo(firstLine.endPoint.x, firstLine.endPoint.y);
mPath.lineTo(secondLine.endPoint.x, secondLine.endPoint.y);
canvas.drawPath(mPath, mPaint);
break;
case PROGRESS:
//支付中
canvas.drawArc(mRectF, -90f + firstProgress, sweepLength, false, mPaint);
secondProgress += circleIncRate;
if (secondProgress < sweepMaxAngle) {
firstProgress = 0;
sweepLength += circleIncRate;
} else if (secondProgress >= sweepMaxAngle && secondProgress <= 360) {
firstProgress = secondProgress - sweepMaxAngle;
sweepLength = sweepMaxAngle;
} else if (secondProgress > 360) {
if (sweepLength > 0) {
firstProgress += circleIncRate;
sweepLength -= circleIncRate;
} else {
// canvas.drawArc(mRectF, -89f, 1f, false, mPaint);
reset();
if (isEndPay) {
state = FINISH;
}
postInvalidateDelayed(200);
break;
}
}
invalidate();
break;
case FINISH:
//支付完成
mPath.reset();
if (secondProgress < 360) {
float sweepAngle = secondProgress;
canvas.drawArc(mRectF, -90f, sweepAngle, false, mPaint);
secondProgress += circleIncRate;
invalidate();
} else {
canvas.drawArc(mRectF, -90f, 360f, false, mPaint);
mPath.moveTo(firstLine.startPoint.x, firstLine.startPoint.y);
float lineX = x1 + lineProgress;
if (lineProgress < xDis2to1) {
//绘制第一条线
mPath.lineTo(lineX, firstLine.getY(lineX));
invalidate();
} else if (lineProgress >= xDis2to1 && lineProgress < xDis3to1) {
//绘制第二条线
mPath.lineTo(firstLine.endPoint.x, firstLine.endPoint.y);
mPath.lineTo(lineX, secondLine.getY(lineX));
invalidate();
} else {
//全部画完
mPath.lineTo(firstLine.endPoint.x, firstLine.endPoint.y);
mPath.lineTo(secondLine.endPoint.x, secondLine.endPoint.y);
}
lineProgress += increaseDis;
canvas.drawPath(mPath, mPaint);
}
break;
}
} private void reset() {
firstProgress = 0;
secondProgress = 0;
sweepLength = 0;
lineProgress = 0;
} enum State {
IDLE,
PROGRESS,
FINISH
} public void setState(State state) {
this.state = state;
invalidate();
} public void setOverPay(boolean endPay) {
isEndPay = endPay;
} class Line {
PointF startPoint;
PointF endPoint; float k;//比例系数
float b;//常数 Line(PointF startPoint, PointF endPoint) {
this.startPoint = startPoint;
this.endPoint = endPoint; k = (endPoint.y - startPoint.y) / (endPoint.x - startPoint.x);
b = startPoint.y - k * startPoint.x;
} float getY(float x) {
return k * x + b;
}
}
}

MainActivity.java

package com.loaderman.customviewdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button; public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private AlipayView alipay_view;
private Button btn_start_pay, btn_end_pay;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
alipay_view = (AlipayView) findViewById(R.id.alipay_view);
alipay_view.setState(AlipayView.State.IDLE);
btn_start_pay = (Button) findViewById(R.id.btn_start_pay);
btn_end_pay = (Button) findViewById(R.id.btn_end_pay);
btn_start_pay.setOnClickListener(this);
btn_end_pay.setOnClickListener(this);
} @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start_pay:
alipay_view.setOverPay(false);
alipay_view.setState(AlipayView.State.PROGRESS);
break;
case R.id.btn_end_pay:
alipay_view.setOverPay(true);
break;
}
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.loaderman.customviewdemo.MainActivity"> <com.loaderman.customviewdemo.AlipayView
android:id="@+id/alipay_view"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
<Button
android:id="@+id/btn_start_pay"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="开始支付"/> <Button
android:id="@+id/btn_end_pay"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="支付完成"/> </LinearLayout>

效果图:

自定义view防支付成功页面的更多相关文章

  1. 手把手带你做一个超炫酷loading成功动画view Android自定义view

    写在前面: 本篇可能是手把手自定义view系列最后一篇了,实际上我也是一周前才开始真正接触自定义view,通过这一周的练习,基本上已经熟练自定义view,能够应对一般的view需要,那么就以本篇来结尾 ...

  2. 到处都是坑的微信支付V3之 微信支付回调页面

    据上次 到处都是坑的微信支付V3 后很多园友在被虐了千百遍后终于跳转到了亲切的微信支付界面,但输入密码支付后却不知道怎么处理了,接下来补上支付后的处理流程. 1. html中根据前台支付后反馈信息成功 ...

  3. Thinkphp框架中自定义修改success和error页面

    Thinkphp框架中自定义修改success和error页面 Thinkphp框架的默认success和error太难看,可以自定义设置,步骤如下: (注意:TP原框架中的success跳转有问题, ...

  4. JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(四):自定义T4模板快速生成页面

    前言:上篇介绍了下ko增删改查的封装,确实节省了大量的js代码.博主是一个喜欢偷懒的人,总觉得这些基础的增删改查效果能不能通过一个什么工具直接生成页面效果,啥代码都不用写了,那该多爽.于是研究了下T4 ...

  5. salesforce 零基础学习(五十)自定义View或者List以及查看系统原来的View或者List

    salesforce给我们提供了标准的页面,比如标准的页面包括标准的列表和标准的详细页视图.有的时候我们想要自定义视图,比如做一个项目的时候不希望使用者直接通过ID查看到标准的详细页,而是跳转到指定处 ...

  6. Dialog详解(包括进度条、PopupWindow、自定义view、自定义样式的对话框)

    Dialog详解(包括进度条.PopupWindow.自定义view.自定义样式的对话框)   Android中提供了多种对话框,在实际应用中我们可能会需要修改这些已有的对话框.本实例就是从实际出发, ...

  7. Android 自定义View合集

    自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...

  8. Android自定义View的实现方法,带你一步步深入了解View(四)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17357967 不知不觉中,带你一步步深入了解View系列的文章已经写到第四篇了,回 ...

  9. [原] Android 自定义View步骤

    例子如下:Android 自定义View 密码框 例子 1 良好的自定义View 易用,标准,开放. 一个设计良好的自定义view和其他设计良好的类很像.封装了某个具有易用性接口的功能组合,这些功能能 ...

随机推荐

  1. Spring框架中<mvc:default-servlet-handler/>的作用

    优雅REST风格的资源URL不希望带 .html 或 .do 等后缀.由于早期的Spring MVC不能很好地处理静态资源,所以在web.xml中配置DispatcherServlet的请求映射,往往 ...

  2. ip正则

    IP地址是指互联网协议地址(英语:Internet Protocol Address,又译为网际协议地址),是IP Address的缩写.IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一 ...

  3. cmd完成拷贝文件,并生成两个快捷脚本

    @echo off@echo ------------------------------ @echo 正在创建目录 color 03if exist y:\00程序数据备份 ( md y:\00程序 ...

  4. 斐波那契数列 Java 不同的实现方法所需要的时间比较

    # 首先我们直接看一个demo以及他的结果 public class QQ { public static void main(String[] args) throws ParseException ...

  5. SSH中直接运行php文件

    cd /home/afish/domains/afish.cnblogs.com/public_htmlphp locoy_im_folder.php php locoy_im.php

  6. Codeforces 1000 组合数可行线段倒dp 边双联通缩点求树直径

    A /*Huyyt*/ #include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) using namespace std ...

  7. @AutoConfigureBefore

    @AutoConfigureBefore(Xxx.class)此注解用在类名上,标识在加载Xxx类前加载该配置类

  8. window下,nodejs安装http-server,并开启HTTP服务器

    1.下载nodejs  官方下载地址:https://nodejs.org/en/ 2.在cmd命令中,输入node -v 输入出版本号,代表安装成功. 3.输入 npm install http-s ...

  9. mysql数据库之 存储引擎、事务、视图、触发器、存储过程、函数、流程控制、数据库备份

    目录 一.存储引擎 1.什么是存储引擎? 2.mysql支持的存储引擎 3. 使用存储引擎 二.事务 三.视图 1.什么是视图 2.为什么要用视图 3.如何用视图 四.触发器 为何要用触发器 创建触发 ...

  10. buuctf@helloword