Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android自定義帶增長動畫和點擊彈窗提示效果的柱狀圖DEMO

Android自定義帶增長動畫和點擊彈窗提示效果的柱狀圖DEMO

編輯:關於Android編程

項目中最近用到各種圖表,本來打算用第三方的,例如MPAndroid,這是一個十分強大的圖表庫,應用起來十分方便,但是最終發現和設計不太一樣,沒辦法,只能自己寫了。今天將寫好的柱狀圖的demo貼在這,該柱狀圖可根據數據的功能有一下幾點:

     1. 根據數據的多少,動態的繪制柱狀圖柱子的條數;

     2. 柱狀圖每條柱子的繪制都有動態的動畫效果;

     3. 每條柱子有點擊事件,點擊時彈出提示框,顯示相關信息,規定時間後,彈窗自動消失。

     好了,先上演示圖:

     下邊貼出相關代碼:

     自定義柱狀圖類:

package com.example.histogram; 
import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.RectF; 
import android.os.Handler; 
import android.text.TextPaint; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.MotionEvent; 
import android.view.View; 
import com.example.histogram.UI.UI; 
import java.text.NumberFormat; 
/** 
 * Created by ZHANGZDon 2016/6/16 0016. 
 * 柱狀圖 
 */ 
public class HistoGram extends View implements Runnable { 
  private Handler handler = new Handler(); // 用於延時更新,實現動畫 
  private float animHeight; // 進度條動畫高度 
  private Paint axisLinePaint; // 坐標軸畫筆 
  private Paint hLinePaint; // 內部水平虛線畫筆 
  private Paint textPaint; // 繪制文本的畫筆 
  private Paint recPaint; // 繪制柱狀圖陰影背景的畫筆 
  private Paint dataPaint; // 繪制柱狀圖的畫筆 
  private Paint textPaint2; // 繪制白色文本的畫筆 
  private Paint textPaint3; // 繪制坐標的畫筆 
  private Paint textPaint4; // 繪制x軸上的白色豎線的畫筆 
  private String[] xTitleString; // x軸刻度 
  private String[] yTitleString; // y軸刻度 
  private String[] data; // 接口返回的indicatordata,用於計算柱子高度 
  NumberFormat numberFormat; //用於格式化數字 
  private float currentHeight; // 當前柱狀圖應有的高度,應由計算得來 
  private int num = -1; // 畫多少條柱子,因為存在剛開機數據不足24條的情況 
  private float mRelativePxInHeight; 
  private float mRelativePxInWidth; 
  private OnChartClickListener listener; 
  private int mDist; 
  public void setNum(int num) { 
    this.num = num; 
    invalidate(); 
  } 
  public void setData(String[] data) { 
    this.data = data; 
    invalidate(); 
  } 
  public void setxTitleString(String[] title) { 
    this.xTitleString = title; 
    invalidate(); 
  } 
  public HistoGram(Context context) { 
    this(context, null); 
  } 
  public HistoGram(Context context, AttributeSet attrs) { 
    this(context, attrs, 0); 
  } 
  public void setTitle(String[] title) { 
    this.xTitleString = title; 
  } 
  public HistoGram(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
    init(context, attrs); 
  } 
  /** 
   * 進行相關初始化操作 
   * @param context 
   * @param attrs 
   */ 
  private void init(Context context, AttributeSet attrs) { 
    axisLinePaint = new Paint(); 
    hLinePaint = new Paint(); 
    textPaint = new Paint(); 
    recPaint = new Paint(); 
    dataPaint = new Paint(); 
    textPaint2 = new Paint(); 
    textPaint3 = new Paint(); 
    textPaint4 = new Paint(); 
    numberFormat = NumberFormat.getNumberInstance(); 
    numberFormat.setMinimumFractionDigits(3); //設置打印時保留三位小數 
    axisLinePaint.setColor(Color.parseColor("#dbdde4")); //設置坐標軸的顏色為白色 
    hLinePaint.setARGB(51, 255, 255, 255); 
    textPaint.setColor(Color.parseColor("#8593a1")); 
//    textPaint.setTextSize(29); 
    textPaint.setTextSize(UI.dip2px(getContext(), 12)); 
    recPaint.setColor(Color.parseColor("#f2f5fc")); 
    dataPaint.setColor(Color.CYAN); 
    textPaint2.setColor(Color.WHITE); 
    textPaint2.setTextSize(UI.dip2px(getContext(), 12)); 
    textPaint3.setColor(Color.parseColor("#000000")); 
    textPaint3.setTextSize(UI.dip2px(getContext(), 9)); 
    textPaint4.setColor(Color.parseColor("#8593a1")); 
    textPaint4.setTextSize(UI.dip2px(getContext(), 6)); 
    axisLinePaint.setAntiAlias(true); 
    hLinePaint.setAntiAlias(true); 
    textPaint.setAntiAlias(true); 
    recPaint.setAntiAlias(true); 
    dataPaint.setAntiAlias(true); 
    textPaint2.setAntiAlias(true); 
    textPaint3.setAntiAlias(true); 
    textPaint4.setAntiAlias(true); 
  } 
  @Override 
  protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 
    if(data == null || xTitleString == null || num < 0 ) { 
      return; 
    } 
    //繪制y軸刻度 
    Paint.FontMetrics metrics = textPaint3.getFontMetrics(); 
    int decent = (int) metrics.descent; 
    float width = getWidth(); 
    float height = getHeight(); 
    //根據原型圖得出,圖中每px高度在實際中的相對尺寸 
    mRelativePxInHeight = height / 470; 
    //根據原型圖得出,圖中每px寬度在實際中的相對尺寸 
    mRelativePxInWidth = width / 690; 
    textPaint3.setTextAlign(Paint.Align.RIGHT); 
    //繪制縱坐標 
    yTitleString = new String[6]; 
    yTitleString[5] = "0"; 
    yTitleString[4] = "20"; 
    yTitleString[3] = "40"; 
    yTitleString[2] = "60"; 
    yTitleString[1] = "80"; 
    yTitleString[0] = "100"; 
    for (int i = 0; i < yTitleString.length; i++) { 
      canvas.drawText(yTitleString[i], 88 * mRelativePxInWidth, (72 + i * 56) * mRelativePxInHeight + decent, textPaint3); 
    } 
    //繪制x軸刻度 
    textPaint3.setTextAlign(Paint.Align.CENTER); 
    textPaint4.setTextAlign(Paint.Align.CENTER); 
    TextPaint textPaint = new TextPaint(); 
    textPaint.setColor(Color.parseColor("#000000")); 
    textPaint.setTextSize(UI.dip2px(getContext(), 9)); 
    //計算柱子之間的間隔 
    //最左側位置100 * mRelativePxInWidth,最右側位置630 ePxInWidth, 
    float totalWidth = 630 - 100; 
    // 柱子與之子之間的間隔 
    mDist = (int) (totalWidth / (xTitleString.length + 1)); 
    for (int i = 0; i < xTitleString.length; i++) { 
      //繪制白色豎線 
      canvas.drawLine((100 + (i+1) * mDist) * mRelativePxInWidth, 348 * mRelativePxInHeight, (100 + (i+1) * mDist) * mRelativePxInWidth, 352 * mRelativePxInHeight, axisLinePaint); 
      //繪制x軸文字 
      canvas.drawText(xTitleString[i], (100 + (i+1) * mDist) * mRelativePxInWidth, 370 * mRelativePxInHeight, textPaint3); 
    } 
//    繪制矩形陰影 
    for (int i = 0; i < num; i++) { 
      RectF rectF = new RectF(); 
//      rectF.left = 111 * relativePxInWidth + i * 22 * relativePxInWidth; 
//      rectF.right = 121 * relativePxInWidth + i * 22 * relativePxInWidth; 
      rectF.left = 95 * mRelativePxInWidth + (i+1) * mDist * mRelativePxInWidth; 
      rectF.right = 105 * mRelativePxInWidth +(i+1) * mDist * mRelativePxInWidth; 
      rectF.top = 70 * mRelativePxInHeight; 
      rectF.bottom = 338 * mRelativePxInHeight; 
      canvas.drawRoundRect(rectF, 10, 10, recPaint); 
    } 
    //    繪制x軸坐標線 
    for (int i = 0; i < 6; i++) { 
      canvas.drawLine(100 * mRelativePxInWidth, (66 + i * 56) * mRelativePxInHeight + decent, 630 * mRelativePxInWidth, (66 + i * 56) * mRelativePxInHeight + decent, axisLinePaint); 
    } 
//    延時繪制,實現動畫效果。數字越大,延時越久,動畫效果就會越慢 
    handler.postDelayed(this, 1); 
    for (int i = 0; i < num; i++) { 
      RectF dataRectF = new RectF(); 
      dataRectF.left = 95 * mRelativePxInWidth + (i + 1) * mDist * mRelativePxInWidth; 
      dataRectF.right = 105 * mRelativePxInWidth + (i + 1) * mDist * mRelativePxInWidth; 
      dataPaint.setColor(Color.parseColor("#3ac2d9")); 
      //獲取柱子高度 
      currentHeight = Float.parseFloat(data[num - 1 - i]); 
      if (currentHeight == 0) { 
        dataRectF.top = 346 * mRelativePxInHeight; 
      } else if (currentHeight == 100) { 
        dataRectF.top = 70 * mRelativePxInHeight; 
      } else { 
        if (animHeight >= currentHeight) { 
          dataRectF.top = 346 * mRelativePxInHeight - currentHeight / 100 * 276 * mRelativePxInHeight; 
        } else { 
          dataRectF.top = 346 * mRelativePxInHeight - 276 * mRelativePxInHeight * (animHeight / 100); 
        } 
      } 
      dataRectF.bottom = 346 * mRelativePxInHeight; 
//        限制最高高度 
      if (dataRectF.top < 70 * mRelativePxInHeight) { 
        dataRectF.top = 70 * mRelativePxInHeight; 
      } 
      canvas.drawRoundRect(dataRectF, 10, 10, dataPaint); 
    } 
  } 
  //實現柱子增長的動畫效果 
  @Override 
  public void run() { 
    animHeight += 1; 
    if (animHeight >= 276 * mRelativePxInHeight) { 
      return; 
    } else { 
      invalidate(); 
    } 
  } 
  @Override 
  public boolean onTouchEvent(MotionEvent event) { 
    switch (event.getAction()) { 
      case MotionEvent.ACTION_DOWN: { 
        //獲取點擊坐標 
        float x = event.getX(); 
        float y = event.getY(); 
        //判斷點擊點的位置 
        float leftx = 0; 
        float rightx = 0; 
        for (int i = 0; i < num; i++) { 
          leftx = 95 * mRelativePxInWidth + (i+ 1) * mDist * mRelativePxInWidth - mDist/2 * mRelativePxInWidth; 
          rightx = 105 * mRelativePxInWidth + (i+ 1) * mDist * mRelativePxInWidth + mDist/2 * mRelativePxInWidth; 
          if (x < leftx) { 
            continue; 
          } 
          if (leftx <= x && x <= rightx) { 
            //獲取點擊的柱子區域的y值 
            float top = 346 * mRelativePxInHeight - Float.parseFloat(data[num - 1 - i])/ 100 * 276 * mRelativePxInHeight; 
            float bottom = 346 * mRelativePxInHeight; 
            if (y >= top && y <= bottom) { 
              //判斷是否設置監聽 
              //將點擊的第幾條柱子,點擊柱子頂部的坐值,用於彈出dialog提示數據,還要返回百分比currentHeidht = Float.parseFloat(data[num - 1 - i]) 
              if(listener != null) { 
                Log.e("ss","x" + x +";y:" + y); 
                listener.onClick(i + 1, leftx + mDist/2,top,Float.parseFloat(data[num - 1 - i])); 
              } 
              break; 
            } 
          } 
        } 
        break; 
      } 
      case MotionEvent.ACTION_MOVE: 
        Log.e("touch", "ACTION_MOVE"); 
        break; 
      case MotionEvent.ACTION_UP: 
        Log.e("touch", "ACTION_UP"); 
        break; 
    } 
    return true; 
  } 
  /** 
   * 柱子點擊時的監聽接口 
   */ 
  public interface OnChartClickListener { 
    void onClick(int num, float x, float y, float value); 
  } 
  /** 
   * 設置柱子點擊監聽的方法 
   * @param listener 
   */ 
  public void setOnChartClickListener(OnChartClickListener listener) { 
    this.listener = listener; 
  } 
} 

  在xml文件中的應用:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout 
  xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  android:id="@+id/activity_main" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  android:orientation="vertical" 
  tools:context="com.example.histogram.MainActivity"> 
  <TextView 
    android:layout_width="match_parent" 
    android:layout_height="40dp" 
    android:gravity="center" 
    android:text="繁忙度指示圖(%)" 
    android:textSize="15sp" 
    android:textColor="#000000" 
    /> 
  <com.example.histogram.HistoGram 
    android:id="@+id/staticview" 
    android:layout_width="400dp" 
    android:layout_height="500dp" 
    android:layout_gravity="center_horizontal" 
    android:layout_marginBottom="14dp" 
    android:layout_marginTop="5dp"/> 
