自定义View,环状进度条

来源:互联网 发布:codecademy python课程 编辑:程序博客网 时间:2024/04/28 07:54

首先看一下效果图:


首先,为什么需要自定义View?
1. 现有的View满足不了你的需求,也没有办法从已有控件派生一个出来;界面元素需要自己绘制。
2. 现有View可以满足要求,把它做成自定义View只是为了抽象:为这个自定义View提供若干方法,方便调用着操纵View。通常做法是派生一个已有View,或者结合xml文件直接inflate。
目前常用的基本上是第二种方式,这种方式非常简单,与通常的View使用方法基本相同,但是作用却异常强大,拥有了这一层抽象,代码更加整洁也更容易维护,通过抽取自定义View的公共操作方法也减少了冗余代码,虽然简单,但不可忽视。
大多数人感觉神秘的应该是第一种,自绘控件,完全自定义;但其实这两种方式归根结底全部都是自绘;不信你去看看TextView的源码。只不过通常情况下系统帮我们绘制好了一些控件给开发者使用;OK,接下来就是一个问题。
在讲述之前我还是啰嗦地重申一下,复用已有View是最最常用也最有效的自定义View方式,必须熟练使用。
一:主函数:
[html] view plain copy
  1. package com.bwie.lizeayang20171009;  
  2.   
  3. import android.support.v7.app.AppCompatActivity;  
  4. import android.os.Bundle;  
  5. import android.view.View;  
  6. import android.widget.Button;  
  7.   
  8. import com.bwie.lizeayang20171009.R;  
  9.   
  10. public class MainActivity extends AppCompatActivity {  
  11.     private Button mButton;  
  12.     private MyClass mCirclePercentView;  
  13.     @Override  
  14.     protected void onCreate(Bundle savedInstanceState) {  
  15.         super.onCreate(savedInstanceState);  
  16.         setContentView(R.layout.activity_main);  
  17.         mCirclePercentView = (MyClass) findViewById(R.id.circleView);  
  18.         mButton = (Button) findViewById(R.id.button);  
  19.         mButton.setOnClickListener(new View.OnClickListener() {  
  20.             @Override  
  21.             public void onClick(View v) {  
  22.                 int n = (int)(Math.random()*100);  
[html] view plain copy
  1. // 如果是固定值则自己可以定义  
  2. //                int n = 79;  
  3.                 mCirclePercentView.setPercent(n);  
  4.             }  
  5.         });  
  6.     }  
  7. }  


