第一步: 在res/values目录下新建attrs文件声明自定义view所需要的属性。 <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MeterView"> <attr name="arcColor" format="color"/> <attr name="arcWidth" format="dimension"/> <attr name="text" format="string"/> <attr name="levelCount" format="integer"/> <attr name="innerCircleColor" format="color"/> <attr name="pointerColor" format="color"/> <attr name="textSize" format="dimension"/> </declare-styleable> </resources> MainActivity文件代码: ---------- package com.z.androidday29; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.SeekBar; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; public class MainActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener{ MeterView meterView; SeekBar seekBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); meterView = (MeterView) findViewById(R.id.meterView); seekBar = (SeekBar) findViewById(R.id.seekBar); seekBar.setOnSeekBarChangeListener(this); thread.start(); } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { meterView.setPercent(progress); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case 1: int progress = (int) (msg.arg1 * 1.0f / msg.arg2 * 100); meterView.setPercent(progress); seekBar.setProgress(progress); break; } } }; Thread thread = new Thread(new Runnable() { @Override public void run() { String fileUrl = "http://111.7.174.149/cache/gdown.baidu.com/data/wisegame/81cce5bbe49b4301/QQ_422.apk?ich_args2=238-31152314040098_5008fd23eaccae3ec6cea9c371a15606_10068001_9c88632bdfcaf9d49e33518939a83798_b29e13b2a160d232c8c532dce097b7a8"; try { URL url = new URL(fileUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); InputStream inputStream = conn.getInputStream(); int curLen = -1; byte[] bytes = new byte[1024]; int totalBytes = conn.getContentLength(); int curTotalBytes = 0; while((curLen = inputStream.read(bytes)) != -1){ curTotalBytes += curLen; //在此写入本地文件即可,本次省略,即只下载,不保存。 Message msg = handler.obtainMessage(); msg.arg1 = curTotalBytes; msg.arg2 = totalBytes; msg.what = 1; handler.sendMessage(msg); } inputStream.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }); } ---------- 自定义View代码: ---------- package com.z.androidday29; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.SweepGradient; import android.util.AttributeSet; import android.util.Log; import android.view.View; /** * Created by Administrator on 2016/10/31. */ public class MeterView extends View { private final String TAG = "MeterView"; private Context context; //仪表的宽高 private int meterViewWidth; private int meterViewHeight; //颜色变量 private int arcColor; private int smallCircleColor; private int pointerColor; //刻度数量 private int levelCount; //文字内容 private String text; //文字大小 private int textSize; //文字粗度 private int textStrokeWidth = 1; int strokeWidth = 3; //内弧粗度 private int arcWidth; //内弧填充渐变 Shader shader; //当前进度 private int percent; private Paint basePaint; private Canvas baseCanvas; private Bitmap baseBitmap; private Paint timelyPaint; public MeterView(Context context) { super(context); } public MeterView(Context context, AttributeSet attrs) { this(context, attrs, R.style.MeterViewInStyle); } public MeterView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); Log.i(TAG, "MeterView"); this.context = context; TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MeterView, defStyleAttr, 0); arcColor = typedArray.getColor(R.styleable.MeterView_arcColor, Color.parseColor("#5FB1ED")); smallCircleColor = typedArray.getColor(R.styleable.MeterView_innerCircleColor, Color.parseColor("#C9DEEE")); pointerColor = typedArray.getColor(R.styleable.MeterView_pointerColor, Color.parseColor("#C9DEEE")); levelCount = typedArray.getInt(R.styleable.MeterView_levelCount, 12); textSize = typedArray.getDimensionPixelSize(R.styleable.MeterView_textSize, 24); text = typedArray.getString(R.styleable.MeterView_text); if(text == null || text.length() <= 0){ text = "当前速度"; } arcWidth = typedArray.getDimensionPixelOffset(R.styleable.MeterView_arcWidth, 50); timelyPaint = new Paint(); timelyPaint.setAntiAlias(true); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Log.i(TAG, "onMeasure"); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(widthMeasureSpec); /*1、UNSPECIFIED 父控件没有对子控件施加任何约束,子控件可以是任意大小(也就是未指定) UNSPECIFIED在源码里处理和EXACTLY一样,当View的宽高值为0的时候或者没有设置 宽高值的时候,模式为UNSPECIFIED *2、EXACTLY 父控件决定子控件确切的大小,子控件被限定在给定的边界里面,忽略本身的大小 当设置width为match_parent时,模式为EXACTLY,因为子控件View会占据剩余的父空间, 所以大小是确定的。 *3、AT_MOST * 子控件最大能够达到的指定大小 * 当设置wrap_content时,模式为AT_MOST,表示子控件View的大小最多是多少, * 这样这个子控件View会根据这个上限来设置自己的尺寸 */ if(widthMode == MeasureSpec.EXACTLY){ meterViewWidth = widthSize; }else{ meterViewWidth = 400; } if(heightMode == MeasureSpec.EXACTLY){ meterViewHeight = heightSize; }else{ meterViewHeight = 400; } Log.i(TAG, meterViewWidth + " , " + meterViewHeight); //应用测量值 setMeasuredDimension(meterViewWidth, meterViewHeight); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); Log.i(TAG, "onLayout"); baseBitmap = Bitmap.createBitmap(meterViewWidth, meterViewHeight, Bitmap.Config.ARGB_8888); baseCanvas = new Canvas(baseBitmap); basePaint = new Paint(); basePaint.setAntiAlias(true); basePaint.setColor(arcColor); basePaint.setStyle(Paint.Style.STROKE); basePaint.setStrokeWidth(strokeWidth); //画最外层弧 RectF outterArc = new RectF(strokeWidth, strokeWidth, meterViewWidth - strokeWidth, meterViewHeight - strokeWidth); baseCanvas.drawArc(outterArc, 145, 250, false, basePaint); //画内层弧 basePaint.setColor(Color.WHITE); basePaint.setStrokeWidth(arcWidth); RectF innerArc = new RectF(strokeWidth + 50, strokeWidth + 50, meterViewWidth - strokeWidth - 50, meterViewHeight - strokeWidth - 50); baseCanvas.drawArc(innerArc, 145, 250, false, basePaint); //画大圆 basePaint.setColor(arcColor); basePaint.setStrokeWidth(strokeWidth); baseCanvas.drawCircle(meterViewWidth / 2, meterViewHeight / 2, 30, basePaint); //画小圆 basePaint.setColor(smallCircleColor); basePaint.setStrokeWidth(strokeWidth + 5); baseCanvas.drawCircle(meterViewWidth / 2, meterViewHeight / 2, 15, basePaint); //绘制刻度 basePaint.setColor(arcColor); basePaint.setStrokeWidth(strokeWidth); baseCanvas.drawLine(meterViewWidth / 2, 0, meterViewWidth / 2, levelCount, basePaint); //绘制右边刻度 //旋转角度 float roundAngle = 250f / levelCount; //右刻度 //当画布进行任何位置变换后,最终均将回到最初状态 baseCanvas.save(); for(int i = 0; i < levelCount / 2; i++){ baseCanvas.rotate(roundAngle, meterViewWidth / 2, meterViewHeight / 2); baseCanvas.drawLine(meterViewWidth / 2, 0, meterViewWidth / 2, levelCount, basePaint); } baseCanvas.restore(); //左刻度 baseCanvas.save(); for(int i = 0; i < levelCount / 2; i++){ baseCanvas.rotate(-roundAngle, meterViewWidth / 2, meterViewHeight / 2); baseCanvas.drawLine(meterViewWidth / 2, 0, meterViewWidth / 2, levelCount, basePaint); } baseCanvas.restore(); //绘制矩形区域 basePaint.setStyle(Paint.Style.FILL); basePaint.setColor(arcColor); baseCanvas.drawRect(meterViewWidth / 2 - 60, meterViewHeight / 2 + 60, meterViewWidth / 2 + 60, meterViewHeight / 2 + 60 + 50, basePaint ); shader = new LinearGradient(0, 0, meterViewWidth, meterViewHeight, Color.parseColor("#9d98cf"), Color.parseColor("#f0445e"), Shader.TileMode.CLAMP); } @Override protected void onDraw(Canvas canvas) { Log.i(TAG, "onDraw"); canvas.drawBitmap(baseBitmap, 0, 0, basePaint); //绘制提示字 onDraw绘制 timelyPaint.setTextSize(textSize); timelyPaint.setStrokeWidth(textStrokeWidth); timelyPaint.setStyle(Paint.Style.FILL); timelyPaint.setColor(Color.WHITE); float textLength = timelyPaint.measureText(text); canvas.drawText(text, (meterViewWidth - textLength) / 2, meterViewHeight / 2 + 60 + 60 / 2, timelyPaint); //绘制填充色 onDraw绘制 timelyPaint.setShader(shader); timelyPaint.setStyle(Paint.Style.STROKE); // timelyPaint.setColor(Color.parseColor("#fe696d")); timelyPaint.setStrokeWidth(arcWidth); RectF innerArc = new RectF(strokeWidth + 50, strokeWidth + 50, meterViewWidth - strokeWidth - 50, meterViewHeight - strokeWidth - 50); canvas.drawArc(innerArc, 145, 250 * percent / 100, false, timelyPaint); //绘制表针 onDraw绘制 timelyPaint.reset(); timelyPaint.setStyle(Paint.Style.STROKE); timelyPaint.setColor(pointerColor); timelyPaint.setStrokeWidth(strokeWidth); canvas.save(); canvas.rotate(250 * percent / 100 - 250 * 1.0f / 2, meterViewWidth / 2, meterViewHeight / 2); canvas.drawLine(meterViewWidth / 2, meterViewHeight / 2, meterViewWidth / 2, strokeWidth + arcWidth / 2, timelyPaint); canvas.restore(); } public void setPercent(int percent) { this.percent = percent; this.text = percent == 100 ? "下载完成" : percent + "%"; invalidate(); } public void setText(String text) { this.text = text; } } ---------- 布局文件代码: ---------- <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:meter="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#7c7200" tools:context="com.z.androidday29.MainActivity"> <com.z.androidday29.MeterView android:id="@+id/meterView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="10dp" meter:arcColor="#00a2ff" meter:innerCircleColor="#aeafaf" meter:levelCount="16" meter:pointerColor="#5e5d5e" meter:text="当前进度" meter:textSize="25px" /> <SeekBar android:id="@+id/seekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/meterView" /> </RelativeLayout> ---------- ![效果](https://img-blog.csdn.net/20161031190728717) ----------下面的seekBar,中间text,仪表盘跟随文件下载改变
自定义View之仪表盘版进度条
最新推荐文章于 2023-07-14 14:56:10 发布