自定义view防支付成功页面
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防支付成功页面的更多相关文章
- 手把手带你做一个超炫酷loading成功动画view Android自定义view
写在前面: 本篇可能是手把手自定义view系列最后一篇了,实际上我也是一周前才开始真正接触自定义view,通过这一周的练习,基本上已经熟练自定义view,能够应对一般的view需要,那么就以本篇来结尾 ...
- 到处都是坑的微信支付V3之 微信支付回调页面
据上次 到处都是坑的微信支付V3 后很多园友在被虐了千百遍后终于跳转到了亲切的微信支付界面,但输入密码支付后却不知道怎么处理了,接下来补上支付后的处理流程. 1. html中根据前台支付后反馈信息成功 ...
- Thinkphp框架中自定义修改success和error页面
Thinkphp框架中自定义修改success和error页面 Thinkphp框架的默认success和error太难看,可以自定义设置,步骤如下: (注意:TP原框架中的success跳转有问题, ...
- JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(四):自定义T4模板快速生成页面
前言:上篇介绍了下ko增删改查的封装,确实节省了大量的js代码.博主是一个喜欢偷懒的人,总觉得这些基础的增删改查效果能不能通过一个什么工具直接生成页面效果,啥代码都不用写了,那该多爽.于是研究了下T4 ...
- salesforce 零基础学习(五十)自定义View或者List以及查看系统原来的View或者List
salesforce给我们提供了标准的页面,比如标准的页面包括标准的列表和标准的详细页视图.有的时候我们想要自定义视图,比如做一个项目的时候不希望使用者直接通过ID查看到标准的详细页,而是跳转到指定处 ...
- Dialog详解(包括进度条、PopupWindow、自定义view、自定义样式的对话框)
Dialog详解(包括进度条.PopupWindow.自定义view.自定义样式的对话框) Android中提供了多种对话框,在实际应用中我们可能会需要修改这些已有的对话框.本实例就是从实际出发, ...
- Android 自定义View合集
自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...
- Android自定义View的实现方法,带你一步步深入了解View(四)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17357967 不知不觉中,带你一步步深入了解View系列的文章已经写到第四篇了,回 ...
- [原] Android 自定义View步骤
例子如下:Android 自定义View 密码框 例子 1 良好的自定义View 易用,标准,开放. 一个设计良好的自定义view和其他设计良好的类很像.封装了某个具有易用性接口的功能组合,这些功能能 ...
随机推荐
- BLOB和CLOB
mysql各数据类型及字节长度一览表: 数据类型 字节长度 范围或用法 Bit 1 无符号[0,255],有符号[-128,127],天缘博客备注:BIT和BOOL布尔型都占用1字节 TinyInt ...
- selenium入门学习
在写爬虫的学习过程中,经常会有一些动态加载,有些是可以动过接口直接获取到,但是实在没办法,所以学习下selenium. 首先百度一下: Selenium [1] 是一个用于Web应用程序测试的工具. ...
- Ext4文件系统修复
Ext4文件系统修复 目录 一. super block........................................................................ ...
- IO模型(epoll)--详解-02
写在前面 从事服务端开发,少不了要接触网络编程.epoll作为linux下高性能网络服务器的必备技术至关重要,大部分游戏服务器都使用到这一多路复用技术.文章核心思想是:要让读者清晰明白EPOLL为什么 ...
- xml配置文件命名空间学习
xmlns(XML Namespaces的缩写)是一个属性,是XML(标准通用标记语言的子集)命名空间.作用是赋予命名空间一个唯一的名称. 编写Spring或者Maven或者其他需要用到XML文档的程 ...
- (转)AIX中修改主机名 要注意
smit hostname改名后一个常见的问题是:hostname看到的是新名, uname -n 看到的仍是旧名.没见IBM针对改名有官方的步骤,因此共享下我多年来的一直使用的方法. 1.smit ...
- JS 转化为String的三种方法
// 1. toString() var num = 8; var numString = num.toString(); console.log(numString); var result = t ...
- Kattis - bitwise Bitwise (RMQ+尺取+树上dfs)
题意:有一个长度为n的序列,让你把它分成k段,段内元素取or,段间取and,求能够得到的最大值. 这个算法是我和xz场上yy出来的,然而时间不够了没写出来,而且时间复杂度是$O(nlogn+nlogA ...
- k8sReplicaSet控制器
一.ReplicaSet概述 简称RS,是pod控制器类型的一种实现,用于确保由其管控的pod对象副本数在任一时刻都能精确满足期望的数量.ReplicaSet控制器资源启动后会查找集群中匹配其标签选择 ...
- TOP K和Partition对比
TOP k算法适用于海量数据,不用一批装入内存.. partition算法需要全部装入内存排序,需要修改原数据..