Android自定义之仿支付宝支付成功、失败状态的加载进度
2016-10-24 19:30
627 查看
话说今天就是传说中的1024,程序员的节日,在这个重大的节日里我决定撸一篇博文压压惊。今天实现的效果是仿支付宝支付时的几种状态效果,首先是Material Design风格的小圆圈在不停的旋转,当支付成功后,会出现一个带动画效果的对勾,反之,一个大红叉子呈现在你面前,这就尴尬了。。
先看下效果图
对于自定义view前面也写了很多篇了,这里就不再啰嗦了,关于自定义view的步骤请移驾查看前几篇博文,理论+实践,相信你能有所收获。
先看下效果图
对于自定义view前面也写了很多篇了,这里就不再啰嗦了,关于自定义view的步骤请移驾查看前几篇博文,理论+实践,相信你能有所收获。
自定义属性
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MdStyleProgress"> <attr name="progress_color" format="color"/> <attr name="progress_width" format="dimension"/> <attr name="radius" format="dimension"/> </declare-styleable> </resources>
还是把整个自定义view的类贴出来吧,方便大家浏览,其中对勾和叉号动画,我采用的是属性动画来实现的,并通过AnimatorSet实现将多个动画组合到一起,关于属性动画相关的知识点,可以到郭婶的博客中去,写的比较详细,什么??你不愿意去翻,那好吧,我把地址贴过来吧,郭婶讲属性动画
public class MdStyleProgress extends View { private static final int PROGRESS_COLOR = Color.parseColor("#10a679"); private static final int PROGRESS_WIDTH = 3; private static final int RADIUS = 30; private int mProgressColor = PROGRESS_COLOR; private int mProgressWidth = dp2px(PROGRESS_WIDTH); private int mRadius = dp2px(RADIUS); private Paint progressPaint; private int rotateDelta = 4; private int curAngle = 0; private int minAngle = -90; private int startAngle = -90; private int endAngle = 120; private Path path; private Status mStatus = Status.Loading; private float lineValueLeft;//左边对勾 private float lineValueRight;//右边对勾 private float failLineFirst;//叉号 private float failLineSecond; public MdStyleProgress(Context context) { this(context,null); } public MdStyleProgress(Context context, AttributeSet attrs) { this(context, attrs,0); } public MdStyleProgress(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //获取自定义属性 TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.MdStyleProgress); int indexCount = typedArray.getIndexCount(); for (int i=0;i<indexCount;i++){ int attr = typedArray.getIndex(i); switch (attr){ case R.styleable.MdStyleProgress_progress_color: mProgressColor = typedArray.getColor(attr,PROGRESS_COLOR); break; case R.styleable.MdStyleProgress_progress_width: mProgressWidth = (int) typedArray.getDimension(attr,mProgressWidth); break; case R.styleable.MdStyleProgress_radius: mRadius = (int) typedArray.getDimension(attr,mRadius); break; } } //回收TypedArray对象 typedArray.recycle(); //设置画笔 setPaint(); path = new Path(); path.moveTo(mRadius/2,mRadius); path.lineTo(mRadius,mRadius+mRadius/2); path.lineTo(mRadius+mRadius/2,mRadius/2); } private void setPaint() { progressPaint = new Paint(); progressPaint.setAntiAlias(true); progressPaint.setDither(true); progressPaint.setColor(mProgressColor); progressPaint.setStyle(Paint.Style.STROKE); progressPaint.setStrokeWidth(mProgressWidth); progressPaint.setStrokeCap(Paint.Cap.ROUND); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize; int heightSize; if(widthMode != MeasureSpec.EXACTLY){ widthSize = getPaddingLeft() + mProgressWidth + mRadius*2 + getPaddingRight(); widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize,MeasureSpec.EXACTLY); } if(heightMode != MeasureSpec.EXACTLY){ heightSize = getPaddingTop() + mProgressWidth + mRadius*2 + getPaddingBottom(); heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize,MeasureSpec.EXACTLY); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.translate(getPaddingLeft(),getPaddingTop()); if(mStatus == Status.Loading){ if (startAngle == minAngle) { endAngle += 6; } if (endAngle >= 300 || startAngle > minAngle) { startAngle += 6; if(endAngle > 20) { endAngle -= 6; } } if (startAngle > minAngle + 300) { minAngle = startAngle; endAngle = 20; } canvas.rotate(curAngle += rotateDelta,mRadius,mRadius);//旋转rotateDelta=4的弧长 canvas.drawArc(new RectF(0,0,mRadius*2,mRadius*2),startAngle,endAngle,false,progressPaint); invalidate(); }else if(mStatus == Status.LoadSuccess){ canvas.drawArc(new RectF(0,0,mRadius*2,mRadius*2),startAngle,360,false,progressPaint); //canvas.drawPath(path,progressPaint); //画圆圈中的对勾 canvas.drawLine(mRadius/2,mRadius,mRadius/2+lineValueLeft,mRadius+lineValueLeft,progressPaint); canvas.drawLine(mRadius,mRadius+mRadius/2,mRadius+lineValueRight,mRadius+mRadius/2-1.5f*lineValueRight,progressPaint); }else { canvas.drawArc(new RectF(0,0,mRadius*2,mRadius*2),startAngle,360,false,progressPaint); //画圆圈中的叉号(画右边叉号的时候,终止位置的x坐标为起始x位置减去failLineFirst,而failLineFirst在属性动画中的取值范围是0-mRadius) canvas.drawLine(mRadius+mRadius/2,mRadius/2,mRadius*3/2-failLineFirst,mRadius/2+failLineFirst,progressPaint); canvas.drawLine(mRadius/2,mRadius/2,mRadius/2+failLineSecond,mRadius/2+failLineSecond,progressPaint); } canvas.restore(); } public enum Status{ Loading, LoadSuccess, LoadFail } public void startAnima(){ //对勾左边线的属性动画 ValueAnimator animatorLeft = ValueAnimator.ofFloat(0f,mRadius/2f); animatorLeft.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { lineValueLeft = (float) animation.getAnimatedValue(); Log.i("lineValueLeft",lineValueLeft+""); invalidate();//重绘,调onDraw()重绘 } }); //对勾右边线的属性动画 ValueAnimator animatorRight = ValueAnimator.ofFloat(0f,mRadius/2f); animatorRight.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { lineValueRight = (float) animation.getAnimatedValue(); Log.i("lineValueRight",lineValueRight+""); invalidate(); } }); //将多个动画组合到一起需要借助AnimatorSet这个类 final AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(animatorRight).after(animatorLeft); animatorSet.setDuration(150); animatorSet.start(); } public void failAnima(){ ValueAnimator failOne = ValueAnimator.ofFloat(0f,mRadius); failOne.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { failLineFirst = (float) animation.getAnimatedValue(); invalidate(); } }); ValueAnimator failOther = ValueAnimator.ofFloat(0f,mRadius); failOther.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { failLineSecond = (float) animation.getAnimatedValue(); invalidate(); } }); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.play(failOther).after(failOne); animatorSet.setDuration(150); animatorSet.start(); } public Status getStatus() { return mStatus; } public void setStatus(Status mStatus) { this.mStatus = mStatus; invalidate(); } /** * dp 2 px */ protected int dp2px(int dpVal) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, getResources().getDisplayMetrics()); } /** * sp 2 px */ protected int sp2px(int spVal) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, getResources().getDisplayMetrics()); } }
xml布局文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.mdstyleprogress.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:layout_marginTop="30dp" android:orientation="horizontal"> <!--<Button android:id="@+id/loading" android:layout_width="0dp" android:layout_height="match_parent" android:text="还原" android:layout_marginRight="5dp" android:layout_weight="1"/>--> <Button android:id="@+id/success" android:layout_width="0dp" android:layout_height="match_parent" android:text="成功" android:layout_marginRight="5dp" android:layout_weight="1"/> <Button android:id="@+id/fail" android:layout_width="0dp" android:layout_height="match_parent" android:text="失败" android:layout_weight="1"/> </LinearLayout> <com.example.mdstyleprogress.MdStyleProgress android:id="@+id/progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:padding="10dp" /> </RelativeLayout>
最后是我们的MainActivity调用
public class MainActivity extends AppCompatActivity { private MdStyleProgress progress; private Button btnLoading,btnSuccess,btnFail; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); progress = (MdStyleProgress) findViewById(R.id.progress); //btnLoading = (Button) findViewById(R.id.loading); btnSuccess = (Button) findViewById(R.id.success); btnFail = (Button) findViewById(R.id.fail); /*btnLoading.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(progress.getStatus() != MdStyleProgress.Status.Loading){ progress.setStatus(MdStyleProgress.Status.Loading); } } });*/ //成功状态 btnSuccess.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(progress.getStatus() != MdStyleProgress.Status.LoadSuccess){ progress.setStatus(MdStyleProgress.Status.LoadSuccess); progress.startAnima(); } } }); //失败状态 btnFail.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(progress.getStatus() != MdStyleProgress.Status.LoadFail){ progress.setStatus(MdStyleProgress.Status.LoadFail); progress.failAnima(); } } }); } }
代码中已经注释的很清楚了,其中叉号的实现不是很漂亮,略显长,可适当调整下叉号的坐标值即可,这里我就不再微调了,关于坐标的计算如果有看不懂的,欢迎提出,也可以自己下载demo,断点调试下就明白了,随后即将源码奉上。1024送你一个漂亮的加载进度条。
相关文章推荐
- Android自定义View系列之Path绘制仿支付宝支付成功动画
- Android自定义dialog实现支付宝支付成功样式
- Android自定义View实现支付宝支付成功-极速get花式Path炫酷动画
- Android--判断发送短信后的状态/发送成功Or发送失败
- 【android】自定义ProgressDialog实现暂时隐藏进度值并显示等待状态(附源码下载)
- Android 自定义View修炼-自定义加载进度动画XCLoadingImageView
- android界面之美---自定义网络请求进度加载对话框
- android:Activity中切换不同状态页:加载中,加载失败,数据页,空页面……
- Android--自定义标题栏之显示网页加载进度
- Android--判断发送短信后的状态/发送成功Or发送失败
- Android 浏览网页:WebView 嵌入浏览器(浏览历史返回、自定义加载失败界面、支持缩放、获取标题栏)
- Android自定义View二(加载进度动画)
- Android项目中使用自定义进度加载Dialog
- android webview 加载进度和自定义404错误页面
- android 加载webview 自定义 失败页面
- Android--自定义标题栏之显示网页加载进度
- Android之加载图片时自定义进度条
- Android项目中使用自定义进度加载Dialog
- magento 支付宝模块 当支付成功时在哪里更改订单状态的
- 完美解决Android的WebView加载失败(404,500),显示的自定义视图