二:MyClass:
[html] view plain copy
  1. <pre name="code" class="html">package com.bwie.lizeayang20171009;  
  2.   
  3. import android.content.Context;  
  4. import android.content.res.TypedArray;  
  5. import android.graphics.Canvas;  
  6. import android.graphics.Color;  
  7. import android.graphics.Paint;  
  8. import android.graphics.RectF;  
  9. import android.util.AttributeSet;  
  10. import android.view.View;  
  11.   
  12. import java.util.Random;  
  13.   
  14. /**  
  15.  * Created by 笔片 on 2017/10/9.  
  16.  */  
  17.   
  18. public class MyClass extends View {  
  19.     //圆的半径  
  20.     private float mRadius;  
  21.   
  22.     //色带的宽度  
  23.     private float mStripeWidth;  
  24.     //总体大小  
  25.     private int mHeight;  
  26.     private int mWidth;  
  27.   
  28.     //动画位置百分比进度  
  29.     private int mCurPercent;  
  30.   
  31.     //实际百分比进度  
  32.     private int mPercent;  
  33.     //圆心坐标  
  34.     private float x;  
  35.     private float y;  
  36.   
  37.     //要画的弧度  
  38.     private int mEndAngle;  
  39.   
  40.     //小圆的颜色  
  41.     private int mSmallColor;  
  42.     //大圆颜色  
  43.     private int mBigColor;  
  44.   
  45.     //中心百分比文字大小  
  46.     private float mCenterTextSize;  
  47.   
  48.     public MyClass(Context context) {  
  49.         this(context, null);  
  50.     }  
  51.   
  52.     public MyClass(Context context, AttributeSet attrs) {  
  53.         this(context, attrs, 0);  
  54.     }  
  55.   
  56.     public MyClass(Context context, AttributeSet attrs, int defStyleAttr) {  
  57.         super(context, attrs, defStyleAttr);  
  58.         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyClass, defStyleAttr, 0);  
  59.         mStripeWidth = a.getDimension(R.styleable.MyClass_stripeWidth, PxUtils.dpToPx(30, context));  
  60.         mCurPercent = a.getInteger(R.styleable.MyClass_percent, 0);  
  61.         mSmallColor = a.getColor(R.styleable.MyClass_smallColor, 0xffafb4db);  
  62.         mBigColor = a.getColor(R.styleable.MyClass_bigColor, 0xff6950a1);  
  63.         mCenterTextSize = a.getDimensionPixelSize(R.styleable.MyClass_centerTextSize, PxUtils.spToPx(20, context));  
  64.         mRadius = a.getDimensionPixelSize(R.styleable.MyClass_radius, PxUtils.dpToPx(100, context));  
  65.     }  
  66.   
  67.   
  68.   
  69.     @Override  
  70.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  71.   
  72.         //获取测量模式  
  73.         int widthMode = MeasureSpec.getMode(widthMeasureSpec);  
  74.         int heightMode = MeasureSpec.getMode(heightMeasureSpec);  
  75.         //获取测量大小  
  76.         int widthSize = MeasureSpec.getSize(widthMeasureSpec);  
  77.         int heightSize = MeasureSpec.getSize(heightMeasureSpec);  
  78.   
  79.         if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {  
  80.             mRadius = widthSize / 2;  
  81.             x = widthSize / 2;  
  82.             y = heightSize / 2;  
  83.             mWidth = widthSize;  
  84.             mHeight = heightSize;  
  85.         }  
  86.   
  87.         if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {  
  88.             mWidth = (int) (mRadius * 2);  
  89.             mHeight = (int) (mRadius * 2);  
  90.             x = mRadius;  
  91.             y = mRadius;  
  92.   
  93.         }  
  94.   
  95.         setMeasuredDimension(mWidth, mHeight);  
  96.     }  
  97.   
  98.     @Override  
  99.     protected void onDraw(Canvas canvas) {  
  100.         Random r = new Random();  
  101.         mEndAngle = (int) (mCurPercent * 3.6);  
  102.         //绘制大圆  
  103.         Paint bigCirclePaint = new Paint();  
  104.         bigCirclePaint.setAntiAlias(true);  
  105.         bigCirclePaint.setColor(Color.RED);  
  106. //        bigCirclePaint.setARGB(200,r.nextInt(255),r.nextInt(255),r.nextInt(255));  
  107.   
  108.   
  109.         canvas.drawCircle(x, y, mRadius, bigCirclePaint);  
  110.   
  111.   
  112.         //饼状图  
  113.         Paint sectorPaint = new Paint();  
  114.         sectorPaint.setColor(mSmallColor);  
  115.         sectorPaint.setAntiAlias(true);  
  116.         RectF rect = new RectF(0, 0, mWidth, mHeight);  
  117.   
  118.         canvas.drawArc(rect, 270, mEndAngle, true, sectorPaint);  
  119.   
  120.   
  121.         //绘制小圆,颜色透明  
  122.         Paint smallCirclePaint = new Paint();  
  123.         smallCirclePaint.setAntiAlias(true);  
  124.         smallCirclePaint.setColor(mBigColor);  
  125.         canvas.drawCircle(x, y, mRadius - mStripeWidth, smallCirclePaint);  
  126.   
  127.   
  128.         //绘制文本  
  129.         Paint textPaint = new Paint();  
  130.         String text = mCurPercent + "%";  
  131.   
  132.         textPaint.setTextSize(mCenterTextSize);  
  133.         float textLength = textPaint.measureText(text);  
  134.   
  135.         textPaint.setColor(Color.WHITE);  
  136.         canvas.drawText(text, x - textLength / 2, y, textPaint);  
  137.     }  
  138.   
  139.     //外部设置百分比数  
  140.     public void setPercent(int percent) {  
  141.         if (percent > 100) {  
  142.             throw new IllegalArgumentException("percent must less than 100!");  
  143.         }  
  144.   
  145.         setCurPercent(percent);  
  146.   
  147.   
  148.     }  
  149.   
  150.     //内部设置百分比 用于动画效果  
  151.     private void setCurPercent(int percent) {  
  152.   
  153.         mPercent = percent;  
  154.   
  155.         new Thread(new Runnable() {  
  156.             @Override  
  157.             public void run() {  
  158.                 int sleepTime = 1;  
  159.                 for (int i = 0; i < mPercent; i++) {  
  160.                     if (i % 20 == 0) {  
  161.                         sleepTime += 2;  
  162.                     }  
  163.                     try {  
  164.                         Thread.sleep(sleepTime);  
  165.                     } catch (InterruptedException e) {  
  166.                         e.printStackTrace();  
  167.                     }  
  168.                     mCurPercent = i;  
  169.                     MyClass.this.postInvalidate();  
  170.                 }  
  171.             }  
  172.   
  173.         }).start();  
  174.   
  175.     }  
  176.   
  177. }  
  178. </pre><br><br>  
三:PxUtils:
[html] view plain copy
  1. package com.bwie.lizeayang20171009;  
  2.   
  3. import android.content.Context;  
  4. import android.util.TypedValue;  
  5.   
  6. /**  
  7.  * 用于px和  dp,sp的转换工具  
  8.  * Created by Administrator on 2015/12/16.  
  9.  */  
  10. public class PxUtils {  
  11.   
  12.     public static int dpToPx(int dp, Context context) {  
  13.         return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());  
  14.     }  
  15.   
  16.     public static int spToPx(int sp,Context context) {  
  17.         return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());  
  18.     }  
  19. }  



四:activity_main:
[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.   
  5.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  6.     android:layout_width="match_parent"  
  7.     android:layout_height="match_parent"  
  8.     android:paddingBottom="@dimen/activity_vertical_margin"  
  9.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  10.     android:paddingRight="@dimen/activity_horizontal_margin"  
  11.     android:paddingTop="@dimen/activity_vertical_margin"  
  12.     tools:context=".MainActivity">  
  13.     <com.bwie.lizeayang20171009.MyClass  
  14.         android:id="@+id/circleView"  
  15.         app:stripeWidth="15dp"  
  16.         app:centerTextSize="16sp"  
  17.         app:percent="45"  
  18.         android:layout_width="wrap_content"  
  19.         android:layout_height="wrap_content" />  
  20.     <Button  
  21.         android:id="@+id/button"  
  22.         android:text="change"  
  23.         android:layout_width="wrap_content"  
  24.         android:layout_height="wrap_content" />  
  25. </LinearLayout>  

五:自建attrs.xml:
[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <declare-styleable name="MyClass">  
  4.         <attr name="radius" format="dimension"/>  
  5.         <attr name="stripeWidth" format="dimension"/><!--色带宽度-->  
  6.         <attr name="percent" format="integer"/><!--百分比 最大值为100-->  
  7.         <attr name="smallColor" format="color"/><!--色带宽度-->  
  8.         <!--外圈颜色-->  
  9.         <attr name="bigColor" format="color"/>  
  10.   
  11.         <!--中间字体颜色-->  
  12.         <attr name="centerTextSize" format="dimension"/>  
  13.         <!--色带宽度-->  
  14.     </declare-styleable>  
  15. </resources>  
原创粉丝点击