自定义View,环状进度条
、
首先看一下效果图:

首先,为什么需要自定义View?1. 现有的View满足不了你的需求,也没有办法从已有控件派生一个出来;界面元素需要自己绘制。2. 现有View可以满足要求,把它做成自定义View只是为了抽象:为这个自定义View提供若干方法,方便调用着操纵View。通常做法是派生一个已有View,或者结合xml文件直接inflate。目前常用的基本上是第二种方式,这种方式非常简单,与通常的View使用方法基本相同,但是作用却异常强大,拥有了这一层抽象,代码更加整洁也更容易维护,通过抽取自定义View的公共操作方法也减少了冗余代码,虽然简单,但不可忽视。大多数人感觉神秘的应该是第一种,自绘控件,完全自定义;但其实这两种方式归根结底全部都是自绘;不信你去看看TextView的源码。只不过通常情况下系统帮我们绘制好了一些控件给开发者使用;OK,接下来就是一个问题。在讲述之前我还是啰嗦地重申一下,复用已有View是最最常用也最有效的自定义View方式,必须熟练使用。
一:主函数:
- package com.bwie.lizeayang20171009;
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.Button;
- import com.bwie.lizeayang20171009.R;
- public class MainActivity extends AppCompatActivity {
- private Button mButton;
- private MyClass mCirclePercentView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mCirclePercentView = (MyClass) findViewById(R.id.circleView);
- mButton = (Button) findViewById(R.id.button);
- mButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- int n = (int)(Math.random()*100);
- // 如果是固定值则自己可以定义
- // int n = 79;
- mCirclePercentView.setPercent(n);
- }
- });
- }
- }
二:MyClass:
- <pre name="code" class="html">package com.bwie.lizeayang20171009;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.RectF;
- import android.util.AttributeSet;
- import android.view.View;
- import java.util.Random;
- /**
- * Created by 笔片 on 2017/10/9.
- */
- public class MyClass extends View {
- //圆的半径
- private float mRadius;
- //色带的宽度
- private float mStripeWidth;
- //总体大小
- private int mHeight;
- private int mWidth;
- //动画位置百分比进度
- private int mCurPercent;
- //实际百分比进度
- private int mPercent;
- //圆心坐标
- private float x;
- private float y;
- //要画的弧度
- private int mEndAngle;
- //小圆的颜色
- private int mSmallColor;
- //大圆颜色
- private int mBigColor;
- //中心百分比文字大小
- private float mCenterTextSize;
- public MyClass(Context context) {
- this(context, null);
- }
- public MyClass(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public MyClass(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyClass, defStyleAttr, 0);
- mStripeWidth = a.getDimension(R.styleable.MyClass_stripeWidth, PxUtils.dpToPx(30, context));
- mCurPercent = a.getInteger(R.styleable.MyClass_percent, 0);
- mSmallColor = a.getColor(R.styleable.MyClass_smallColor, 0xffafb4db);
- mBigColor = a.getColor(R.styleable.MyClass_bigColor, 0xff6950a1);
- mCenterTextSize = a.getDimensionPixelSize(R.styleable.MyClass_centerTextSize, PxUtils.spToPx(20, context));
- mRadius = a.getDimensionPixelSize(R.styleable.MyClass_radius, PxUtils.dpToPx(100, context));
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- //获取测量模式
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- //获取测量大小
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
- mRadius = widthSize / 2;
- x = widthSize / 2;
- y = heightSize / 2;
- mWidth = widthSize;
- mHeight = heightSize;
- }
- if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
- mWidth = (int) (mRadius * 2);
- mHeight = (int) (mRadius * 2);
- x = mRadius;
- y = mRadius;
- }
- setMeasuredDimension(mWidth, mHeight);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- Random r = new Random();
- mEndAngle = (int) (mCurPercent * 3.6);
- //绘制大圆
- Paint bigCirclePaint = new Paint();
- bigCirclePaint.setAntiAlias(true);
- bigCirclePaint.setColor(Color.RED);
- // bigCirclePaint.setARGB(200,r.nextInt(255),r.nextInt(255),r.nextInt(255));
- canvas.drawCircle(x, y, mRadius, bigCirclePaint);
- //饼状图
- Paint sectorPaint = new Paint();
- sectorPaint.setColor(mSmallColor);
- sectorPaint.setAntiAlias(true);
- RectF rect = new RectF(0, 0, mWidth, mHeight);
- canvas.drawArc(rect, 270, mEndAngle, true, sectorPaint);
- //绘制小圆,颜色透明
- Paint smallCirclePaint = new Paint();
- smallCirclePaint.setAntiAlias(true);
- smallCirclePaint.setColor(mBigColor);
- canvas.drawCircle(x, y, mRadius - mStripeWidth, smallCirclePaint);
- //绘制文本
- Paint textPaint = new Paint();
- String text = mCurPercent + "%";
- textPaint.setTextSize(mCenterTextSize);
- float textLength = textPaint.measureText(text);
- textPaint.setColor(Color.WHITE);
- canvas.drawText(text, x - textLength / 2, y, textPaint);
- }
- //外部设置百分比数
- public void setPercent(int percent) {
- if (percent > 100) {
- throw new IllegalArgumentException("percent must less than 100!");
- }
- setCurPercent(percent);
- }
- //内部设置百分比 用于动画效果
- private void setCurPercent(int percent) {
- mPercent = percent;
- new Thread(new Runnable() {
- @Override
- public void run() {
- int sleepTime = 1;
- for (int i = 0; i < mPercent; i++) {
- if (i % 20 == 0) {
- sleepTime += 2;
- }
- try {
- Thread.sleep(sleepTime);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- mCurPercent = i;
- MyClass.this.postInvalidate();
- }
- }
- }).start();
- }
- }
- </pre><br><br>
三:PxUtils:
- package com.bwie.lizeayang20171009;
- import android.content.Context;
- import android.util.TypedValue;
- /**
- * 用于px和 dp,sp的转换工具
- * Created by Administrator on 2015/12/16.
- */
- public class PxUtils {
- public static int dpToPx(int dp, Context context) {
- return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
- }
- public static int spToPx(int sp,Context context) {
- return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());
- }
- }
四:activity_main:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- 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=".MainActivity">
- <com.bwie.lizeayang20171009.MyClass
- android:id="@+id/circleView"
- app:stripeWidth="15dp"
- app:centerTextSize="16sp"
- app:percent="45"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <Button
- android:id="@+id/button"
- android:text="change"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- </LinearLayout>
五:自建attrs.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="MyClass">
- <attr name="radius" format="dimension"/>
- <attr name="stripeWidth" format="dimension"/><!--色带宽度-->
- <attr name="percent" format="integer"/><!--百分比 最大值为100-->
- <attr name="smallColor" format="color"/><!--色带宽度-->
- <!--外圈颜色-->
- <attr name="bigColor" format="color"/>
- <!--中间字体颜色-->
- <attr name="centerTextSize" format="dimension"/>
- <!--色带宽度-->
- </declare-styleable>
- </resources>
相关推荐
- 用原型单元格(prototype cell)自定义table view
- 开发的第32天-android自定义控件之 自己画个进度条
- android kotlin带泛型的自定义View的坑
- 自定义View带箭头的圆环,加速 减速 暂停 变色
- Android软件开发之盘点自定义View界面大合集(二)
- 自定义View知识体系
- 自定义View从入门到懵逼系列(下)
- eclipse的VIEW的自定义方法
- 自定义View实例(一)仿优酷菜单
- 自定义View Measure的过程
- 如何依靠副业赚钱,应对人到中年的职场危机
- vscode切换虚拟环境报错无法加载文件 E:\Python_project\shop_env\Scripts\Activate.ps1,因为在此系统上禁止运行 脚本。