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

相关文章

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

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

hdu1496(用hash思想统计数目)

作为一个刚学hash的孩子,感觉这道题目很不错,灵活的运用的数组的下标。 解题步骤:如果用常规方法解,那么时间复杂度为O(n^4),肯定会超时,然后参考了网上的解题方法,将等式分成两个部分,a*x1^2+b*x2^2和c*x3^2+d*x4^2, 各自作为数组的下标,如果两部分相加为0,则满足等式; 代码如下: #include<iostream>#include<algorithm

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

flume系列之:查看flume系统日志、查看统计flume日志类型、查看flume日志

遍历指定目录下多个文件查找指定内容 服务器系统日志会记录flume相关日志 cat /var/log/messages |grep -i oom 查找系统日志中关于flume的指定日志 import osdef search_string_in_files(directory, search_string):count = 0

hdu4267区间统计

题意:给一些数,有两种操作,一种是在[a,b] 区间内,对(i - a)% k == 0 的加value,另一种操作是询问某个位置的值。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import

hdu4417区间统计

给你一个数列{An},然后有m次查询,每次查询一段区间 [l,r] <= h 的值的个数。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamRead

hdu3333区间统计

题目大意:求一个区间内不重复数字的和,例如1 1 1 3,区间[1,4]的和为4。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;