项目要求访问网络是等待状态要做时钟的样子,经过不懈努力,终于写出来了,现分享出来,功能比较全,直接拷贝代码就可以用,仅供有这种需求的码农们参考,如果采纳,请点个赞,谢谢支持。
效果图
主Activity,主要是在访问接口的时候开启时钟,接口访问结束关闭时钟。
package com.example.myapplication;
import android.graphics.Color;
import .AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final UFWaitingIndicatorView uFWaitingIndicatorView = (UFWaitingIndicatorView) findViewById(.uFWaitingIndicatorView);
findViewById(.open).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
uFWaitingIndicatorView.setTintColor(Color.WHITE);
uFWaitingIndicatorView.start();//时钟开始绘制
}
});
findViewById(.close).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
uFWaitingIndicatorView.stopAnimated(false);//停止绘制时钟
}
});
}
}
自定义时钟
package com.cccollector.magazine.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import com.cccollector.magazine.R;
import java.util.Timer;
import java.util.TimerTask;
/**
* 仿小米时钟
*/
public class UFWaitingIndicatorView extends View {
private float hourHandStartAngle;//时针当前角度
private float minuteHandStartAngle;//分针当前角度;
private float stopAnimateDuration; // 停止动画时长
private float stopAnimateProgress; // 停止动画进度,
private boolean hiddenWhenStop;//执行完之后是否隐藏;
private float minuteHandDuration;//分针一次旋转多少度;
private float speedRatio;//时针是分针的几倍速度;
private float lineWidth;//时针,分针的线段宽度;
private float hourHandCurrentAngle;//时针当前角度;;
private float minuteHandCurrentAngle;//分针当前角度;
private int refreshDuration;//定时器多久刷新一次;
private Paint paint;//画笔;
private float mRadius;//时钟半径,不包括padding值;
private Canvas mCanvas;//画布;
private Timer waitingTimer;//定时器;
private Timer stopTimer;
public UFWaitingIndicatorView(Context context) {
this(context, null);
}
public UFWaitingIndicatorView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public UFWaitingIndicatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//配置文件读出默认配置,配置的属性可以写到xml中生效;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.UFWaitingIndicatorView);
float hourHandStartAngle_attrs = a.getDimension(R.styleable.UFWaitingIndicatorView_hourHandStartAngle, 45);
float minuteHandStartAngle_attrs = a.getDimension(R.styleable.UFWaitingIndicatorView_minuteHandStartAngle, 315);
float minuteHandDuration_attrs = a.getDimension(R.styleable.UFWaitingIndicatorView_minuteHandDuration, 2000);
float speedRatio_attrs = a.getDimension(R.styleable.UFWaitingIndicatorView_speedRatio, 0.375f);
float lineWidth_attrs = a.getDimension(R.styleable.UFWaitingIndicatorView_lineWidth, 2);
paint = new Paint();//画笔;
hourHandStartAngle = 0;
minuteHandStartAngle = 0;
hiddenWhenStop = false;
minuteHandDuration = minuteHandDuration_attrs;
speedRatio = speedRatio_attrs;
lineWidth = lineWidth_attrs;
hourHandCurrentAngle = 0;
minuteHandCurrentAngle = 0;
refreshDuration = 50;
stopAnimateDuration = 1000;
stopAnimateProgress = 1000;
setTintColor(Color.parseColor("#15B300"));
}
//重写测量方法;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureDimension(widthMeasureSpec), measureDimension(heightMeasureSpec));
}
private int measureDimension(int measureSpec) {
int result;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else {
result = 260;
if (mode == MeasureSpec.AT_MOST) {
result = Math.min(result, size);
}
}
return result;
}
/**
* 重写方法得到控件的宽,即圆的半径;
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//宽和高分别去掉padding值,其中最小值为半径值
mRadius = (float)Math.min(Math.floor(w /2) , Math.floor(h / 2)) - 3;
}
/**
* 绘制
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
//画布;
mCanvas = canvas;
//线段的宽;
paint.setStrokeWidth(dip2px(getContext(),lineWidth));
mCanvas.save();//保存画布;
mCanvas.rotate(hourHandCurrentAngle, getWidth() / 2, getHeight() / 2);//以画布中心为圆点,旋转画布;
mCanvas.translate(getWidth() / 2, getHeight() / 2);
// mCanvas.drawPoint(0,0,paint);
mCanvas.drawLine(0f,0f,-(float) (mRadius / Math.sqrt(2)),-(float) (mRadius / Math.sqrt(2)),paint);//画时针;
mCanvas.restore();//复位画布;
mCanvas.save();//保存画布;
mCanvas.rotate(minuteHandCurrentAngle, getWidth() / 2, getHeight() / 2);//以画布中心为圆点,旋转画布;
mCanvas.translate(getWidth() / 2, getHeight() / 2);
// mCanvas.drawPoint(0,0,paint);
mCanvas.drawLine(0f,0f,-(float) (mRadius / Math.sqrt(2)),(float) (mRadius / Math.sqrt(2)),paint);//画分针;
mCanvas.restore();//复位画布;
}
/**
* 设置指针颜色;
* @param color
*/
public void setTintColor (int color) {
paint.reset();//让画笔的设置回到原始状态;
paint.setStrokeCap(Paint.Cap.ROUND);//设置成圆头;
//抗锯齿
paint.setAntiAlias(true);
paint.setColor(color);
//刷新(onDraw)调用重绘方法;
invalidate();
}
/**
* 设置背景颜色;
* @param color
*/
public void setBackgroundColor (int color) {
setBackgroundColor(color);
}
/**
* 设置线宽;
* @param mLineWidth
*/
public void setLineWidth (float mLineWidth) {
this.lineWidth = mLineWidth;
}
/**
* dp转换成px;
* @param context
* @param dpValue
* @return
*/
public int dip2px(Context context, float dpValue){
final float scale=context.getResources().getDisplayMetrics().density;
return (int)(dpValue*scale+0.5f);
}
/**
* 如果计时器不为空,则说明正在进行,如果为空,,没进行;
* @return
*/
public boolean started(){
if (waitingTimer != null) {
return true;
}else {
return false;
}
}
public boolean stoping () {
return waitingTimer != null && stopAnimateProgress < stopAnimateDuration;
}
/**
* 开始动画;
*/
public void start() {
// 如果已开始,则返回
if (started()) {
return;
}
// 将起始角度设为当前角度
hourHandCurrentAngle = this.hourHandStartAngle;
minuteHandCurrentAngle = this.minuteHandStartAngle;
//创建计时器;
// 初始化定时器
waitingTimer = new Timer();
waitingTimer.schedule(new TimerTask() {
@Override
public void run() {
// 计算当前角度
hourHandCurrentAngle += (refreshDuration / (minuteHandDuration / speedRatio)) * 360;
minuteHandCurrentAngle += (refreshDuration / minuteHandDuration) * 360;
mHandler.sendEmptyMessage(Timer_MESSAGE);
}
}, 0, refreshDuration);//第二个参数,延迟几秒开始第一次刷新,第三个参数,每隔几秒刷新;
}
private static final int Timer_MESSAGE =1000;
private static final int StopTimer_MESSAGE =1001;
//定时器配合handler实现,定时器子线程发送消息,handler主线程刷新界面;
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case Timer_MESSAGE:
// 刷新显示
invalidate();
Log.i("TAG", "handleMessage: "+"ting");
break;
case StopTimer_MESSAGE:
// 刷新显示
invalidate();
// if (hiddenWhenStop) {//执行完之后隐藏
// setVisibility(View.GONE);
// }
break;
}
}
};
/**
* 停止动画;
*/
public void stopAnimated(boolean animated) {
if (started()) {
//停止刷新等待计时器;。。。。。。。后面要重新开一个停止计时器;
waitingTimer.cancel();
waitingTimer = null;
}
if (animated) {
// 缩减到360度以内
hourHandCurrentAngle = (float) Math.floor(hourHandCurrentAngle - Math.floor(hourHandCurrentAngle / 360) * 360);
minuteHandCurrentAngle =(float) Math.floor(minuteHandCurrentAngle - Math.floor(minuteHandCurrentAngle / 360) * 360);
// 动画开始时的角度
final float hourHandAnimateBeginAngle = hourHandCurrentAngle;
final float minuteHandAnimateBeginAngle = minuteHandCurrentAngle;
// 动画经过的的角度
final double hourHandAnimateAngle = hourHandAnimateBeginAngle < this.hourHandStartAngle ? this.hourHandStartAngle - hourHandAnimateBeginAngle : this.hourHandStartAngle + 360 - hourHandAnimateBeginAngle;
final double minuteHandAnimateAngle = minuteHandAnimateBeginAngle < this.minuteHandStartAngle ? this.minuteHandStartAngle - minuteHandAnimateBeginAngle : this.minuteHandStartAngle + 360 - minuteHandAnimateBeginAngle;
// 初始化进度
stopAnimateProgress = 0;
//停止计时器;
stopTimer = new Timer();
stopTimer.schedule(new TimerTask() {
@Override
public void run() {
double t = stopAnimateProgress;
double d = stopAnimateDuration;//一秒之内停止进度;
// double progress = -1 * (t /= d) * (t - 2);
// double progress = (t = t / d - 1) * t * t + 1;
// double progress = -((t = t / d - 1) * t * t * t - 1);
double progress = (t = t / d - 1) * t * t * t * t + 1;
// 计算当前角度
hourHandCurrentAngle = (float) (hourHandAnimateBeginAngle + progress * hourHandAnimateAngle);
minuteHandCurrentAngle = (float) (minuteHandAnimateBeginAngle + progress * minuteHandAnimateAngle);
// 刷新显示
// invalidate();
mHandler.sendEmptyMessage(Timer_MESSAGE);
// 更新进度
stopAnimateProgress += refreshDuration;
// 如果进度大于等于时长
if (stopAnimateProgress >= stopAnimateDuration) {
hourHandCurrentAngle = 0;
minuteHandCurrentAngle = 0;
// 刷新显示
// invalidate();
if (stopTimer != null) {
stopTimer.cancel();
stopTimer = null;
}
mHandler.sendEmptyMessage(StopTimer_MESSAGE);
}
}
},0,refreshDuration);
}else {
// 恢复初始设置
hourHandCurrentAngle = 0;
minuteHandCurrentAngle = 0;
// 刷新显示
// stopTimer.cancel();
// stopTimer = null;
mHandler.sendEmptyMessage(StopTimer_MESSAGE);
}
}
}
为了尽可能的不劳累小伙伴们,特把布局也贴上
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http:///apk/res/android"
xmlns:tools="http:///tools" android:id="@+id/activity_main"
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.myapplication.MainActivity">
<Button
android:id="@+id/open"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开启时钟" />
<Button
android:id="@+id/close"
android:layout_below="@id/open"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关闭时钟" />
<RelativeLayout
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="200dp"
android:background="@drawable/shape_pointer">
<com.example.myapplication.UFWaitingIndicatorView
android:id="@+id/uFWaitingIndicatorView"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_centerInParent="true"/>
</RelativeLayout>
</RelativeLayout>
shape_pointer 时钟椭圆形状 ,可根据需求,自己定义
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http:///apk/res/android">
<corners android:radius="6dp"/>
<solid android:color="#000000"/>
</shape>
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="UFWaitingIndicatorView">
<!--时针起始角度-->
<attr name="hourHandStartAngle" format="dimension" />
<!--分针起始角度-->
<attr name="minuteHandStartAngle" format="dimension" />
<!--分针一圈时长-->
<attr name="minuteHandDuration" format="dimension" />
<!--时针分针速度比(0~1)-->
<attr name="speedRatio" format="dimension" />
<!--线宽度-->
<attr name="lineWidth" format="dimension" />
</declare-styleable>
</resources>
到之处代码已经写完,直接拷贝到项目的对应目录就可以的,如果对你有帮助,请点赞评论,谢谢支持。