您好,登錄后才能下訂單哦!
Android 開發訂單流程view實例詳解
先看看最終效果圖:
怎么樣,效果還是很不錯的吧?群里有人說切四張圖的、recycleview的、各種的都有啊,但是最簡單的就是通過自定義view來實現了~接下來讓我們來實現下這個(訂單流程view)。
首先我們定義好我們的自定義屬性:
attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="ProcessView"> <!--滑動圓點的半徑--> <attr name="thumb_radius" format="dimension"/> <!--到達的顏色--> <attr name="color_reached" format="color"/> <!--未到達的顏色--> <attr name="color_unreached" format="color"/> <!--textsize的大小--> <attr name="textsize" format="dimension"/> <!--text的顏色--> <attr name="text_color" format="color"/> <!--線的寬度--> <attr name="line_width" format="dimension"/> <!--狀態文字數組--> <attr name="texts" format="reference"/> </declare-styleable> </resources>
然后就是我們的老套路了,創建一個叫ProcessView的類繼承view,然后定義好我們需要的屬性:
/** * Created by leo on 17/3/27. */ 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); } }
然后就是重寫我們的onmeasure方法了,我們這里就不考慮控件的高度為wrap_content這種情況了,所以我們只需要測量高度就可以了:
@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; }
接著就是我們的核心方法onDraw()了,代碼很簡單都有注釋,我就不一一解釋了:
@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); }
好啦~~然后我們暴露一個方法給外部,修改progress:
public void setProgress(float progress) { if (progress != mProgress) { mProgress = progress; if (Looper.myLooper() == Looper.getMainLooper()) { invalidate(); } else { postInvalidate(); } } }
最后我們就可以跑起來了:
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:
package com.yasin.processdemo; import android.animation.ValueAnimator; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.animation.AccelerateDecelerateInterpolator; import com.yasin.processdemo.view.ProcessView; 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; /** * Created by leo on 17/3/27. */ 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())); } }
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。