StepView
Step by step. Step indicator. Flow indicator。
github地址:stepview
snapshot
like this
also like this:VerticalStepView
Yeah,also like this
how to use
Add it in your root build.gradle at the end of repositories:
repositories {
...
maven { url "https://jitpack.io" }
}
Step 2. Add the dependency
dependencies {
compile 'com.github.baoyachi:StepView:1.2'
}
use HorizontalStepView
in xml
<com.baoyachi.stepview.HorizontalStepView
android:id="@+id/step_view0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="@android:color/white"
android:textSize="14sp"
/>
use code
HorizontalStepView setpview0 = (HorizontalStepView) mView.findViewById(R.id.step_view0);
List<String> list0 = new ArrayList<>();
list0.add("接單");
list0.add("打包");
list0.add("出發(fā)");
list0.add("送單");
list0.add("完成");
list0.add("支付");
setpview0.setStepsViewIndicatorComplectingPosition(2)//設(shè)置完成的步數(shù)
.setStepViewTexts(list0)//總步驟
.setStepsViewIndicatorCompletedLineColor(ContextCompat.getColor(getActivity(), android.R.color.white))//設(shè)置StepsViewIndicator完成線的顏色
.setStepsViewIndicatorUnCompletedLineColor(ContextCompat.getColor(getActivity(), R.color.uncompleted_text_color))//設(shè)置StepsViewIndicator未完成線的顏色
.setStepViewComplectedTextColor(ContextCompat.getColor(getActivity(), android.R.color.white))//設(shè)置StepsView text完成線的顏色
.setStepViewUnComplectedTextColor(ContextCompat.getColor(getActivity(), R.color.uncompleted_text_color))//設(shè)置StepsView text未完成線的顏色
.setStepsViewIndicatorCompleteIcon(ContextCompat.getDrawable(getActivity(), R.drawable.complted))//設(shè)置StepsViewIndicator CompleteIcon
.setStepsViewIndicatorDefaultIcon(ContextCompat.getDrawable(getActivity(), R.drawable.default_icon))//設(shè)置StepsViewIndicator DefaultIcon
.setStepsViewIndicatorAttentionIcon(ContextCompat.getDrawable(getActivity(), R.drawable.attention));//設(shè)置StepsViewIndicator AttentionIcon
use VerticalStepView
in xml
<com.baoyachi.stepview.VerticalStepView
android:id="@+id/step_view0"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="vertical setpview"
/>
in code
mSetpview0 = (VerticalStepView) mView.findViewById(R.id.step_view0);
List<String> list0 = new ArrayList<>();
list0.add("接已提交定案,等待系統(tǒng)確認(rèn)");
list0.add("您的商品需要從外地調(diào)撥,我們會(huì)盡快處理,請(qǐng)耐心等待");
list0.add("您的訂單已經(jīng)進(jìn)入亞洲第一倉(cāng)儲(chǔ)中心1號(hào)庫(kù)準(zhǔn)備出庫(kù)");
list0.add("您的訂單預(yù)計(jì)6月23日送達(dá)您的手中,618期間促銷火爆,可能影響送貨時(shí)間,請(qǐng)您諒解,我們會(huì)第一時(shí)間送到您的手中");
list0.add("您的訂單已打印完畢");
list0.add("您的訂單已揀貨完成");
list0.add("掃描員已經(jīng)掃描");
list0.add("打包成功");
list0.add("配送員【包牙齒】已出發(fā),聯(lián)系電話【130-0000-0000】,感謝您的耐心等待,參加評(píng)價(jià)還能贏取好多禮物哦");
list0.add("感謝你在京東購(gòu)物,歡迎你下次光臨!");
mSetpview0.setStepsViewIndicatorComplectingPosition(list0.size() - 2)//設(shè)置完成的步數(shù)
.setStepViewTexts(list0)//總步驟
.setStepsViewIndicatorCompletedLineColor(ContextCompat.getColor(getActivity(), android.R.color.white))//設(shè)置StepsViewIndicator完成線的顏色
.setStepsViewIndicatorUnCompletedLineColor(ContextCompat.getColor(getActivity(), R.color.uncompleted_text_color))//設(shè)置StepsViewIndicator未完成線的顏色
.setStepViewComplectedTextColor(ContextCompat.getColor(getActivity(), android.R.color.white))//設(shè)置StepsView text完成線的顏色
.setStepViewUnComplectedTextColor(ContextCompat.getColor(getActivity(), R.color.uncompleted_text_color))//設(shè)置StepsView text未完成線的顏色
.setStepsViewIndicatorCompleteIcon(ContextCompat.getDrawable(getActivity(), R.drawable.complted))//設(shè)置StepsViewIndicator CompleteIcon
.setStepsViewIndicatorDefaultIcon(ContextCompat.getDrawable(getActivity(), R.drawable.default_icon))//設(shè)置StepsViewIndicator DefaultIcon
.setStepsViewIndicatorAttentionIcon(ContextCompat.getDrawable(getActivity(), R.drawable.attention));//設(shè)置StepsViewIndicator AttentionIcon
Use So Simple!!!
See Detail
you can see thereExample
Introduction
現(xiàn)在,絕大部分公司對(duì)于一個(gè)項(xiàng)目訂單流程控制不外乎從訂單的初始狀態(tài)到訂單完成的狀態(tài),總結(jié)起來(lái)就是關(guān)于一個(gè)物體(訂單/工單)狀態(tài)變化的事物屬性。所以就有了下面類似圖片的效果,從訂單的初始狀態(tài)到訂單完成。一個(gè)好的流程展示,對(duì)于工作效率的提高尤其的關(guān)鍵。該庫(kù)代碼看起來(lái)簡(jiǎn)潔,加上了詳細(xì)的備注,看起來(lái)不會(huì)那么枯燥,也方便定制。那么廢話不多說(shuō),直接進(jìn)入正題。
preview
可能當(dāng)前的StepView展示的點(diǎn)是動(dòng)態(tài)的,有時(shí)候是兩個(gè),有時(shí)候是三個(gè),有時(shí)候是四個(gè)甚至五個(gè)六個(gè),之前有想過(guò)展示成下面的效果。
但是當(dāng)stepview的個(gè)數(shù)為2時(shí)效果太丑,一個(gè)距最左邊,一個(gè)距左右邊。能不忍,改吧,改了變成下面的效果
上下對(duì)比下是不是好看了很多呢。
What can be learned about this page
好了,我們通過(guò)這篇文章可以學(xué)習(xí)哪些知識(shí)呢?
- 自定義控件的加強(qiáng)
- Canvas,Paint的使用
- 如何繪制矩形
- 如何繪制虛線
- 如何繪制圓
- 加上小小的數(shù)學(xué)計(jì)算,哈哈,開個(gè)小玩笑,學(xué)過(guò)數(shù)學(xué),應(yīng)該不成問(wèn)題!
start-pre
寫這個(gè)開源項(xiàng)目前的熱身
- 首先我們來(lái)畫一個(gè)矩形
public class RectView extends View
{
public RectView(Context context)
{
super(context);
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
setBackgroundResource(R.drawable.default_bg);//設(shè)置背景色
//----繪制矩形------------
Paint paint = new Paint();// 定義畫筆
paint.setStyle(Paint.Style.FILL);//設(shè)置實(shí)心
paint.setAntiAlias(true);// 消除鋸齒
paint.setColor(Color.WHITE);//設(shè)置畫筆顏色
paint.setStrokeWidth(40);// 設(shè)置paint的外框?qū)挾? canvas.drawRect(200, 200, 800, 220, paint);//繪制矩形
//----繪制矩形------------
}
}
}
如下圖:繪制矩形,因?yàn)槔L制矩形需要知道左上又下四個(gè)點(diǎn)的坐標(biāo)。
我們?cè)O(shè)置好四個(gè)點(diǎn)的坐標(biāo),繪制如下圖
接上面繪制圓
//----繪制圓---------------------
canvas.drawCircle(350, 350, 100, paint);
//----繪制圓---------------------
因?yàn)槔L制圓需要圓點(diǎn)和半徑,定義好后,展示如下:
接著繪制虛線
//----繪制虛線---------------------
Paint pathPaint = new Paint();
pathPaint.setAntiAlias(true);
pathPaint.setColor(Color.WHITE);
pathPaint.setStyle(Paint.Style.STROKE);
pathPaint.setStrokeWidth(2);
DashPathEffect mEffects = new DashPathEffect(new float[]{8, 8, 8, 8}, 1);
Path path = new Path();
path.moveTo(200, 600);
path.lineTo(800, 600);
pathPaint.setPathEffect(mEffects);
canvas.drawPath(path, pathPaint);
//----繪制虛線---------------------
}
}
這里用到一個(gè)新控件
DashPathEffect:DashPathEffect是PathEffect類的一個(gè)子類,可以使paint畫出類似虛線的樣子,并且可以任意指定虛實(shí)的排列方式.
好了,我們通過(guò)canvas.drawPath(path, pathPaint)繪制如下圖
難點(diǎn)說(shuō)完了,我們就開始我們的項(xiàng)目吧。
構(gòu)成
我們拿這個(gè)局部圖來(lái)做‘栗子’:
因此整個(gè)這一張圖是一個(gè)組合控件,
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.baoyachi.stepview.StepsViewIndicator
android:id="@+id/steps_indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"/>
<RelativeLayout
android:id="@+id/rl_text_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
上面是我們自定義的StepsViewIndicator,
下面是我們展示的文字,因?yàn)槭嵌鄠€(gè)文字組合,我們下面應(yīng)該是一個(gè)ViewGroup容器
分析:
-
如何做到居中顯示
1.首先得到該控件的寬度。
2.其次得到當(dāng)前控件距離最左邊值。然后計(jì)算當(dāng)前有幾個(gè)圓,幾個(gè)條線?這個(gè)是外部傳遞進(jìn)來(lái)的,告訴該控件當(dāng)前共有幾個(gè)步驟,并且當(dāng)前正在執(zhí)行到哪一步?
當(dāng)前控件距離最左邊值,定義為:paddingLeft;
當(dāng)前控件的寬度:getWidth();
圓的半徑:mCircleRadius;
兩條線之前的padding值:mLinePadding;
這么說(shuō)可能不怎么明白,舉個(gè)‘栗子’。
1.假設(shè)當(dāng)前共有一步: 接單。
意味當(dāng)前有一個(gè)圓,沒(méi)有連線,得出paddingLeft
float paddingLeft= (getWidth() - 1*(mCircleRadius*2)-0*mLinePadding)/2;
2.假設(shè)當(dāng)前共有二步:接單->打包
意味當(dāng)前有兩個(gè)圓,之前有一條連線,得出paddingLeft
float paddingLeft= (getWidth() - 2*(mCircleRadius*2)-1*mLinePadding)/2;
3.假設(shè)當(dāng)前共有三步:接單->打包->出發(fā)
意味當(dāng)前有三個(gè)圓,之前有二條連線,得出paddingLeft
float paddingLeft= (getWidth() - 3(mCircleRadius2)-2*mLinePadding)/2;
4.假設(shè)當(dāng)前共有四步:接單->打包->出發(fā)->送單
意味當(dāng)前有四個(gè)圓,之前有三條連線,得出paddingLeft
float paddingLeft= (getWidth() - 4*(mCircleRadius*2)-3*mLinePadding)/2;
5.假設(shè)當(dāng)前共有五步:接單->打包->出發(fā)->送單->完成
意味著我當(dāng)前有五個(gè)圓,五個(gè)圓中間有四條線相連接,這樣我們可以得到五個(gè)圓的直徑+四條線的長(zhǎng)度,這樣我們就可以得到最左邊的paddingLeft的值:
float paddingLeft= getWidth() - 5*(mCircleRadius*2)-4*mLinePadding;
綜上所述:
得出一個(gè)計(jì)算公式:其中mStepNum:當(dāng)前控件所展示的步數(shù)。
float paddingLeft= (getWidth() - 5*(mCircleRadius*2)-4*mLinePadding)/2;
所以,paddingLeft就可以動(dòng)態(tài)展示出來(lái),這樣我們就可以知道所有步數(shù)對(duì)應(yīng)圓的中心點(diǎn)的位置了:其中mComplectedXPosition為裝所有圓中心點(diǎn)的集合。
for(int i = 0; i < mStepNum; i++)
{
//先計(jì)算全部最左邊的padding值(getWidth()-(圓形直徑+兩圓之間距離)*2)
float paddingLeft = (getWidth() - mStepNum * mCircleRadius * 2 - (mStepNum - 1) * mLinePadding) / 2;
mComplectedXPosition.add(paddingLeft + mCircleRadius + i * mCircleRadius * 2 + i * mLinePadding);
}
Global graph 我們先來(lái)看下面這張動(dòng)態(tài)全局預(yù)覽圖.
我們來(lái)看下全局預(yù)覽圖,當(dāng)前StepView的展示是根據(jù)StepView的位置動(dòng)態(tài)調(diào)整的。
是不是有了上面的小知識(shí)點(diǎn)的引導(dǎo),這張圖看起后,是不是思路就清晰許多了呢!是的,StepView本身就是有圖片矩形和虛線繪制而成,下面我們進(jìn)行拆分。
一步步解析。
第一步 init() 初始化
因?yàn)樵搗iew分為完成塊和未完成塊,因此,init()主要是在做一些初始化的信息設(shè)置
private void init()
{
mPath = new Path();
mEffects = new DashPathEffect(new float[]{8, 8, 8, 8}, 1);
mComplectedXPosition = new ArrayList<>();//初始化
//設(shè)置未完成mUnCompletedPaint的初始化設(shè)置
mUnCompletedPaint = new Paint();
mCompletedPaint = new Paint();
mUnCompletedPaint.setAntiAlias(true);
mUnCompletedPaint.setColor(mUnCompletedLineColor);
mUnCompletedPaint.setStyle(Paint.Style.STROKE);
mUnCompletedPaint.setStrokeWidth(2);
//設(shè)置完成mCompletedPaint的初始化設(shè)置
mCompletedPaint.setAntiAlias(true);
mCompletedPaint.setColor(mCompletedLineColor);
mCompletedPaint.setStyle(Paint.Style.STROKE);
mCompletedPaint.setStrokeWidth(2);
mUnCompletedPaint.setPathEffect(mEffects);
mCompletedPaint.setStyle(Paint.Style.FILL);
.
.
.
}
-
定義已完成成線(矩形)mCompletedLineHeight的高度:
mCompletedLineHeight = 0.05f * defaultStepIndicatorNum;
定義圓的半徑:
mCircleRadius = 0.28f * defaultStepIndicatorNum;定義線與線之前的間距
mLinePadding = 0.85f * defaultStepIndicatorNum;//線與線之間的間距
不要問(wèn)我這線是怎么算出來(lái)的,我也是慢慢調(diào)出來(lái)的!!!-
定義三個(gè)狀態(tài)的圖片
mCompleteIcon = ContextCompat.getDrawable(getContext(), R.drawable.complted);//已經(jīng)完成的icon mAttentionIcon = ContextCompat.getDrawable(getContext(), R.drawable.attention);//正在進(jìn)行的icon mDefaultIcon = ContextCompat.getDrawable(getContext(), R.drawable.default_icon);//未完成的icon
第二步
- onMeasure()
哈哈,好熟悉的方法,這里的作用為了測(cè)量自身寬和高
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = defaultStepIndicatorNum * 2;
if(MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(widthMeasureSpec))
{
width = MeasureSpec.getSize(widthMeasureSpec);
}
int height = defaultStepIndicatorNum;
if(MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(heightMeasureSpec))
{
height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec));
}
setMeasuredDimension(width, height);
}
第三步 onSizeChanged(int w, int h, int oldw, int oldh)
動(dòng)態(tài)計(jì)算當(dāng)前view的位置,這里的計(jì)算paddingLeft和mComplectedXPosition的方法已經(jīng)在前面詳細(xì)說(shuō)明
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
//獲取中間的高度
mCenterY = 0.5f * getHeight();
//獲取左上方Y(jié)的位置,獲取該點(diǎn)的意義是為了方便畫矩形左上的Y位置
mLeftY = mCenterY - (mCompletedLineHeight / 2);
//獲取右下方Y(jié)的位置,獲取該點(diǎn)的意義是為了方便畫矩形右下的Y位置
mRightY = mCenterY + mCompletedLineHeight / 2;
for(int i = 0; i < mStepNum; i++)
{
//先計(jì)算全部最左邊的padding值(getWidth()-(圓形直徑+兩圓之間距離)*2)
float paddingLeft = (getWidth() - mStepNum * mCircleRadius * 2 - (mStepNum - 1) * mLinePadding) / 2;
mComplectedXPosition.add(paddingLeft + mCircleRadius + i * mCircleRadius * 2 + i * mLinePadding);
}
//當(dāng)位置發(fā)生改變時(shí)的回調(diào)監(jiān)聽
mOnDrawListener.ondrawIndicator();
}
這里onSizeChanged()方法里取mLeftY,mRightY是為了方便之后畫矩形。
第四步 protected synchronized void onDraw(Canvas canvas)
重重之重的方法來(lái)了,就會(huì)繪制該view所調(diào)用的方法,我們來(lái)看代碼
@Override
protected synchronized void onDraw(Canvas canvas)
{
super.onDraw(canvas);
mUnCompletedPaint.setColor(mUnCompletedLineColor);
mCompletedPaint.setColor(mCompletedLineColor);
//-----------------------畫線---------------------------------------------------------------
for(int i = 0; i < mComplectedXPosition.size() - 1; i++)
{
//前一個(gè)ComplectedXPosition
final float preComplectedXPosition = mComplectedXPosition.get(i);
//后一個(gè)ComplectedXPosition
final float afterComplectedXPosition = mComplectedXPosition.get(i + 1);
if(i < mComplectingPosition)//判斷在完成之前的所有點(diǎn)
{
//判斷在完成之前的所有點(diǎn),畫完成的線,這里是矩形
canvas.drawRect(preComplectedXPosition + mCircleRadius - 10, mLeftY, afterComplectedXPosition - mCircleRadius + 10, mRightY, mCompletedPaint);
} else
{
mPath.moveTo(preComplectedXPosition + mCircleRadius, mCenterY);
mPath.lineTo(afterComplectedXPosition - mCircleRadius, mCenterY);
canvas.drawPath(mPath, mUnCompletedPaint);
}
}
//-----------------------畫線---------------------------------------------------------------
//-----------------------畫圖標(biāo)--------------------------------------------------------------
for(int i = 0; i < mComplectedXPosition.size(); i++)
{
final float currentComplectedXPosition = mComplectedXPosition.get(i);
Rect rect = new Rect((int) (currentComplectedXPosition - mCircleRadius), (int) (mCenterY - mCircleRadius), (int) (currentComplectedXPosition + mCircleRadius), (int) (mCenterY + mCircleRadius));
if(i < mComplectingPosition)
{
mCompleteIcon.setBounds(rect);
mCompleteIcon.draw(canvas);
} else if(i == mComplectingPosition && mComplectedXPosition.size() != 1)
{
mCompletedPaint.setColor(Color.WHITE);
canvas.drawCircle(currentComplectedXPosition, mCenterY, mCircleRadius * 1.1f, mCompletedPaint);
mAttentionIcon.setBounds(rect);
mAttentionIcon.draw(canvas);
} else
{
mDefaultIcon.setBounds(rect);
mDefaultIcon.draw(canvas);
}
}
//-----------------------畫圖標(biāo)--------------------------------------------------------------
}
我們來(lái)看,在onDraw()方法里,主要是做了兩部分事情
- 畫線
這里我們拿到前一個(gè)圓的位置preComplectedXPosition和后一個(gè)圓心的位置afterComplectedXPosition,然后進(jìn)行判斷,小于當(dāng)前正在進(jìn)行的點(diǎn),畫完成的線,我們這里用繪制矩形樣式表示。大于當(dāng)前正在進(jìn)行的點(diǎn),畫虛線。
//-----------------------畫線---------------------------------------------------------------
for(int i = 0; i < mComplectedXPosition.size() - 1; i++)
{
//前一個(gè)ComplectedXPosition
final float preComplectedXPosition = mComplectedXPosition.get(i);
//后一個(gè)ComplectedXPosition
final float afterComplectedXPosition = mComplectedXPosition.get(i + 1);
if(i < mComplectingPosition)//判斷在完成之前的所有點(diǎn)
{
//判斷在完成之前的所有點(diǎn),畫完成的線,這里是矩形
canvas.drawRect(preComplectedXPosition + mCircleRadius - 10, mLeftY, afterComplectedXPosition - mCircleRadius + 10, mRightY, mCompletedPaint);
} else
{
mPath.moveTo(preComplectedXPosition + mCircleRadius, mCenterY);
mPath.lineTo(afterComplectedXPosition - mCircleRadius, mCenterY);
canvas.drawPath(mPath, mUnCompletedPaint);
}
}
這里細(xì)心的小伙伴可能有注意到,為什么在畫線的的時(shí)候,為什么canvas.drawRect的時(shí)候,左右會(huì)分別-10,+10
canvas.drawRect(preComplectedXPosition + mCircleRadius - 10, mLeftY, afterComplectedXPosition - mCircleRadius + 10, mRightY, mCompletedPaint);
那是因?yàn)楫?dāng)畫矩形時(shí),線和圓之間的連接像是有縫隙,于是我就讓矩形在往左邊多畫了10單位,在右邊多畫了10單位,這樣他們看起來(lái)像是無(wú)縫連接一樣。哈哈,但是這間距不能太大。
- 畫圓
這里判斷小于正在進(jìn)行中的為則表示已經(jīng)完成。并且剛好等于正在進(jìn)行中的且不等于一表示正在進(jìn)行中,大于則表示該步驟為完成,分別繪制圖標(biāo)。
//-----------------------畫圖標(biāo)--------------------------------------------------------------
for(int i = 0; i < mComplectedXPosition.size(); i++)
{
final float currentComplectedXPosition = mComplectedXPosition.get(i);
Rect rect = new Rect((int) (currentComplectedXPosition - mCircleRadius), (int) (mCenterY - mCircleRadius), (int) (currentComplectedXPosition + mCircleRadius), (int) (mCenterY + mCircleRadius));
if(i < mComplectingPosition)
{
mCompleteIcon.setBounds(rect);
mCompleteIcon.draw(canvas);
} else if(i == mComplectingPosition && mComplectedXPosition.size() != 1)
{
mCompletedPaint.setColor(Color.WHITE);
canvas.drawCircle(currentComplectedXPosition, mCenterY, mCircleRadius * 1.1f, mCompletedPaint);
mAttentionIcon.setBounds(rect);
mAttentionIcon.draw(canvas);
} else
{
mDefaultIcon.setBounds(rect);
mDefaultIcon.draw(canvas);
}
}
//-----------------------畫圖標(biāo)--------------------------------------------------------------
StepsViewIndicator的其他方法
/**
* 得到所有圓點(diǎn)所在的位置
*
* @return
*/
public List<Float> getComplectedXPosition()
{
return mComplectedXPosition;
}
/**
* 設(shè)置流程步數(shù)
*
* @param stepNum 流程步數(shù)
*/
public void setStepNum(int stepNum)
{
this.mStepNum = stepNum;
invalidate();
}
/**
* 設(shè)置正在進(jìn)行position
*
* @param complectingPosition
*/
public void setComplectingPosition(int complectingPosition)
{
this.mComplectingPosition = complectingPosition;
invalidate();
}
/**
* 設(shè)置未完成線的顏色
*
* @param unCompletedLineColor
*/
public void setUnCompletedLineColor(int unCompletedLineColor)
{
this.mUnCompletedLineColor = unCompletedLineColor;
}
/**
* 設(shè)置已完成線的顏色
*
* @param completedLineColor
*/
public void setCompletedLineColor(int completedLineColor)
{
this.mCompletedLineColor = completedLineColor;
}
/**
* 設(shè)置默認(rèn)圖片
*
* @param defaultIcon
*/
public void setDefaultIcon(Drawable defaultIcon)
{
this.mDefaultIcon = defaultIcon;
}
/**
* 設(shè)置已完成圖片
* @param completeIcon
*/
public void setCompleteIcon(Drawable completeIcon)
{
this.mCompleteIcon = completeIcon;
}
/**
* 設(shè)置正在進(jìn)行中的圖片
* @param attentionIcon
*/
public void setAttentionIcon(Drawable attentionIcon)
{
this.mAttentionIcon = attentionIcon;
}
StepsViewIndicator (全部代碼)
public class StepsViewIndicator extends View
{
//定義默認(rèn)的高度
private int defaultStepIndicatorNum = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, getResources().getDisplayMetrics());
private float mCompletedLineHeight;//完成線的高度
private float mCircleRadius;//圓的半徑
private Drawable mCompleteIcon;//完成的默認(rèn)圖片
private Drawable mAttentionIcon;//正在進(jìn)行的默認(rèn)圖片
private Drawable mDefaultIcon;//默認(rèn)的背景圖
private float mCenterY;//該view的中間位置
private float mLeftY;//左上方的Y位置
private float mRightY;//右下方的位置
private int mStepNum = 0;//當(dāng)前有幾部流程
private float mLinePadding;
private List<Float> mComplectedXPosition;//定義完成時(shí)當(dāng)前view在左邊的位置
private Paint mUnCompletedPaint;//未完成Paint
private Paint mCompletedPaint;//完成paint
private int mUnCompletedLineColor = ContextCompat.getColor(getContext(), R.color.uncompleted_color);//定義默認(rèn)未完成線的顏色
private int mCompletedLineColor = Color.WHITE;//定義默認(rèn)完成線的顏色
private PathEffect mEffects;
private int mComplectingPosition;//正在進(jìn)行position
private Path mPath;
private OnDrawIndicatorListener mOnDrawListener;
/**
* 設(shè)置監(jiān)聽
*
* @param onDrawListener
*/
public void setOnDrawListener(OnDrawIndicatorListener onDrawListener)
{
mOnDrawListener = onDrawListener;
}
/**
* get小圓的半徑
*
* @return
*/
public float getCircleRadius()
{
return mCircleRadius;
}
public StepsViewIndicator(Context context)
{
this(context, null);
}
public StepsViewIndicator(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public StepsViewIndicator(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
/**
* init
*/
private void init()
{
mPath = new Path();
mEffects = new DashPathEffect(new float[]{8, 8, 8, 8}, 1);
mComplectedXPosition = new ArrayList<>();//初始化
mUnCompletedPaint = new Paint();
mCompletedPaint = new Paint();
mUnCompletedPaint.setAntiAlias(true);
mUnCompletedPaint.setColor(mUnCompletedLineColor);
mUnCompletedPaint.setStyle(Paint.Style.STROKE);
mUnCompletedPaint.setStrokeWidth(2);
mCompletedPaint.setAntiAlias(true);
mCompletedPaint.setColor(mCompletedLineColor);
mCompletedPaint.setStyle(Paint.Style.STROKE);
mCompletedPaint.setStrokeWidth(2);
mUnCompletedPaint.setPathEffect(mEffects);
mCompletedPaint.setStyle(Paint.Style.FILL);
//已經(jīng)完成線的寬高
mCompletedLineHeight = 0.05f * defaultStepIndicatorNum;
//圓的半徑
mCircleRadius = 0.28f * defaultStepIndicatorNum;
//線與線之間的間距
mLinePadding = 0.85f * defaultStepIndicatorNum;
mCompleteIcon = ContextCompat.getDrawable(getContext(), R.drawable.complted);//已經(jīng)完成的icon
mAttentionIcon = ContextCompat.getDrawable(getContext(), R.drawable.attention);//正在進(jìn)行的icon
mDefaultIcon = ContextCompat.getDrawable(getContext(), R.drawable.default_icon);//未完成的icon
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = defaultStepIndicatorNum * 2;
if(MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(widthMeasureSpec))
{
width = MeasureSpec.getSize(widthMeasureSpec);
}
int height = defaultStepIndicatorNum;
if(MeasureSpec.UNSPECIFIED != MeasureSpec.getMode(heightMeasureSpec))
{
height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec));
}
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
//獲取中間的高度
mCenterY = 0.5f * getHeight();
//獲取左上方Y(jié)的位置,獲取該點(diǎn)的意義是為了方便畫矩形左上的Y位置
mLeftY = mCenterY - (mCompletedLineHeight / 2);
//獲取右下方Y(jié)的位置,獲取該點(diǎn)的意義是為了方便畫矩形右下的Y位置
mRightY = mCenterY + mCompletedLineHeight / 2;
for(int i = 0; i < mStepNum; i++)
{
//先計(jì)算全部最左邊的padding值(getWidth()-(圓形直徑+兩圓之間距離)*2)
float paddingLeft = (getWidth() - mStepNum * mCircleRadius * 2 - (mStepNum - 1) * mLinePadding) / 2;
mComplectedXPosition.add(paddingLeft + mCircleRadius + i * mCircleRadius * 2 + i * mLinePadding);
}
mOnDrawListener.ondrawIndicator();
}
@Override
protected synchronized void onDraw(Canvas canvas)
{
super.onDraw(canvas);
mUnCompletedPaint.setColor(mUnCompletedLineColor);
mCompletedPaint.setColor(mCompletedLineColor);
//-----------------------畫線---------------------------------------------------------------
for(int i = 0; i < mComplectedXPosition.size() - 1; i++)
{
//前一個(gè)ComplectedXPosition
final float preComplectedXPosition = mComplectedXPosition.get(i);
//后一個(gè)ComplectedXPosition
final float afterComplectedXPosition = mComplectedXPosition.get(i + 1);
if(i < mComplectingPosition)//判斷在完成之前的所有點(diǎn)
{
//判斷在完成之前的所有點(diǎn),畫完成的線,這里是矩形
canvas.drawRect(preComplectedXPosition + mCircleRadius - 10, mLeftY, afterComplectedXPosition - mCircleRadius + 10, mRightY, mCompletedPaint);
} else
{
mPath.moveTo(preComplectedXPosition + mCircleRadius, mCenterY);
mPath.lineTo(afterComplectedXPosition - mCircleRadius, mCenterY);
canvas.drawPath(mPath, mUnCompletedPaint);
}
}
//-----------------------畫線---------------------------------------------------------------
//-----------------------畫圖標(biāo)--------------------------------------------------------------
for(int i = 0; i < mComplectedXPosition.size(); i++)
{
final float currentComplectedXPosition = mComplectedXPosition.get(i);
Rect rect = new Rect((int) (currentComplectedXPosition - mCircleRadius), (int) (mCenterY - mCircleRadius), (int) (currentComplectedXPosition + mCircleRadius), (int) (mCenterY + mCircleRadius));
if(i < mComplectingPosition)
{
mCompleteIcon.setBounds(rect);
mCompleteIcon.draw(canvas);
} else if(i == mComplectingPosition && mComplectedXPosition.size() != 1)
{
mCompletedPaint.setColor(Color.WHITE);
canvas.drawCircle(currentComplectedXPosition, mCenterY, mCircleRadius * 1.1f, mCompletedPaint);
mAttentionIcon.setBounds(rect);
mAttentionIcon.draw(canvas);
} else
{
mDefaultIcon.setBounds(rect);
mDefaultIcon.draw(canvas);
}
}
//-----------------------畫圖標(biāo)--------------------------------------------------------------
}
/**
* 得到所有圓點(diǎn)所在的位置
*
* @return
*/
public List<Float> getComplectedXPosition()
{
return mComplectedXPosition;
}
/**
* 設(shè)置流程步數(shù)
*
* @param stepNum 流程步數(shù)
*/
public void setStepNum(int stepNum)
{
this.mStepNum = stepNum;
invalidate();
}
/**
* 設(shè)置正在進(jìn)行position
*
* @param complectingPosition
*/
public void setComplectingPosition(int complectingPosition)
{
this.mComplectingPosition = complectingPosition;
invalidate();
}
/**
* 設(shè)置未完成線的顏色
*
* @param unCompletedLineColor
*/
public void setUnCompletedLineColor(int unCompletedLineColor)
{
this.mUnCompletedLineColor = unCompletedLineColor;
}
/**
* 設(shè)置已完成線的顏色
*
* @param completedLineColor
*/
public void setCompletedLineColor(int completedLineColor)
{
this.mCompletedLineColor = completedLineColor;
}
/**
* 設(shè)置默認(rèn)圖片
*
* @param defaultIcon
*/
public void setDefaultIcon(Drawable defaultIcon)
{
this.mDefaultIcon = defaultIcon;
}
/**
* 設(shè)置已完成圖片
* @param completeIcon
*/
public void setCompleteIcon(Drawable completeIcon)
{
this.mCompleteIcon = completeIcon;
}
/**
* 設(shè)置正在進(jìn)行中的圖片
* @param attentionIcon
*/
public void setAttentionIcon(Drawable attentionIcon)
{
this.mAttentionIcon = attentionIcon;
}
/**
* 設(shè)置對(duì)view監(jiān)聽
*/
public interface OnDrawIndicatorListener
{
void ondrawIndicator();
}
}
StepView
好了StepsViewIndicator是不是已經(jīng)完全熟悉了呢,下面我們看StepView.StepView其實(shí)組合控件,設(shè)置其子控件的屬性,包括顏色,position的狀態(tài)...其中有一個(gè)方法我們來(lái)看下,就是對(duì)于設(shè)置TextView的。
@Override
public void ondrawIndicator()
{
List<Float> complectedXPosition = mStepsViewIndicator.getComplectedXPosition();
if(mTexts != null)
{
for(int i = 0; i < mTexts.size(); i++)
{
TextView textView = new TextView(getContext());
textView.setText(mTexts.get(i));
textView.setX(complectedXPosition.get(i) - mStepsViewIndicator.getCircleRadius() - 10);//這里的-10是將文字進(jìn)行調(diào)整居中,稍后再動(dòng)態(tài)修改
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
if(i <= mComplectingPosition)
{
textView.setTypeface(null, Typeface.BOLD);
textView.setTextColor(mComplectedTextColor);
} else
{
textView.setTextColor(mUnComplectedTextColor);
}
mTextContainer.addView(textView);
}
}
}
這里的ondrawIndicator()方法是在StepsViewIndicator的onSizeChanged()引發(fā)的回調(diào),來(lái)設(shè)置TextView
StepView全部代碼
public class StepView extends LinearLayout implements StepsViewIndicator.OnDrawIndicatorListener
{
private RelativeLayout mTextContainer;
private StepsViewIndicator mStepsViewIndicator;
private List<String> mTexts;
private int mComplectingPosition;
private int mUnComplectedTextColor = ContextCompat.getColor(getContext(), R.color.uncompleted_text_color);//定義默認(rèn)未完成文字的顏色;
private int mComplectedTextColor = ContextCompat.getColor(getContext(), android.R.color.white);//定義默認(rèn)完成文字的顏色;
public StepView(Context context)
{
this(context, null);
}
public StepView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public StepView(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
init();
}
private void init()
{
View rootView = LayoutInflater.from(getContext()).inflate(R.layout.widget_stepsview, this);
mStepsViewIndicator = (StepsViewIndicator) rootView.findViewById(R.id.steps_indicator);
mStepsViewIndicator.setOnDrawListener(this);
mTextContainer = (RelativeLayout) rootView.findViewById(R.id.rl_text_container);
mTextContainer.removeAllViews();
}
/**
* 設(shè)置顯示的文字
*
* @param texts
* @return
*/
public StepView setStepViewTexts(List<String> texts)
{
mTexts = texts;
mStepsViewIndicator.setStepNum(mTexts.size());
return this;
}
/**
* 設(shè)置正在進(jìn)行的position
*
* @param complectingPosition
* @return
*/
public StepView setStepsViewIndicatorComplectingPosition(int complectingPosition)
{
mComplectingPosition = complectingPosition;
mStepsViewIndicator.setComplectingPosition(complectingPosition);
return this;
}
/**
* 設(shè)置未完成文字的顏色
*
* @param unComplectedTextColor
* @return
*/
public StepView setStepViewUnComplectedTextColor(int unComplectedTextColor)
{
mUnComplectedTextColor = unComplectedTextColor;
return this;
}
/**
* 設(shè)置完成文字的顏色
*
* @param complectedTextColor
* @return
*/
public StepView setStepViewComplectedTextColor(int complectedTextColor)
{
this.mComplectedTextColor = complectedTextColor;
return this;
}
/**
* 設(shè)置StepsViewIndicator未完成線的顏色
*
* @param unCompletedLineColor
* @return
*/
public StepView setStepsViewIndicatorUnCompletedLineColor(int unCompletedLineColor)
{
mStepsViewIndicator.setUnCompletedLineColor(unCompletedLineColor);
return this;
}
/**
* 設(shè)置StepsViewIndicator完成線的顏色
*
* @param completedLineColor
* @return
*/
public StepView setStepsViewIndicatorCompletedLineColor(int completedLineColor)
{
mStepsViewIndicator.setCompletedLineColor(completedLineColor);
return this;
}
/**
* 設(shè)置StepsViewIndicator默認(rèn)圖片
*
* @param defaultIcon
*/
public StepView setStepsViewIndicatorDefaultIcon(Drawable defaultIcon)
{
mStepsViewIndicator.setDefaultIcon(defaultIcon);
return this;
}
/**
* 設(shè)置StepsViewIndicator已完成圖片
*
* @param completeIcon
*/
public StepView setStepsViewIndicatorCompleteIcon(Drawable completeIcon)
{
mStepsViewIndicator.setCompleteIcon(completeIcon);
return this;
}
/**
* 設(shè)置StepsViewIndicator正在進(jìn)行中的圖片
*
* @param attentionIcon
*/
public StepView setStepsViewIndicatorAttentionIcon(Drawable attentionIcon)
{
mStepsViewIndicator.setAttentionIcon(attentionIcon);
return this;
}
@Override
public void ondrawIndicator()
{
List<Float> complectedXPosition = mStepsViewIndicator.getComplectedXPosition();
if(mTexts != null)
{
for(int i = 0; i < mTexts.size(); i++)
{
TextView textView = new TextView(getContext());
textView.setText(mTexts.get(i));
textView.setX(complectedXPosition.get(i) - mStepsViewIndicator.getCircleRadius() - 10);//這里的-10是將文字進(jìn)行調(diào)整居中,稍后再動(dòng)態(tài)修改
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
if(i <= mComplectingPosition)
{
textView.setTypeface(null, Typeface.BOLD);
textView.setTextColor(mComplectedTextColor);
} else
{
textView.setTextColor(mUnComplectedTextColor);
}
mTextContainer.addView(textView);
}
}
}
}
好了,其實(shí)到了這里,基本上也要接近尾聲了.有了前面的只是積累,寫VerticalStepView是不是就思路更加明確了呢?其實(shí)這個(gè)控件看起來(lái)‘很復(fù)雜’,翻了翻代碼,看了也沒(méi)有多大難度,小伙伴們,只要靜下心來(lái),花點(diǎn)時(shí)間研究下,發(fā)現(xiàn),也就是那么回事,只要努力,就會(huì)有收貨。
關(guān)于VerticalStepView
這里就不在啰嗦的闡述VerticalStepView的原理啦,有了上面的HorizontalStepsViewIndicator的講解,在來(lái)看看VerticalStepView應(yīng)該是非常輕松的吧,好了,有想法的小伙伴何不嘗試自己來(lái)寫這個(gè)VerticalStepView,相信你可以的!!!
- 【VerticalStepView參考地址】VerticalStepView
參考鏈接
Thanks
圖片來(lái)源
End
喜歡這個(gè)控件的小伙伴可以點(diǎn)擊star哦!
下一篇文章WrapTextView
點(diǎn)擊查看WrapTextView