Android 自定義柱狀圖及屬性動畫
阿新 • • 發佈:2018-11-12
前段時間公司專案中用到了統計圖,網上找了些資料和框架都不能滿足我的需求,沒辦法,只有自己寫了。
近來清閒,將其抽出一個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