activity_main.xml arrays.xml: activity: ProcessView : ...
activity_main.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" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" android:background="#b2000000" android:orientation="vertical" > <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" app:cardCornerRadius="5dp" app:cardElevation="3dp" app:cardBackgroundColor="#FF2384DD" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="10dp" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="商家已接單" android:textSize="14.5sp" android:textColor="#FFF1AE0D" /> <TextView android:layout_marginTop="5dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="訂單超過12小時自動完成" android:textSize="13sp" android:textColor="#fff" /> <View android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:layout_width="match_parent" android:layout_height="2dp" android:background="@drawable/bg_line" android:layerType="software" /> <com.yasin.processdemo.view.ProcessView android:id="@+id/id_process" android:layout_width="match_parent" android:layout_height="wrap_content" app:texts="@array/process_states" /> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout>
arrays.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <array name="process_states"> <item>訂單已提交</item> <item>已付款</item> <item>商家已接單</item> <item>已送達</item> </array> </resources>
activity:
public class MainActivity extends AppCompatActivity { private ProcessView mProcessView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mProcessView= (ProcessView) findViewById(R.id.id_process); startAni(); } private void startAni() { ValueAnimator a = ValueAnimator.ofFloat(0, 1); a.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float progress = (float) animation.getAnimatedValue(); mProcessView.setProgress(progress); } }); a.setDuration(10000); a.setInterpolator(new AccelerateDecelerateInterpolator()); a.start(); } }
ProcessView :
package com.yasin.processdemo.view; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RadialGradient; import android.graphics.Shader; import android.os.Looper; import android.text.TextPaint; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; import android.view.View; import com.yasin.processdemo.R; public class ProcessView extends View { /** * 預設線寬度 */ private static final float D_LINE_WIDTH = 3; /** * 預設滑動圓點半徑 */ private static final float D_THUMB_RADIUS = 10; /** * 預設textsize */ private static final float D_TEXT_SIZE = 13f; private static final int D_REACH_COLOR = 0xFFF1AE0D; private static final int D_UNREACH_COLOR = Color.WHITE; private static final int D_TEXT_COLOR = Color.WHITE; private Paint linePaint; private TextPaint textPaint; private Paint thumbPaint; private float mTextSize = xx2px(TypedValue.COMPLEX_UNIT_SP, D_TEXT_SIZE); private float mLineWidth = xx2px(TypedValue.COMPLEX_UNIT_DIP, D_LINE_WIDTH); private float mThumbRadius = xx2px(TypedValue.COMPLEX_UNIT_DIP, D_THUMB_RADIUS); private int mReachedColor = D_REACH_COLOR; private int mUnreachedColor = D_UNREACH_COLOR; private int mTextColor = D_TEXT_COLOR; //當前進度 private float mProgress = 0.0f; //所有的狀態文字 private String[] texts; public ProcessView(Context context) { this(context, null); } public ProcessView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ProcessView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); obtainStyledAttrs(context, attrs, defStyleAttr); initViews(); } /** * 獲取我們的自定義屬性 * @param context * @param attrs * @param defStyleAttr */ private void obtainStyledAttrs(Context context, AttributeSet attrs, int defStyleAttr) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProcessView, defStyleAttr, 0); texts = a.hasValue(R.styleable.ProcessView_texts) ? getResources().getStringArray(a.getResourceId(R.styleable.ProcessView_texts, 0)) : texts; mLineWidth = a.hasValue(R.styleable.ProcessView_line_width) ? a.getDimensionPixelSize(R.styleable.ProcessView_line_width, 0) : mLineWidth; mThumbRadius = a.hasValue(R.styleable.ProcessView_thumb_radius) ? a.getDimensionPixelSize(R.styleable.ProcessView_thumb_radius, 0) : mThumbRadius; mTextSize = a.hasValue(R.styleable.ProcessView_textsize) ? a.getDimensionPixelSize(R.styleable.ProcessView_text_color, 0) : mTextSize; mReachedColor=a.hasValue(R.styleable.ProcessView_color_reached)? a.getColor(R.styleable.ProcessView_color_reached,D_REACH_COLOR):D_REACH_COLOR; mUnreachedColor=a.hasValue(R.styleable.ProcessView_color_unreached)? a.getColor(R.styleable.ProcessView_color_unreached,D_UNREACH_COLOR):D_UNREACH_COLOR; mTextColor=a.hasValue(R.styleable.ProcessView_text_color)? a.getColor(R.styleable.ProcessView_text_color,D_TEXT_COLOR):D_TEXT_COLOR; a.recycle(); } /** * 初始化一些對象 */ private void initViews() { linePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); linePaint.setStyle(Paint.Style.FILL); textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG); thumbPaint = new Paint(linePaint); textPaint.setTextSize(mTextSize); textPaint.setColor(mTextColor); linePaint.setStrokeWidth(mLineWidth); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int heightM = MeasureSpec.getMode(heightMeasureSpec); int defaultW = MeasureSpec.getSize(widthMeasureSpec); int defaultH = MeasureSpec.getSize(heightMeasureSpec); int resultW, resultH; resultW = defaultW; resultH = getDefaultHeight(defaultH, heightM); setMeasuredDimension(resultW, resultH); } private int getDefaultHeight(int height, int mode) { int result; if (mode == MeasureSpec.EXACTLY) { result = height; } else { //獲取文字的高度 float textH = (textPaint.getFontMetrics().bottom - textPaint.getFontMetrics().top); //高度=圓半徑+2.2*線條寬度(也就是豎線高度)+文字高度*1.3(也就是空隙高度)+0.5*文字高度 result = (int) (mThumbRadius + mLineWidth * 2.2f + textH * 1.3f + 0.5 * textH); } return result; } @Override protected void onDraw(Canvas canvas) { //畫底部的豎線跟文字 drawFoot(canvas); //畫移動的小圓點跟進度條 drawProgressAndThumb(canvas); } /** * 畫底部的豎線跟文字 */ private void drawFoot(Canvas canvas) { //設置底部豎線寬度(底部的豎線會比進度條的要小一點) float lineWidth = mLineWidth * 0.8f; linePaint.setStrokeWidth(mLineWidth * 0.8f); //起始位置(也就是"訂單已提交"的"已"字位置) float startX = textPaint.measureText(texts[0]) / 2; //結束的文字的位置("已送達"的"送"字位置) float endTextW = textPaint.measureText(texts[texts.length - 1]) / 2; //繪製的終點位置 float endX = getMeasuredWidth() - endTextW; //線條的總長度 float lineW = (endX - startX) / (texts.length - 1); //豎線的高度 float lineH = mLineWidth * 2.2f; //豎線的終點位置 float lineY = mThumbRadius + mLineWidth / 2; //迴圈畫出豎線跟文字 for (int i = 0; i < texts.length; i++) { canvas.save(); //每畫一條豎線讓畫布水平平移linew個寬度 canvas.translate(i * lineW, 0); //如果當前進度>豎線所在的位置,就改變豎線的顏色 linePaint.setColor(i * lineW >= mProgress * (endX - startX) ? mUnreachedColor : mReachedColor); float endX2 = i == texts.length - 1 ? startX - lineWidth / 2 : startX + lineWidth / 2; canvas.drawLine(endX2, lineY, endX2, lineY + lineH, linePaint); //畫文字 textPaint.setTextAlign(Paint.Align.CENTER); float textH = (textPaint.getFontMetrics().bottom - textPaint.getFontMetrics().top); canvas.drawText(texts[i], endX2, lineY + lineH + textH * 1.3f, textPaint); canvas.restore(); } } private void drawProgressAndThumb(Canvas canvas) { float startX = textPaint.measureText(texts[0]) / 2; float endTextW = textPaint.measureText(texts[texts.length - 1]) / 2; float endX = getMeasuredWidth() - endTextW; float lineY = mThumbRadius; linePaint.setStrokeWidth(mLineWidth); //draw basic line linePaint.setColor(mUnreachedColor); canvas.drawLine(startX, lineY, endX, lineY, linePaint); //draw progress line float progressX = startX + (endX - startX) * mProgress; linePaint.setColor(mReachedColor); canvas.drawLine(startX, lineY, progressX, lineY, linePaint); //給移動圓點一個RadialGradient顏色梯度效果 thumbPaint.setShader(new RadialGradient(progressX, mThumbRadius, mThumbRadius, new int[]{Color.WHITE, D_REACH_COLOR, Color.YELLOW}, null, Shader.TileMode.REPEAT)); canvas.drawCircle(progressX, mThumbRadius, mThumbRadius, thumbPaint); } public void setProgress(float progress) { if (progress != mProgress) { mProgress = progress; if (Looper.myLooper() == Looper.getMainLooper()) { invalidate(); } else { postInvalidate(); } } } private float xx2px(int unit, float value) { Context c = getContext(); Resources r; if (c == null) r = Resources.getSystem(); else r = c.getResources(); return (TypedValue.applyDimension( unit, value, r.getDisplayMetrics())); } }
github:https://github.com/ganchuanpu/ProcessDemo