自定义view防支付成功页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?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> |
效果图:
最后,关注【码上加油站】微信公众号后,有疑惑有问题想加油的小伙伴可以码上加入社群,让我们一起码上加油吧!!!
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步