</LinearLayout> 

   在activity中的實現:

package com.example.histogram; 
import android.os.Bundle; 
import android.os.Handler; 
import android.support.v7.app.AppCompatActivity; 
import android.util.Log; 
import android.view.View; 
import android.widget.PopupWindow; 
import android.widget.TextView; 
public class MainActivity extends AppCompatActivity { 
  private PopupWindow mPopupWindow; 
  @Override 
  protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    final HistoGram histoGram = (HistoGram) findViewById(R.id.staticview); 
    String[] data ={"100","20","40","20","80","20","60","30","5","20","60","30","5","5","20","60","30","5"}; 
    final String[] title = {"1","2","3","4","5","6","7","8","9","6","7","8","9","9","6","7","8","9"}; 
    histoGram.setNum(title.length); 
    histoGram.setData(data); 
    histoGram.setxTitleString(title); 
    histoGram.setOnChartClickListener(new HistoGram.OnChartClickListener() { 
      @Override 
      public void onClick(int num, float x, float y, float value) { 
        //顯示提示窗 
        View inflate = View.inflate(MainActivity.this, R.layout.popupwindow, null); 
        TextView textView = (TextView) inflate.findViewById(R.id.main_tv); 
        textView.setText(value + "%\n" + title[num - 1]); 
        if(mPopupWindow != null) { 
          mPopupWindow.dismiss(); 
        } 
        mPopupWindow = new PopupWindow(inflate,140, 60, true); 
        mPopupWindow.setTouchable(true); 
        Log.e("ss","num" + num +";x" + x+";y"+ y + ";value" + value 
            +";(int)((- histoGram.getHeight()) + y - 65)" 
            +(int)((- histoGram.getHeight()) + y - 65) 
        + "histoGram.getHeight()" + histoGram.getHeight()); 
        // 設置好參數之後再show 
//        Toast.makeText(MainActivity.this, "num" + num +";x" + x+";y"+ y + ";value" + value 
//            +";popupWindow.getWidth()"+ mPopupWindow.getWidth()+";"+ mPopupWindow.getHeight(), Toast.LENGTH_SHORT).show(); 
        mPopupWindow.showAsDropDown(histoGram,(int)(x - 65),(int)((- histoGram.getHeight()) + y - 65) ); 
        mPopupWindow.setBackgroundDrawable(getResources().getDrawable(R.mipmap.databg_busyness)); 
        new Handler().postDelayed(new Runnable(){ 
          public void run() { 
            mPopupWindow.dismiss(); 
          } 
        }, 1000); 
      } 
    }); 
  } 
} 

以上所述是小編給大家介紹的Android自定義帶增長動畫和點擊彈窗提示效果的柱狀圖,實現一個模擬後台數據登入的效果,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對本站網站的支持!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved