刚回顾完群英传的自定义view章节,在3.6.3.1中弧形展示图,看完在想,做成加载进度条是否稍微有趣点呢,就着手开始实现了。先看下弧形展示图。
准备期
有了需求,那么就得先思考如何实现,开启线程,自加后更新数据?还是开个服务再返回更新呢?我选择后者,作为小白,多拓展,也能温习其他知识。
实现
创建一个service,service内做的内容有开启一个定时任务,任务内进行自加num并传递num。Activity中绑定服务并在连接处调用回调获取num,通过bundle写入数据,交由message传输给主线程处理并更新UI。
自定义View
自定义view的相关代码。
package com.example.OwnerView;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
/**
* @author San-Nan
* @date 2020/1/7
* @description 自定义view界面
*/
public class MyCircleView extends View {
private float mCircleXY;
private float mRadius;
private RectF mArcRectF;
private Paint mCirclePaint;
private Paint mArcPaint;
private Paint mTextPaint;
private int mMeasureWidth;
private int mMeasureHeight;
private float mSweepAngle;
private float mSweepValue = 0;
private String mShowText;
private float mShowTextSize;
private int mTextNum = 0;
public MyCircleView(Context context) {
super(context);
}
public MyCircleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mMeasureWidth = MeasureSpec.getSize(widthMeasureSpec);
mMeasureHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(mMeasureWidth,mMeasureHeight);
initView();
}
private void initView() {
float length = 0;
if(mMeasureHeight >= mMeasureWidth){
length = mMeasureWidth;
}else{
length = mMeasureHeight;
}
mCircleXY = length/2;
mRadius = (float) (length * 0.5 / 2);
mCirclePaint = new Paint();
//设置抗锯齿
mCirclePaint.setAntiAlias(true);
mCirclePaint.setColor(getResources().getColor(android.R.color.holo_blue_bright));
mArcRectF = new RectF(
(float) (length * 0.1),
(float) (length * 0.1),
(float) (length * 0.9),
(float) (length * 0.9));
mSweepAngle = (mSweepValue / 100f) * 360f;
mArcPaint = new Paint();
mArcPaint.setAntiAlias(true);
mArcPaint.setColor(getResources().getColor(android.R.color.holo_orange_light));
//描边宽度
mArcPaint.setStrokeWidth((float) (length * 0.1));
//描边效果
mArcPaint.setStyle(Paint.Style.STROKE);
mShowText = setTextShow();
mShowTextSize = setTextSize();
mTextPaint = new Paint();
mTextPaint.setTextSize(mShowTextSize);
mTextPaint.setTextAlign(Paint.Align.CENTER);
}
private float setTextSize() {
this.invalidate();
return 50;
}
private String setTextShow() {
this.invalidate();
return String.valueOf(mTextNum)+"%";
}
@Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
//绘制圆
canvas.drawCircle(mCircleXY,mCircleXY,mRadius,mCirclePaint);
//绘制弧形
canvas.drawArc(mArcRectF,270,mSweepAngle,false,mArcPaint);
//绘制文字
canvas.drawText(mShowText,0,mShowText.length(),mCircleXY,mCircleXY + (mShowTextSize / 4),mTextPaint);
}
public void setSweepValue(float sweepValue){
if (sweepValue != 0) {
mSweepValue = sweepValue;
} else {
mSweepValue = 0;
}
this.invalidate();
}
public void setTextNum(int textNum){
if (textNum != 0) {
mTextNum = textNum;
} else {
mTextNum = 0;
}
this.invalidate();
}
}
Service
package com.example.service;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import java.util.Timer;
import java.util.TimerTask;
public class MyDownLoadService extends Service {
private DownloadBinder downloadBinder = new DownloadBinder();
private Callback callback;
private Timer timer = new Timer();
private int num;
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return downloadBinder;
}
public class DownloadBinder extends Binder {
public MyDownLoadService getService() {
return MyDownLoadService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
//定时执行task
timer.schedule(task,1000,1000);
}
public void setCallback(Callback callback){
this.callback = callback;
}
TimerTask task = new TimerTask() {
@Override
public void run() {
if(num == 100){
num = 0;
}else{
num++;
}
if(callback != null){
//得到最新的num
callback.getNum(num);
}
}
};
//回调接口
public interface Callback{
void getNum(int num);
}
@Override
public void onDestroy() {
timer.cancel();
super.onDestroy();
}
}
主Activity
package com.example.OwnerView;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import com.example.service.MyDownLoadService;
/**
* @author San-Nan
* @date 2020/1/7
* @description 主activity界面
*/
public class OwnerCircleViewActivity extends AppCompatActivity {
private MyDownLoadService.DownloadBinder downloadBinder ;
private MyDownLoadService myDownLoadService;
MyCircleView circleView;
public static final int MSG_UPDATE_VIEW = 0x01;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_owner_circle_view);
Intent intent = new Intent(this, MyDownLoadService.class);
bindService(intent,mServiceConnection,BIND_AUTO_CREATE);//绑定服务
circleView = (MyCircleView)findViewById(R.id.circle);
}
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case MSG_UPDATE_VIEW:
int showNum = msg.getData().getInt("Num");
circleView.setSweepValue(showNum);
circleView.setTextNum(showNum);
//强制更新view
circleView.invalidate();
circleView.forceLayout();
circleView.requestLayout();
break;
default:
super.handleMessage(msg);
}
}
};
private ServiceConnection mServiceConnection = new ServiceConnection() {
//绑定服务时调用
@Override
public void onServiceConnected(final ComponentName name, IBinder service) {
downloadBinder = (MyDownLoadService.DownloadBinder)service;
myDownLoadService = (MyDownLoadService) downloadBinder.getService();
//实时刷新数据
myDownLoadService.setCallback(new MyDownLoadService.Callback() {
@Override
public void getNum(int num) {
Message msg = new Message();
msg.what = MSG_UPDATE_VIEW;
Bundle bundle = new Bundle();
bundle.putInt("Num",num);//通过bundle写入数据并使用message传输
msg.setData(bundle);
handler.sendMessage(msg);
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onDestroy() {
unbindService(mServiceConnection);//解绑服务
super.onDestroy();
}
}
layout布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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=".OwnerCircleViewActivity">
<com.example.mediapecorder.MyCircleView
android:id="@+id/circle"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.example.mediapecorder.MyCircleView>
</LinearLayout>