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

相关文章

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

CSS自定义浏览器滚动条样式完整代码

《CSS自定义浏览器滚动条样式完整代码》:本文主要介绍了如何使用CSS自定义浏览器滚动条的样式,包括隐藏滚动条的角落、设置滚动条的基本样式、轨道样式和滑块样式,并提供了完整的CSS代码示例,通过这些技巧,你可以为你的网站添加个性化的滚动条样式,从而提升用户体验,详细内容请阅读本文,希望能对你有所帮助...

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

opencv实现像素统计的示例代码

《opencv实现像素统计的示例代码》本文介绍了OpenCV中统计图像像素信息的常用方法和函数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 统计像素值的基本信息2. 统计像素值的直方图3. 统计像素值的总和4. 统计非零像素的数量

SpringBoot 自定义消息转换器使用详解

《SpringBoot自定义消息转换器使用详解》本文详细介绍了SpringBoot消息转换器的知识,并通过案例操作演示了如何进行自定义消息转换器的定制开发和使用,感兴趣的朋友一起看看吧... 目录一、前言二、SpringBoot 内容协商介绍2.1 什么是内容协商2.2 内容协商机制深入理解2.2.1 内容

如何使用 Bash 脚本中的time命令来统计命令执行时间(中英双语)

《如何使用Bash脚本中的time命令来统计命令执行时间(中英双语)》本文介绍了如何在Bash脚本中使用`time`命令来测量命令执行时间,包括`real`、`user`和`sys`三个时间指标,... 使用 Bash 脚本中的 time 命令来统计命令执行时间在日常的开发和运维过程中,性能监控和优化是不

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06