編輯:關於Android編程
最近在做項目的時候,有個功能是訂單流程每個階段的時間段,這個和購物或者外賣的時候的下單、接單、配送類似!請看下圖
剛開始的做的時候,沒有想過自定義還是按照之前的想法,ui作圖根據狀態替換圖片之類的,後面做著做著感覺好煩,而且這個為了以後方便人調用之類的,所以開始自定義封裝!
分析:
1:總共有五個狀態,已支付、已接單、等待配送、已簽收、待評價
這五個點根據屏幕五等分,每個圓心按照比例相加畫大空心圓和小的實心圓。
2:畫實線和虛線,根據五等分的比例算出每兩個相鄰的圓之間的x
長度,左右兩邊分別加2和減2(留出縫隙處理),這樣就可以畫出
實線和虛線(實線和虛線根據數據來處理)虛線處理稍微復雜一點,見代碼注解
3:現在畫時間和狀態,這裡需要居中處理,剛開始的沒有處理,導致字體和圓心沒有垂直居中!具體的處理的方法代碼有明確說明
給出自定義類:
package org.yidont.ylife.send.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import org.yidont.ylife.send.R;
import org.yidont.ylife.send.bean.OrderStatusDescribeInfo;
import java.util.ArrayList;
import java.util.List;
/**
* Created by li4236 on 16/6/21.
* li4236@aliyun.com
*/
public class CustomRoundTrue extends View {
private final Paint paint;
private final Context context;
public CustomRoundTrue(Context context) {
// TODO Auto-generated constructor stub
this(context, null);
}
public CustomRoundTrue(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
this.context = context;
this.paint = new Paint();
this.paint.setAntiAlias(true); //消除鋸齒
this.paint.setStyle(Paint.Style.FILL); //繪制空心圓
}
// int number = 5;
int radius = 30;//圓的半徑
int vivio = 4;//控制顯示多少個實心圓
// int state = 2;//控制底部文字顯示
float mFloat[];
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
//平分控件的高度,每段的高度
radius = dip2px(15);
int height =getHeight() / 2;
//平分寬度十等分
int width = getWidth() / (5 * 2);
//畫虛線的設置////////start///////////
int cc = 2 * width - 2 * radius - 4;//計算虛線或者實線的寬度 ,-4是因為左右兩邊圓各自留出2的距離 查看99和100行
mFloat = new float[cc / 2];
for (int i = 0; i < cc / 2; i++) {
mFloat[i] = 3;//虛線的寬度初始化
}
//畫虛線的大小////////end///////////
//1 畫最上層的圓///////////////start//////////////
int circleY = height - radius - radius / 2;
for (int i = 0; i < mornal.size(); i++) {
OrderStatusDescribeInfo info = mornal.get(i);
int circleX = width + i * 2 * width;
this.paint.setARGB(255, 153, 153, 153);
this.paint.setStrokeWidth(2);
if (info.getStatus().equals("0")) { //畫虛圓
canvas.drawCircle(circleX, circleY, radius, this.paint);
} else { //畫實圓
drawReal(circleX, circleY, canvas);
}
}
boolean really = false;
for (int j = 0; j < mornal.size()-1; j++) { //畫線
really = true;
int n = j+1;
if (n < mornal.size())
{
OrderStatusDescribeInfo info1 = mornal.get(n);
if (info1.getStatus().equals("0"))//獲取下一個數據是空的
really = false;
}
int lineX = width + j * 2 * width + radius + 2; //+2是為了留出縫隙
int lineX1 = (width + j * 2 * width) + 2 * width - radius - 2;//-2是為了留出縫隙
if (!really) { //畫虛線
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.DKGRAY);
Path path = new Path();
path.moveTo(lineX, circleY);//起點 x/y
path.lineTo(lineX1, circleY);//終點 x/y
PathEffect effects = new DashPathEffect(mFloat, 1);//虛線數組
paint.setPathEffect(effects);
canvas.drawPath(path, paint);
} else {//畫實線
this.paint.setARGB(255, 255, 108, 0);
canvas.drawLine(lineX, circleY, lineX1, circleY, paint);
}
}
//1 畫最上層的圓///////////////end//////////////
//2 畫最下層的文字///////////////start//////////////
int txtY = height + radius;//第一行文字的Y高度
Paint mPaintLines = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintLines.setStrokeWidth(3);
mPaintLines.setTextSize(dip2px(14));
mPaintLines.setTextAlign(Paint.Align.LEFT);
Rect rect = new Rect();
for (int i = 0; i < mornal.size(); i++) {
OrderStatusDescribeInfo info = mornal.get(i);
int lineX = width + i * 2 * width;//每個字符串x坐標
mPaintLines.getTextBounds(info.getText(), 0, 1, rect);//可以獲取字體寬高
float awayY2 = txtY + rect.height() + radius / 2;//底層文字y高度計算
if (info.getStatus().equals("1")) {//需要顯示的時間和文字
//畫時間
mPaintLines.setColor(getResources().getColor(R.color.send_time));
mPaintLines.getTextBounds(info.getTime(), 0, info.getTime().length(), rect);
canvas.drawText(info.getTime(), lineX - rect.width() / 2, txtY, mPaintLines);
//畫送貨的狀態
mPaintLines.setColor(getResources().getColor(R.color.send_state));
mPaintLines.getTextBounds(info.getText(), 0, info.getText().length(), rect);
canvas.drawText(info.getText(), lineX - rect.width() / 2, awayY2, mPaintLines);
} else {
//單個送貨的狀態
mPaintLines.setColor(getResources().getColor(R.color.send_state_gray));
mPaintLines.getTextBounds(info.getText(), 0, info.getText().length(), rect);
canvas.drawText(info.getText(), lineX - rect.width() / 2, awayY2, mPaintLines);
// //單個送貨的狀態 ======= 居中顯示
// mPaintLines.setColor(getResources().getColor(R.color.send_state_gray));
// mPaintLines.getTextBounds(info.getText(), 0, info.getText().length(), rect);
//
// float awayY = awayY2 / 2 + height / 2 + rect.height() / 2;//設置字體垂直居中計算高度
// canvas.drawText(info.getText(), lineX - rect.width() / 2, awayY, mPaintLines);
}
}
//2 畫最下層的文字///////////////end//////////////
super.onDraw(canvas);
}
public void drawReal(int x, int y, Canvas canvas) {
// 繪制外圓
this.paint.setARGB(255, 255, 108, 0);
this.paint.setStrokeWidth(2);
canvas.drawCircle(x, y, radius, this.paint);
//繪制圓環
this.paint.setColor(Color.WHITE);
// this.paint.setStrokeWidth(ringWidth);
canvas.drawCircle(x, y, radius - 3, this.paint);
//繪制內圓
this.paint.setARGB(255, 255, 108, 0);
this.paint.setStrokeWidth(2);
canvas.drawCircle(x, y, radius / 3, this.paint);
}
/**
* 根據手機的分辨率從 dp 的單位 轉成為 px(像素)
*/
public int dip2px( float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
public List mornal = new ArrayList<>();
public void setMornal(List mornal) {
this.mornal = mornal;
vivio = mornal.size();//控制顯示多少個實心圓
invalidate();
}
}
實體類:
package org.yidont.ylife.send.bean;
/**
* Created by li4236 on 16/7/28.
* li4236@aliyun.com
*/
public class OrderStatusDescribeInfo {
private String status;
private String time;
private String text;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
布局使用:
使用方法:
CustomRoundTrue mRoundTrue = (CustomRoundTrue) findViewById(R.id.send_round);
List mornal = new ArrayList<>();
mRoundTrue.setMornal(mornal);
實際項目效果圖

Android N Preview 行為變更 (版本的 更改)
行為變更Android N 除了提供諸多新特性和功能外,還對系統和 API 行為做出了各種變更。本文重點介紹您應該了解並在開發應用時加以考慮的一些重要變更。如果您之前發布
android 自定義View彎曲滑竿指示器
效果說明:滑竿指示器,是一段彎曲的圓弧,要求在桿上,有滑動小球事件,小球會根據下標文字的起始角度與終止角度,是否選擇滑倒下一個位置。當點擊下標文字時,小球也要做出相應的
如何使用字體管家為qq換字體
字體管家是最好的字體下載工具,提供字體下載、字體備份、字體預覽、字體修復功能,永久免費的好軟件,為您提供最好用的字體下載字體備份字體安裝軟件。我們來看看如何
Android自定義View實現縱向跑馬燈效果詳解
首先看看效果圖(錄制的gif有點卡,真實的效果還是很流暢的)實現思路通過上面的gif圖可以得出結論,其實它就是同時繪制兩條文本信息,然後通過動畫不斷的改變兩條文本信息距離