編輯:關於Android編程
這段時間的自定義View學習,學會了繪制柱狀圖、繪制折線圖、繪制進度控件,那我們今天就來聊聊另外一種自定義的View,這就是我們常見的七日年化收益折線圖效果。先看看長什麼樣。
這就是效果圖了,元素相對而言還是比較多的,這裡有線、柱狀圖、文字、折線、點等等。看起來好像很復雜,但是呢,只要一步一步的實現,那還是可以達到這種效果的,之前我們說過的, 自定義View,就像是在photo shop裡面畫圖,想要什麼就畫什麼,我們可以有很多的畫筆工具,也可以有很多的圖層。
先看看我們這一次用到哪些變量。
private Paint mTextPaint, mLinePaint,mPathPaint,mPointPaint;
//柱狀圖的寬度
private float mPaintRectWidth;
//路徑
private Path mPath;
//高跟寬
private float mWidth, mHeight;
//柱狀圖的數量
private final float mCount = 6;
//偏移量
private final float offsets=1;
private float mRectHeight;
//x軸的坐標
private List xline=new ArrayList();
//Y軸的坐標
private List yline=new ArrayList();
//左邊文字
private float []x={2.46f,2.45f,2.44f,2.43f,2.42f,2.41f,2.40f};
//底部文字
private String [] day={"07-01","07-02","07-03","07-04","07-05","07-06","07-07"};
注釋標記的也是夠詳細了,為了大家能夠看得懂,也為了提高的博客質量,我們注意到,這裡有文字,有數量,基本涵蓋了我們這裡索要用到的所有的變量。
下面開始初始化操作。
private void initView() {
//繪制線和文字的顏色
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setColor(Color.parseColor("#cccccc"));
mTextPaint.setTextSize(25);
mTextPaint.setStrokeWidth(1);
//繪制折線圖的點
mPointPaint= new Paint();
mPointPaint.setAntiAlias(true);
mPointPaint.setColor(Color.parseColor("#000000"));
mPointPaint.setTextSize(25);
mPointPaint.setStrokeWidth(5);
//繪制柱狀圖的畫筆
mLinePaint = new Paint();
mLinePaint.setAntiAlias(true);
//繪制折線圖的畫筆
mPathPaint= new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setColor(Color.parseColor("#ff0000"));
mPathPaint.setStyle(Style.STROKE);
//折線圖的路徑
mPath=new Path();
}
這裡主要就是給畫筆初始化,可以看到每一個畫筆的顏色、寬度都是不一樣的,值的注意的是,這裡面的畫筆並沒有設置镂空樣式。
接下來我們看看怎麼去賦值,老規矩,我們還是選擇在onSizeChange()裡面進行賦值,代碼如下:
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth=(float)(getWidth()-getWidth()*0.1);
mHeight=(float)(getHeight()-getHeight()*0.1);
mRectHeight=(float)(getHeight()-getHeight()*0.1);
mPaintRectWidth=(float) (mWidth*0.8/mCount);
mLinePaint.setStrokeWidth(mPaintRectWidth);
}
跟之前的不一樣,我們以前所要用的寬度跟高度,直接就是使用方法裡的,但是現在我們沒有這麼做,例如:(float)(getWidth()-getWidth()*0.1);我們進行了一定的處理,這樣可以提高頁面的舒適性,提高用戶體驗。
好了,准備工作做好了,接下來看看onDraw方法裡面的操作,代碼如下:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
onDrawRect(canvas);
onDrawLine(canvas);
canvasPath(canvas);
}
喲呵,怎麼這麼簡單,就三個東西?對的,就是這麼簡單粗暴,從名字中也可以看出,第一個是繪制矩形,第二個繪制線,第三個就是繪制折線。是不是很快呢,下面看看具體的實現方式。
第一個方法:
//繪制6個矩形
private void onDrawRect(Canvas canvas) {
for (int i = 0; i < 7; i++) {
if (i%2==0) {
mLinePaint.setColor(Color.parseColor("#eeeeee"));
}else {
mLinePaint.setColor(Color.parseColor("#ece1f3"));
}
float left =(float) (mWidth * 0.4 / 2 + mPaintRectWidth * i + offsets);
float right=(float) (mWidth * 0.4 / 2 + mPaintRectWidth* (i + 1));
canvas.drawRect(left,(float)(mRectHeight*0.01),right, mHeight, mLinePaint);
}
}
第二個:
//繪制網格線
private void onDrawLine(Canvas canvas){
//第一條線
canvas.drawLine(mPaintRectWidth-mPaintRectWidth/2, (float)(mRectHeight*0.01), getWidth(), (float)(mRectHeight*0.01), mTextPaint);
//定義這裡高度
float height;
//橫七條
for (float i = 0; i < 7; i++) {
//從上到下
if (i==0) {
height=i;
}else {
height=mRectHeight*(i/6);
float size=mTextPaint.measureText(x[(int)i]+"");
//繪制線
canvas.drawLine(mPaintRectWidth+mPaintRectWidth/2, height, getWidth(), height, mTextPaint);
//繪制左邊Y軸的文字
canvas.drawText(x[(int)i]+"", (float)(mPaintRectWidth-mPaintRectWidth*0.35), height+size/5, mTextPaint);
}
}
//豎七條
canvas.drawLine((float) (mPaintRectWidth-mPaintRectWidth/2),0, (float) (mPaintRectWidth-mPaintRectWidth/2), mHeight, mTextPaint);
for (float i = 0; i < 7; i++) {
//從左到右
canvas.drawLine((float) (mWidth * 0.4 / 2 + mPaintRectWidth * i),0, (float) (mWidth * 0.4 / 2 + mPaintRectWidth * i), mHeight, mTextPaint);
//繪制底邊的日期文字
canvas.drawText(day[(int) i], (float) (mWidth * 0.34 / 2 + mPaintRectWidth * i), (float)(mHeight+mHeight*0.1), mTextPaint);
//准備好下面折線圖的X軸坐標
xline.add((float) (mWidth * 0.4 / 2 + mPaintRectWidth * i));
}
//折線圖的第一個點
xline.add((float) (mPaintRectWidth-mPaintRectWidth/2));
}
這裡的代碼相對較多,我專門加了許多的注釋,可以用心的看看。
第三個繪制折線:
//繪制折線路徑
public void canvasPath(Canvas canvas){
for (int j = 0; j < yline.size(); j++) {
float x=xline.get(j);
float y =yline.get(j);
float aftery=Math.initData(y);
if (j==0) {
mPath.moveTo(x,aftery );
}else{
mPath.lineTo(x,aftery );
}
canvas.drawPoint(x, aftery, mPointPaint);
float size=mPointPaint.measureText(y+"");
canvas.drawText(y+"", (float)(x-size/2), (float)(aftery+size*0.25), mPointPaint);
}
canvas.drawPath(mPath, mPathPaint);
}
這裡的繪制折線包括繪制線、點、文字、還有文字的轉換、但是這個轉換可以根據自己的需求來進行定制。
最後向外面暴露一個方法,用於更新坐標。
//用於設置Y軸的坐標值
public void setDataY( List yline) {
this.yline.clear();
this.yline=yline;
}
//一個更新UI的方法
public void invalidata(){
invalidate();
}
文字的轉換我這裡用一個自己的類去處理了,代碼如下:
public static float initData(float a){
if (2.40f<=a&&a<2.41f) {
a=540f-540f/(a/0.01f);
}else if(2.41f<=a&&a<2.42f){
a=480f-480f/(a/0.01f);
}else if (2.42f<=a&&a<2.43f) {
a=360f-360f/(a/0.01f);
}else if (2.43f<=a&&a<2.44f) {
a=270f-270f/(a/0.01f);
}else if (2.44f<=a&&a<2.45f) {
a=180f-180f/(a/0.01f);
}else if (2.45f<=a&&a<2.46f) {
a=90f-90f/(a/0.01f);
}
return a;
}
以上就是邏輯的實現過程了。最後,我把所有代碼貼上來:
AnnualyieldView.java
/**
* 小瓶蓋 2016年7月13日18:08:28
*
* @author Android自定義View——實現理財類APP七日年化收益折線圖效果
*
*相關博客地址 http://blog.csdn.net/qq_25193681
*/
public class AnnualyieldView extends View {
private Paint mTextPaint, mLinePaint,mPathPaint,mPointPaint;
//柱狀圖的寬度
private float mPaintRectWidth;
//路徑
private Path mPath;
//高跟寬
private float mWidth, mHeight;
//柱狀圖的數量
private final float mCount = 6;
//偏移量
private final float offsets=1;
private float mRectHeight;
//x軸的坐標
private List xline=new ArrayList();
//Y軸的坐標
private List yline=new ArrayList();
//左邊文字
private float []x={2.46f,2.45f,2.44f,2.43f,2.42f,2.41f,2.40f};
//底部文字
private String [] day={"07-01","07-02","07-03","07-04","07-05","07-06","07-07"};
public AnnualyieldView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
public AnnualyieldView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public AnnualyieldView(Context context) {
super(context);
initView();
}
private void initView() {
//繪制線和文字的顏色
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setColor(Color.parseColor("#cccccc"));
mTextPaint.setTextSize(25);
mTextPaint.setStrokeWidth(1);
//繪制折線圖的點
mPointPaint= new Paint();
mPointPaint.setAntiAlias(true);
mPointPaint.setColor(Color.parseColor("#000000"));
mPointPaint.setTextSize(25);
mPointPaint.setStrokeWidth(5);
//繪制柱狀圖的畫筆
mLinePaint = new Paint();
mLinePaint.setAntiAlias(true);
//繪制折線圖的畫筆
mPathPaint= new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setColor(Color.parseColor("#ff0000"));
mPathPaint.setStyle(Style.STROKE);
//折線圖的路徑
mPath=new Path();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth=(float)(getWidth()-getWidth()*0.1);
mHeight=(float)(getHeight()-getHeight()*0.1);
mRectHeight=(float)(getHeight()-getHeight()*0.1);
mPaintRectWidth=(float) (mWidth*0.8/mCount);
mLinePaint.setStrokeWidth(mPaintRectWidth);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
onDrawRect(canvas);
onDrawLine(canvas);
canvasPath(canvas);
}
//繪制6個矩形
private void onDrawRect(Canvas canvas) {
for (int i = 0; i < 7; i++) {
if (i%2==0) {
mLinePaint.setColor(Color.parseColor("#eeeeee"));
}else {
mLinePaint.setColor(Color.parseColor("#ece1f3"));
}
float left =(float) (mWidth * 0.4 / 2 + mPaintRectWidth * i + offsets);
float right=(float) (mWidth * 0.4 / 2 + mPaintRectWidth* (i + 1));
canvas.drawRect(left,(float)(mRectHeight*0.01),right, mHeight, mLinePaint);
}
}
//繪制網格線
private void onDrawLine(Canvas canvas){
//第一條線
canvas.drawLine(mPaintRectWidth-mPaintRectWidth/2, (float)(mRectHeight*0.01), getWidth(), (float)(mRectHeight*0.01), mTextPaint);
//定義這裡高度
float height;
//橫七條
for (float i = 0; i < 7; i++) {
//從上到下
if (i==0) {
height=i;
}else {
height=mRectHeight*(i/6);
float size=mTextPaint.measureText(x[(int)i]+"");
//繪制線
canvas.drawLine(mPaintRectWidth+mPaintRectWidth/2, height, getWidth(), height, mTextPaint);
//繪制左邊Y軸的文字
canvas.drawText(x[(int)i]+"", (float)(mPaintRectWidth-mPaintRectWidth*0.35), height+size/5, mTextPaint);
}
}
//豎七條
canvas.drawLine((float) (mPaintRectWidth-mPaintRectWidth/2),0, (float) (mPaintRectWidth-mPaintRectWidth/2), mHeight, mTextPaint);
for (float i = 0; i < 7; i++) {
//從左到右
canvas.drawLine((float) (mWidth * 0.4 / 2 + mPaintRectWidth * i),0, (float) (mWidth * 0.4 / 2 + mPaintRectWidth * i), mHeight, mTextPaint);
//繪制底邊的日期文字
canvas.drawText(day[(int) i], (float) (mWidth * 0.34 / 2 + mPaintRectWidth * i), (float)(mHeight+mHeight*0.1), mTextPaint);
//准備好下面折線圖的X軸坐標
xline.add((float) (mWidth * 0.4 / 2 + mPaintRectWidth * i));
}
//折線圖的第一個點
xline.add((float) (mPaintRectWidth-mPaintRectWidth/2));
}
//繪制折線路徑
public void canvasPath(Canvas canvas){
for (int j = 0; j < yline.size(); j++) {
float x=xline.get(j);
float y =yline.get(j);
float aftery=Math.initData(y);
if (j==0) {
mPath.moveTo(x,aftery );
}else{
mPath.lineTo(x,aftery );
}
canvas.drawPoint(x, aftery, mPointPaint);
float size=mPointPaint.measureText(y+"");
canvas.drawText(y+"", (float)(x-size/2), (float)(aftery+size*0.25), mPointPaint);
}
canvas.drawPath(mPath, mPathPaint);
}
//用於設置Y軸的坐標值
public void setDataY( List yline) {
this.yline.clear();
this.yline=yline;
}
//一個更新UI的方法
public void invalidata(){
invalidate();
}
}
MainActivity.java
/**
* 小瓶蓋 2016年7月13日18:08:28
*
* @author Android自定義View——實現理財類APP七日年化收益折線圖效果
*
*相關博客地址 http://blog.csdn.net/qq_25193681
*/
public class MainActivity extends Activity {
private AnnualyieldView annualyieldView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
annualyieldView=(AnnualyieldView) findViewById(R.id.line);
initdata();
}
private void initdata() {
List yline=new ArrayList();
yline.add(2.420123f);
yline.add(2.444122f);
yline.add(2.45359f);
yline.add(2.4206f);
yline.add(2.4357f);
yline.add(2.4228f);
yline.add(2.4350f);
annualyieldView.setDataY(yline);
}
}
布局文件activity_main.xml:
還有一個用於轉換的類,Math.java
/**
* 小瓶蓋 2016年7月13日18:08:28
*
* @author Android自定義View——實現理財類APP七日年化收益折線圖效果
*
*相關博客地址 http://blog.csdn.net/qq_25193681
*/
public class Math {
public static float initData(float a){
if (2.40f<=a&&a<2.41f) {
a=540f-540f/(a/0.01f);
}else if(2.41f<=a&&a<2.42f){
a=480f-480f/(a/0.01f);
}else if (2.42f<=a&&a<2.43f) {
a=360f-360f/(a/0.01f);
}else if (2.43f<=a&&a<2.44f) {
a=270f-270f/(a/0.01f);
}else if (2.44f<=a&&a<2.45f) {
a=180f-180f/(a/0.01f);
}else if (2.45f<=a&&a<2.46f) {
a=90f-90f/(a/0.01f);
}
return a;
}
}
以上就是代碼的全部內容,我記得我大學的老實說,不懂的地方就自己多敲代碼,多了就懂了,雖然那時候我不認同,但是現在覺得還是有一定道理,都是一樣過來的,現在希望能夠跟大家一起進步。
技術概念來源:[ 360開源插件框架,項目地址:https://github.com/DroidPluginTeam/DroidPlugin]一、Binder機制回顧在之
本文實例總結了Android TextView高級顯示技巧。分享給大家供大家參考,具體如下:1. 自定義字體可以使用setTypeface(Typeface)方法來設置文
Android中的傳遞有兩個方法,一個是Serializable,另一個是Parcelable。 Serializable是J2SE本身就支持的。而Parc
有很多地方要用到DatePickerDialog。但有時項目用到的主題樣式是很丑的樣式,顯示出來的真丑。而我們真正想要的樣式是這樣的。這個就漂亮多了。而且很多的時候都不需