android 自定义带动画的统计饼图

2024-06-03 12:38

本文主要是介绍android 自定义带动画的统计饼图,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

达人科技 2016-10-16 15:17

闲来无事,发现市面上好多app都有饼图统计的功能,得空自己实现以下,菜鸟一只,求指教,轻喷!

基本要求:

  1. 在XML布局中可配置控件的属性。
  2. 遵守基本的安卓规范

View基本绘制原理:

首先计算View的大小,测量View的大小主要有三个:

public final void measure(int widthMeasureSpec, int heightMeasureSpec)  
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) 

measure调用onMeasure,onMeasure取得宽高然后调用setMeasureDimension保存测量结果,nMeasure在view的子类中重写。

注意MeasureSpec这个帮助类:

(1) UPSPECIFIED:父容器对于子容器没有任何限制,子容器想要多大就多大.如wrap_content

(2) EXACTLY父容器已经为子容器设置了尺寸,子容器应当服从这些边界,不论子容器想要多大的空间.如match_parent或者具体的值50dp

(3) AT_MOST子容器可以是声明大小内的任意大小.

2.)View的位置
public void layout(int l, int t, int r, int b)
protected boolean setFrame(int left, int top, int right, int bottom)
protected void onLayout(boolean changed, int left, int top, int right, int bottom)

layout通过调用setFrame(l,t,r,b),子视图在父视图中的具体位置,onLayout一般只会在自定义ViewGroup中才会使用,表示子视图在父视图的排列规则以及位置

3.)绘制就是画成什么样子
public void draw(Canvas canvas)
protected void onDraw(Canvas canvas)

通过调用draw函数进行视图绘制,在View类中onDraw函数是个空函数,最终的绘制需求需要在自定义的onDraw函数中进行实现,比如ImageView完成图片的绘制,如果自定义ViewGroup这个函数则不需要重载。

具体事例如下:

package com.example.customview.view;import java.util.Timer;
import java.util.TimerTask;import com.example.customview.R;import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.support.v4.app.TaskStackBuilder;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;public class CirclePercentView extends View {private final static String TAG = CirclePercentView.class.getSimpleName;private Paint mPaint;private RectF oval;// 总数private int max;private int value;// 背景圆的颜色private int backColor;// 圆环的颜色private int frontColor;private float tempValue;// 画圆环的速度private int step;private float maxAngle;private Timer timer;// 字体大小private float textSize;// 字体颜色private int textColor;// 统计数值与统计描述的上下间距private float margin;// 园环宽度private float borderWidth;// 统计描述文本private String descripe;public CirclePercentView(Context context, AttributeSet attrs) {super(context, attrs);init(context, attrs);}public CirclePercentView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context, attrs);}private void init(Context context, AttributeSet attrs) {// 自定义属性TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CirclePercentView);max = ta.getInt(R.styleable.CirclePercentView_maxValue, 0);value = ta.getInt(R.styleable.CirclePercentView_value, 0);backColor = ta.getColor(R.styleable.CirclePercentView_backgroudColor,Color.GRAY);frontColor = ta.getColor(R.styleable.CirclePercentView_frontColor, Color.BLUE);textColor = ta.getColor(R.styleable.CirclePercentView_textColor, Color.BLACK);textSize = ta.getDimension(R.styleable.CirclePercentView_textFont, 16);margin = ta.getDimension(R.styleable.CirclePercentView_textMargin, 16);borderWidth = ta.getDimension(R.styleable.CirclePercentView_borderWidth, 8);descripe = ta.getString(R.styleable.CirclePercentView_descripe);ta.recycle;// 计算角度maxAngle = value * 360f / max;mPaint = new Paint;mPaint.setAntiAlias(true);oval = new RectF;timer = new Timer;startAnim(100, 5000);}/*** * @param t1* 间隔时长* @param t2* 动画总时长*/private void startAnim(long t1, long t2) {step = (int) (maxAngle / t2 * t1);startAnim;}private void startAnim {timer.scheduleAtFixedRate(new TimerTask {@Overridepublic void run {Log.e("tempValuetempValuetempValue", tempValue + "maxAngle"+ maxAngle + "maxAngle" + maxAngle);if (tempValue + step >= maxAngle) {tempValue = maxAngle;timer.cancel;} else {tempValue += step;}// 注意此处postInvalidate与invalidate的区别postInvalidate;}}, 100, 100);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);Log.e(TAG, "onMeasure--widthMode-->" + widthMode);switch (widthMode) {case MeasureSpec.EXACTLY:Log.e(TAG, "EXACTLY-->EXACTLY" + widthSize);setMeasuredDimension(widthSize, heightSize);break;case MeasureSpec.AT_MOST:Log.e(TAG, "AT_MOST-->AT_MOST" + widthSize);break;case MeasureSpec.UNSPECIFIED:Log.e(TAG, "UNSPECIFIED-->UNSPECIFIED" + widthSize);break;}Log.e(TAG, "onMeasure--widthSize-->" + widthSize);Log.e(TAG, "onMeasure--heightMode-->" + heightMode);Log.e(TAG, "onMeasure--heightSize-->" + heightSize);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {super.onLayout(changed, left, top, right, bottom);Log.e(TAG, "onLayout");}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);mPaint.setColor(backColor);// FILL填充, STROKE描边,FILL_AND_STROKE填充和描边mPaint.setStyle(Paint.Style.FILL_AND_STROKE);int with = getWidth;int height = getHeight;// 取最小值作为圆的直径int size = Math.min(with, height);Log.e(TAG, "onDraw---->" + with + "*" + height);// 计算圆的半径float radius = (size - 2 * borderWidth) / 2;// 画背景圆canvas.drawCircle(size / 2, size / 2, radius, mPaint);// 画文本mPaint.setStrokeWidth(0);mPaint.setColor(textColor);mPaint.setTextSize(textSize);canvas.drawText(descripe, radius - mPaint.measureText(descripe) * 0.5f,size / 2 + textSize + margin, mPaint);float textHalfWidth = mPaint.measureText((int) (tempValue / 360 * 100 + 0.5f) + "%") * 0.5f;canvas.drawText((int) (tempValue / 360 * 100 + 0.5f) + "%", radius- textHalfWidth, size / 2, mPaint);// 画圆环mPaint.setStyle(Paint.Style.STROKE);mPaint.setColor(frontColor);mPaint.setStrokeWidth(borderWidth);// 放圆的矩形oval.set(size / 2 - radius, size / 2 - radius, size / 2 + radius, size/ 2 + radius);// 注意第三个参数canvas.drawArc(oval, 0, tempValue, false, mPaint); // 根据进度画圆弧}
}

View Code

attrs.xml如下:

具体使用如下:

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="CirclePercentView"><attr name="maxValue" format="integer" /><attr name="value" format="integer" /><attr name="backgroudColor" format="color|reference" /><attr name="frontColor" format="color|reference" /><attr name="textFont" format="dimension|reference" /><attr name="textColor" format="color|reference" /><attr name="textMargin" format="dimension|reference" /><attr name="borderWidth" format="dimension|reference" /><attr name="descripe" format="string|reference" /></declare-styleable></resources>

View Code

<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:orientation="vertical" ><com.example.customview.view.CirclePercentViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="10dp"app:backgroudColor="#cccccc"app:borderWidth="12dp"app:frontColor="#ff00ff"app:maxValue="360"app:textColor="#ececcc"app:textFont="24sp"app:textMargin="0dp"app:value="270" app:descripe="参与人数"/></LinearLayout>

View Code

也可以在代码中通过暴露方法对各个属性的值进行设置,这里就不举例了

运行结果,如下

android 自定义带动画的统计饼图

这篇关于android 自定义带动画的统计饼图的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1027017

相关文章

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

SpringBoot AspectJ切面配合自定义注解实现权限校验的示例详解

《SpringBootAspectJ切面配合自定义注解实现权限校验的示例详解》本文章介绍了如何通过创建自定义的权限校验注解,配合AspectJ切面拦截注解实现权限校验,本文结合实例代码给大家介绍的非... 目录1. 创建权限校验注解2. 创建ASPectJ切面拦截注解校验权限3. 用法示例A. 参考文章本文

在Android中使用WebView在线查看PDF文件的方法示例

《在Android中使用WebView在线查看PDF文件的方法示例》在Android应用开发中,有时我们需要在客户端展示PDF文件,以便用户可以阅读或交互,:本文主要介绍在Android中使用We... 目录简介:1. WebView组件介绍2. 在androidManifest.XML中添加Interne

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手

聊聊springboot中如何自定义消息转换器

《聊聊springboot中如何自定义消息转换器》SpringBoot通过HttpMessageConverter处理HTTP数据转换,支持多种媒体类型,接下来通过本文给大家介绍springboot中... 目录核心接口springboot默认提供的转换器如何自定义消息转换器Spring Boot 中的消息

IDEA与MyEclipse代码量统计方式

《IDEA与MyEclipse代码量统计方式》文章介绍在项目中不安装第三方工具统计代码行数的方法,分别说明MyEclipse通过正则搜索(排除空行和注释)及IDEA使用Statistic插件或调整搜索... 目录项目场景MyEclipse代码量统计IDEA代码量统计总结项目场景在项目中,有时候我们需要统计

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按