时间:2023-02-24 09:15:44 | 栏目:Android代码 | 点击:次
Android自定义View实现APP启动页倒计时效果,供大家参考,具体内容如下
之前也是做过APP启动页的倒计时效果,但是只有文字变化,没有动画效果,这次通过使用自定义View控件来制作一个带有动画效果的倒计时。
倒计时效果的基本思路如下:
Canvas提供了绘制弧形的方法,drawArc(),使用这个方法通过定时刷新计算当前弧形的角度,就可以模拟出倒计时的动画效果,同时借助drawText()方法可以实现倒计时文字。
(1)继承View
(2)使用canvas的drawArc()来绘制弧形,模拟动画效果
(3)使用canvas的drawText()来绘制倒计时文字
(4)向外部(Activity或者Fragment)提供接口,倒计时结束之后通过接口告诉外部
具体看代码:
首先定义当前view的宽度和高度的默认值,并重写onMeasure()方法,否则在布局文件中即使使用wrap_content当前view也会布满全屏
//当前view高度和宽度的默认值 private static final int DEFAULT_WIDTH = 100; private static final int DEFAULT_HEIGHT = 100;
定义三个变量,分别是倒计时总长度,当前剩余倒计时长度,以及剩余时间比例,根据这个比例绘制弧形划过的角度
private int countDownTime = 5000;//倒计时的时间,默认是5秒 private int countDownNow = 5000;//当前的时间,默认也是5秒 private float timeTatio = 1f;//剩余时间比例,默认为1
定义画笔以及向外部提供的接口
使用Android提供的倒计时类,如果不使用这个类,也可以通过thread+handler实现,初始化这个类需要传入两个参数,第一个参数是倒计时总长度,第二个参数是倒计时间隔,也就是每隔多长时间停止一次。这个类重写了两个方法,第一个方法是倒计时暂停的时候需要执行的操作,第二个方法是倒计时完全结束之后需要执行的操作,在这里,我设置了每隔10ms暂停一次,计算剩余时间的比例并重新绘制整个view,倒计时完全结束后通过接口告诉外部。
private Paint paint; private ViewCountDownFinishListener viewCountDownFinishListener; //倒计时,每隔100毫秒倒计时一次 private CountDownTimer countDownTimer = new CountDownTimer(countDownTime,10) { @Override public void onTick(long l) { LogUtils.logI("倒计时:"+l); countDownNow = (int) l; //计算比例 timeTatio = (float) countDownNow / (float)countDownTime; invalidate(); } @Override public void onFinish() { countDownTimer.cancel(); if(viewCountDownFinishListener != null){ viewCountDownFinishListener.countDownFinish(); } } };
在构造方法中调用init()方法以启动倒计时
private void init(){ if(countDownTimer != null) { countDownTimer.start(); } }
//设置倒计时完成的接口 public void setViewCountDownFinishListener(ViewCountDownFinishListener viewCountDownFinishListener){ this.viewCountDownFinishListener = viewCountDownFinishListener; }
重写onDraw()方法,根据
canvas.drawArc(float left,float top,float right,float bottom,float startAngle,float sweepAngle,boolean useCenter, Paint paint)
参数说明:
前四个参数表明当前的弧形所在的椭圆,只要设置椭圆宽度和高度一样,就是一个圆了,
startAngle是开始绘制的角度,以正右方向(X轴正方向)为0都,顺时针为正度数,逆时针为负度数,这里我设置从-90°(也就是Y轴负方向)开始,
sweep是指弧形划过的角度,这里我设置的是从0开始一直划过360度,刚好画一个圆,但是其实并没有完全到360度,因为我设置了每隔10ms执行一次,最后并不会完全是360度,但是非常接近,几乎看不出来。
useCenter表示是否连接到圆心,如果连接到圆心,就是扇形,这里需要弧形,就选择false
绘制完弧形后开始绘制倒计时文字,这个比较简单,就是计算倒计时剩余时间就可以了,然后绘制出来。
protected void onDraw(Canvas canvas) { LogUtils.logI("onDraw()方法执行"); super.onDraw(canvas); paint = new Paint(); paint.setStyle(Paint.Style.STROKE); paint.setColor(Color.BLACK); paint.setAntiAlias(true); paint.setStrokeWidth(2); paint.setAntiAlias(true); //根据比例绘制一个扇形,也就是一个圆形 //当前的弧度 float currentRadian = 360 - 360 * timeTatio; canvas.drawArc(10,10,60,60,-90,currentRadian,false,paint); //绘制文字 paint.reset(); paint.setStyle(Paint.Style.FILL); paint.setColor(Color.parseColor("#3399ff")); paint.setAntiAlias(true); paint.setTextSize(30); canvas.drawText(String.valueOf((int) (countDownNow/1000)),27,45,paint); }
重写onMeasure()方法,为了将View显示在正确的位置上。
//重写onMeasure方法 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(measureSpecHandler(widthMeasureSpec,DEFAULT_WIDTH),measureSpecHandler(heightMeasureSpec,DEFAULT_HEIGHT)); } //计算高度和宽度的具体值 private int measureSpecHandler(int measureSpec,int defaultSize){ int result = defaultSize; int specModel = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch(specModel){ case MeasureSpec.EXACTLY: result = specSize; break; case MeasureSpec.AT_MOST: result = Math.min(result,specSize); break; default: result = defaultSize; break; } return result; }
定义接口,向外部提供倒计时完成的通知信息
//定义一个接口,当倒计时完成之后通知activity做出相应改变 public interface ViewCountDownFinishListener{ void countDownFinish(); }
在xml中直接使用:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.fanjuan.project.wisdomclass.activity.ActivityMain"> <com.fanjuan.project.wisdomclass.view.CountDownView android:id="@+id/cv_count_down" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:layout_marginRight="20dp" android:layout_marginTop="20dp" /> </FrameLayout>
在activity中使用:
protected void initView() { countDownView = findViewById(R.id.cv_count_down); } @Override protected void initListener() { super.initListener(); countDownView.setViewCountDownFinishListener(new CountDownView.ViewCountDownFinishListener() { @Override public void countDownFinish() { ToastUtils.toastInfo("倒计时结束"); } }); }
最后的效果: