array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 自定义View,环状进度条 - 爱码网

首先看一下效果图:


自定义View,环状进度条

首先,为什么需要自定义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>  

相关文章: