Android 自定义柱状图及属性动画

前段时间公司项目中用到了统计图,网上找了些资料和框架都不能满足我的需求,没办法,只有自己写了。

近来清闲,将其抽出一个demo了,欢迎大家交流指正。

效果图先行

实现方案有两个,一是自定义控件,二是使用属性动画。属性动画在api11以上版本才有,在11版本以下使用可以引入nineoldandroids框架。

由于属性动画比较简单,这里主要说下自定义控件

自定义控件源码如下:

/**
 * 工程名: histogram
 * 文件名: HistogramView.java
 * 包名: com.style.histogram
 * 日期: 2014-4-21下午8:23:38
 * Copyright (c) 2014
 *
*/

package com.style.histogram;
 

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;

/**
 * 类名: HistogramView <br/>
 * 功能: 柱状图. <br/>
 * 日期: 2014-4-21 下午8:23:38 <br/>
 *
 * @author   msl
 * @version  	 
 */
public class HistogramView extends View implements Runnable{
	private static final String TAG = HistogramView.class.getSimpleName();
	
	private int comWidth; //控件宽度
	private int comHeight;//控件高度
	
	private View rateView;//进度条
	
	private View rateTopView; //进度条顶部View
	
	private String rateBackgroundColor;//进图条背景颜色
	
	private int rateBackgroundId; //进图条背景图片id
	
	private Bitmap rataBackgroundBitmap;
	
	private boolean isHasRateTopView; //进度条顶部View
	
	private int rateHeight; //进度条的高
	
	private int rateWidth; //进度条的宽
	
	private int rateAnimValue;//进度条动画高度
	
	private int orientation; //设置柱状图方向
	
	private double progress;//设置进度  1为最大值
	
	private boolean isAnim = true; //是否动画显示统计条
	
    private Handler handler = new Handler();//动画handler
	
	private int animRate = 1; //动画速度   以每1毫秒计
	
	private int animTime = 1;//动画延迟执行时间
	
	private Canvas canvas;//画布
	
	public HistogramView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle); 
	}

	public HistogramView(Context context, AttributeSet attrs) {
		super(context, attrs); 
	}

	public HistogramView(Context context) {
		super(context); 
	}
	

	 
	
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
		super.onSizeChanged(w, h, oldw, oldh); 
		//初始化控件和进度的条相关参数
		comWidth = w;
		comHeight = h;
		if(orientation==LinearLayout.HORIZONTAL){
			rateWidth = (int) (w*progress); 
			rateHeight = h;
		}else{
			rateHeight = (int) (h*progress); 
			rateWidth = w;
		}
	}
	
	@Override
	protected void onDraw(Canvas canvas) { 
		super.onDraw(canvas);
		this.canvas = canvas;
		Paint paint = new Paint();
		paint.setAntiAlias(true);		
		paint.setStyle(Paint.Style.FILL);
		Log.d(TAG, "onDraw  rateBackgroundColor===="+rateBackgroundColor);
		if(rateBackgroundColor!=null){
			drawViewWithColor(paint,isAnim);
		}else if(rateBackgroundId!=-1){
			drawViewWithBitmap(paint, isAnim);
		}
		
	}
	
	/**
	 * 
	 * drawViewWithColor:(绘制颜色进度条). <br/>
	 * @author msl
	 * @param paint
	 * @param isAnim
	 * @since 1.0
	 */
	private void drawViewWithColor(Paint paint,boolean isAnim){
		paint.setColor(Color.parseColor(rateBackgroundColor));
		Log.d(TAG, "rateBackgroundColor===="+rateBackgroundColor);
		if(isAnim){
			handler.postDelayed(this, animTime); 
			if(orientation==LinearLayout.HORIZONTAL){//水平方向柱状图
				canvas.drawRect(0, 0, rateAnimValue, comHeight, paint); 
			}else{//垂直方向柱状图
				canvas.drawRect(0, comHeight-rateAnimValue, comWidth, comHeight, paint); 
			}
		}else {
			if(orientation==LinearLayout.HORIZONTAL){//水平方向无动画柱状图
				canvas.drawRect(0, 0, rateWidth, comHeight, paint);
			}else{//垂直方向无动画柱状图
				canvas.drawRect(0, comHeight-rateHeight, comWidth, comHeight, paint); 
			}
		}
		
	}
	/**
	 * 
	 * drawViewWithBitmap:(绘制图片进度条). <br/>
	 * @author msl
	 * @param paint
	 * @param isAnim
	 * @since 1.0
	 */
	private void drawViewWithBitmap(Paint paint,boolean isAnim){
		Log.d(TAG, "bitmap===="+rataBackgroundBitmap);
		RectF dst = null;
		if(isAnim){
			handler.postDelayed(this, animTime); 
			if(orientation==LinearLayout.HORIZONTAL){//水平方向柱状图
			    dst = new RectF(0, 0, rateAnimValue, comHeight);			    
				canvas.drawBitmap(rataBackgroundBitmap, null, dst, paint);
			}else{//垂直方向柱状图
				dst = new RectF(0, comHeight-rateAnimValue, comWidth, comHeight);
				canvas.drawBitmap(rataBackgroundBitmap, null, dst, paint);
			}
		}else {
			if(orientation==LinearLayout.HORIZONTAL){//水平方向无动画柱状图
				dst = new RectF(0, 0, rateWidth, comHeight);
				canvas.drawBitmap(rataBackgroundBitmap, null, dst, paint);
			}else{//垂直方向无动画柱状图 
				dst = new RectF(0, comHeight-rateHeight, comWidth, comHeight);
				canvas.drawBitmap(rataBackgroundBitmap, null, dst, paint);
			}
		}
	}

  
  public double getProgress() {
		return progress;
	}

	public void setProgress(double progress) {
		this.progress = progress; 
	}


	public View getRateView() {
		return rateView;
	}

	public void setRateView(View rateView) {
		this.rateView = rateView;
	}

	public int getRateHeight() {
		return rateHeight;
	}

	public void setRateHeight(int rateHeight) {
		this.rateHeight = rateHeight;
	}

	public int getRateWidth() {
		return rateWidth;
	}

	public void setRateWidth(int rateWidth) {
		this.rateWidth = rateWidth;
	}

	public int getOrientation() {
		return orientation;
	}

	public void setOrientation(int orientation) {
		this.orientation = orientation;
	}


	public boolean isAnim() {
		return isAnim;
	}

	public void setAnim(boolean isAnim) {
		this.isAnim = isAnim;
	}

	public int getAnimRate() {
		return animRate;
	}

	public void setAnimRate(int animRate) {
		this.animRate = animRate;
	}

	public String getRateBackgroundColor() {
		return rateBackgroundColor;
	}

	public void setRateBackgroundColor(String rateBackgroundColor) {
		this.rateBackgroundColor = rateBackgroundColor;
		rateBackgroundId = -1;
		rataBackgroundBitmap = null;
	}
	
	

	public int getRateBackgroundId() {
		return rateBackgroundId;
	}

	public void setRateBackgroundId(int rateBackground) {
		this.rateBackgroundId = rateBackground;
		rataBackgroundBitmap = BitmapFactory.decodeResource(getResources(), rateBackgroundId);
		rateBackgroundColor = null;
	}

	/**
	 * 
	 *刷新界面
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		if(orientation==LinearLayout.HORIZONTAL&&(rateAnimValue<=rateWidth)){
			rateAnimValue+=animRate;
			invalidate();
		}else if(orientation==LinearLayout.VERTICAL&&(rateAnimValue<=rateHeight)){
			rateAnimValue+=animRate;
			invalidate();
		}else{ 
			handler.removeCallbacks(this);
			rateAnimValue = 0;
		}
		
	}
	
	
	
}


因为需要有动画效果,故HistogramView实现Runable接口,结合Handler的postDelayed方法,使柱状条慢慢增长。

1、首先我们在onSizeChanged方法中初始化控件的相关参数,控件的宽高,柱状条的宽高。当然也可以在其它方法中初始化。这个随个人喜好。


2、接下来在onDraw方法中绘制我们的柱状条。代码挺简单的,没啥好说的。主要用到了两个方法

如果我们的柱状条为颜色值,则用drawRect,它有四个参数,分别是所要绘制区域的四个顶点坐标。

如果我们的柱状条为一张图片,使用drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) 

bitmap表示所要绘制上去的图片,src为图片的绘制区域,如果为null表示整张图片

dst表示图片在控件上的绘制区域,paint为我们的画笔。

使用

布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="@dimen/activity_vertical_margin" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <com.style.histogram.HistogramView
            android:id="@+id/hv1"
            android:layout_width="50dp"
            android:layout_height="100dp"
            android:background="@drawable/asset_column_bg" />

        <com.style.histogram.HistogramView
            android:id="@+id/hv2"
            android:layout_width="50dp"
            android:layout_height="100dp"
            android:layout_marginLeft="20dp"
            android:background="#ee8833" />

        <com.style.histogram.HistogramView
            android:id="@+id/hv3"
            android:layout_width="50dp"
            android:layout_height="100dp"
            android:layout_marginLeft="20dp"
            android:background="@drawable/asset_column_bg" />

        <com.style.histogram.HistogramView
            android:id="@+id/hv4"
            android:layout_width="50dp"
            android:layout_height="100dp"
            android:layout_marginLeft="20dp"
            android:background="#ee8833" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:orientation="vertical" >

        <com.style.histogram.HistogramView
            android:id="@+id/hv5"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="#ee8833" />

        <com.style.histogram.HistogramView
            android:id="@+id/hv6"
        	android:layout_marginTop="20dp"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="#ee8833" />
    </LinearLayout>
    
     <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:orientation="vertical" >
        <RelativeLayout android:layout_width="50dp"
	        android:layout_height="100dp"       
	        android:background="@drawable/asset_column_bg">
	        <View android:layout_width="50dp"
	            android:layout_height="0dp"
	            android:background="@drawable/dq_column"
	            android:layout_alignParentBottom="true"
	            android:id="@+id/v1"/>
	    </RelativeLayout>
	    
	    <FrameLayout android:layout_width="match_parent"
	        android:layout_height="wrap_content"
	        android:layout_marginLeft="20dp"
        	android:layout_marginTop="20dp"
	        android:background="#ee8833">
	        <View android:layout_width="0dp"
	            android:layout_height="50dp"
	            android:background="#123456"
	            android:id="@+id/v2"/>
	    </FrameLayout>
   </LinearLayout>
</LinearLayout>


 java代码

package com.style.histogram;

import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import android.animation.ObjectAnimator;
import android.app.Activity; 
public class MainActivity extends Activity {
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		HistogramView hv1 = (HistogramView) findViewById(R.id.hv1);
		hv1.setProgress(0.4);
		hv1.setRateBackgroundId(R.drawable.dq_column);
		hv1.setOrientation(LinearLayout.VERTICAL);
		
		HistogramView hv2 = (HistogramView) findViewById(R.id.hv2);
		hv2.setProgress(0.4);
		hv2.setRateBackgroundColor("#123456");
		hv2.setOrientation(LinearLayout.VERTICAL);
		
		HistogramView hv3 = (HistogramView) findViewById(R.id.hv3);
		hv3.setProgress(0.4);
		hv3.setRateBackgroundId(R.drawable.dq_column);
		hv3.setOrientation(LinearLayout.VERTICAL);
		hv3.setAnim(false);
		
		HistogramView hv4 = (HistogramView) findViewById(R.id.hv4);
		hv4.setProgress(0.4);
		hv4.setRateBackgroundColor("#123456");
		hv4.setOrientation(LinearLayout.VERTICAL);
		hv4.setAnim(false);
		
		HistogramView hv5 = (HistogramView) findViewById(R.id.hv5);
		hv5.setProgress(0.4);
		hv5.setRateBackgroundColor("#123456");
		hv5.setOrientation(LinearLayout.HORIZONTAL); 
		
		HistogramView hv6 = (HistogramView) findViewById(R.id.hv6);
		hv6.setProgress(0.4);
		hv6.setRateBackgroundColor("#123456");
		hv6.setOrientation(LinearLayout.HORIZONTAL);
		hv6.setAnim(false);
		
		View v1 = findViewById(R.id.v1); 
		ObjectAnimator.ofInt(new ViewWrapper(v1), "height", 30).setDuration(4000).start();
		 
		View v2 = findViewById(R.id.v2); 
		ObjectAnimator.ofInt(new ViewWrapper(v2), "width", 200).setDuration(4000).start();
	}
	
	 class ViewWrapper{
		 private View mTarget;
		 
		 public ViewWrapper(View target) {  
		        mTarget = target;  
		    }  
	  
	    public int getWidth() {  
	        return mTarget.getLayoutParams().width;  
	    }  
	  
	    public void setWidth(int width) {  
	        mTarget.getLayoutParams().width = width;  
	        mTarget.requestLayout();  
	    }  
	    
	    public int getHeight() {  
	        return mTarget.getLayoutParams().height;  
	    }  
	  
	    public void setHeight(int height) {  
	        mTarget.getLayoutParams().height = height;  
	        mTarget.requestLayout();  
	    }  

	 }
 

}


       

没啥难的,demo下载:github

猜你喜欢

转载自blog.csdn.net/msl0903/article/details/24875665