流程状态图

效果图如下:


image.png

仿这个写的,偷了3张图,至于这里的代码还没看过。看到效果图就先自己写个,以后有空再去看作者咋写的。
https://gitee.com/tangbuzhi/stepview/

代码如下:
定义个抽象类,用来显示状态信息的

public abstract class ShowTextParent {

    public abstract String getShowText();
}

实现类

public class FlowStepData extends ShowTextParent{
    private String des;
    
    public FlowStepData(String des) {
        super();
        this.des = des;
    }
    @Override
    public String getShowText() {
        return des;
    }
}

主要类,字体颜色,线条颜色都是写死的,需要的话再添加对外的方法修改。
另外3种状态图片可以通过设置declare-styleable属性来在布局文件里设置比较方便,偷懒了没写。上边的线条颜色,文字颜色也可以通过declare-styleable来设置。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Paint.Align;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import bean.ShowTextParent;

public class FlowStepShow extends View {

    public FlowStepShow(Context context, AttributeSet attrs) {
        super(context, attrs);
        initSomeThing();
    }

    private boolean bottomText = true;// 文字是否在底部显示,默认在底部
    private boolean clickable = true;// 是否可选择
    private int checkedPosition;// 默认的选中位置
    private Paint paintLine = new Paint();
    private Paint paintText = new Paint();
    private int textHeight;
    private int drawablePadding = 5;
    private Bitmap bitmap1, bitmap2, bitmap3;

    private void initSomeThing() {
        paintText.setTextSize(20);
        paintText.setColor(Color.WHITE);
        paintText.setTextAlign(Align.CENTER);
        Rect bounds = new Rect();
        paintText.getTextBounds("您好", 0, 2, bounds);
        textHeight = bounds.height();
        bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.ic_passed);
        bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.ic_target);
        bitmap3 = BitmapFactory.decodeResource(getResources(), R.drawable.ic_normal);

    }

    ArrayList<ShowTextParent> data = new ArrayList<ShowTextParent>();
    private int lineY;
    private int textY;
    private int length;
    private int interval;

    public void setClick(boolean click) {
        clickable = click;
        postInvalidate();
    }

    public void setData(List<ShowTextParent> lists, int position) {
        data.clear();
        data.addAll(lists);
        if(position>=0&&position<data.size()) {
            checkedPosition = position;
        }else {
            checkedPosition=0;
        }
        postInvalidate();
    }

    public void setData(List<ShowTextParent> lists) {
        setData(lists, 0);
    }

    public void setData(ShowTextParent[] arr, int position) {
        setData(Arrays.asList(arr), position);
    }

    public void setData(ShowTextParent[] arr) {
        setData(arr, 0);
    }

    public void setTextBottom(boolean bottom) {
        bottomText = bottom;
        postInvalidate();
    }

    public int getCheckedPosition() {
        return checkedPosition;
    }

    public void setCheckedPosition(int checkedPosition) {
        if (checkedPosition != this.checkedPosition) {
            this.checkedPosition = checkedPosition;
            postInvalidate();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(getMeasuredWidth(),
                textHeight * 2 + drawablePadding + getPaddingTop() + getPaddingBottom());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        lineY = getPaddingTop() + textHeight / 2;
        textY = getPaddingTop() + textHeight * 2 + drawablePadding;
        if (!bottomText) {
            lineY = getPaddingTop() + textHeight + drawablePadding + textHeight / 2;
            textY = getPaddingTop() + textHeight;
        }
        length = data.size();
        if (length > 0) {
            interval = (getWidth() - getPaddingLeft() - getPaddingRight()) / length;
            for (int i = 0; i < data.size(); i++) {
                int x = interval / 2 + interval * i;
                canvas.drawText(data.get(i).getShowText(), x, textY, paintText);

                Bitmap bitmap = getBitmap(i);
                canvas.drawBitmap(bitmap, x - bitmap.getWidth() / 2, lineY - bitmap.getHeight() / 2, null);
                if (i > 0) {
                    paintLine.setColor(i <= checkedPosition ? Color.WHITE : Color.GRAY);
                    canvas.drawLine(x - interval + getBitmap(i - 1).getWidth() / 2, lineY, x - bitmap.getWidth() / 2,
                            lineY, paintLine);
                }
            }
        }

    }

    private Bitmap getBitmap(int i) {
        if (i < checkedPosition) {
            return bitmap1;
        } else if (i > checkedPosition) {
            return bitmap3;
        } else {
            return bitmap2;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
            if (clickable) {
                int position = getClickPosition(event);
                if (position >= 0) {
                    if (listener != null && position != checkedPosition) {
                        listener.positionChanged(position);
                    }
                    checkedPosition = position;
                    postInvalidate();
                }
            }

            return true;
        }
        return super.onTouchEvent(event);
    }

    private int getClickPosition(MotionEvent event) {
        if (length > 0) {
            for (int i = 0; i < length; i++) {
                int x = interval / 2 + interval * i;
                RectF rect = new RectF(x - 20, lineY - 20, x + 20, lineY + 20);
                if (rect.contains(event.getX(), event.getY())) {
                    return i;
                }
            }
        }
        return -1;
    }

    private StateChangeListener listener;

    public void setListener(StateChangeListener listener) {
        this.listener = listener;
    }

    public interface StateChangeListener {
        public void positionChanged(int position);
    }
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        recycleBitmap(bitmap1);
        recycleBitmap(bitmap2);
        recycleBitmap(bitmap3);
    }
    private void recycleBitmap(Bitmap bitmap) {
        if(bitmap!=null&&!bitmap.isRecycled()) {
            bitmap.recycle();
        }
    }
}

布局文件以及代码中使用

    <widget.FlowStepShow
        android:id="@+id/flowStepShow1"
        android:paddingTop="15dp" 
        android:background="#000"
        android:paddingBottom="15dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <widget.FlowStepShow
        android:id="@+id/flowStepShow2"
        android:paddingTop="5dp" 
        android:paddingBottom="5dp"
        android:background="#000"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />


        FlowStepShow flowStepShow=(FlowStepShow) getView().findViewById(R.id.flowStepShow1);
        FlowStepShow flowStepShow2=(FlowStepShow) getView().findViewById(R.id.flowStepShow2);
        ArrayList<ShowTextParent> lists=new ArrayList<ShowTextParent>();
        lists.add(new FlowStepData("下订单"));
        lists.add(new FlowStepData("验证客户订单信息"));
        lists.add(new FlowStepData("支付定金"));
        lists.add(new FlowStepData("订单完成"));
        lists.add(new FlowStepData("已经入住"));
        lists.add(new FlowStepData("已经退房"));
        flowStepShow.setData(lists,3);
        flowStepShow.setListener(new StateChangeListener() {
            
            @Override
            public void positionChanged(int position) {
                System.err.println("current==========="+position);
                
            }
        });
        flowStepShow2.setData(lists,4);
        flowStepShow2.setClick(false);
        flowStepShow2.setTextBottom(false);

抽空修改下,方便在布局文件里设置属性

       <declare-styleable name="FlowStepShowAttr">
           <attr name="flow_step_normal_icon" format="reference"/>
           <attr name="flow_step_target_icon" format="reference"/>
           <attr name="flow_step_passed_icon" format="reference"/>
           <attr name="flow_step_passed_line_color" format="color"/>
           <attr name="flow_step_normal_line_color" format="color"/>
           <attr name="flow_step_text_color" format="color"/>
           <attr name="flow_step_text_size" format="dimension"/>
           <attr name="flow_step_text_bottom" format="boolean"/>
           <attr name="flow_step_clickable" format="boolean"/>
           <attr name="flow_step_drawable_padding" format="dimension"/>
       </declare-styleable>

新的类如下:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Paint.Align;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import bean.ShowTextParent;

public class FlowStepShow extends View {

    public FlowStepShow(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttrs(context, attrs);
        initSomeThing();
    }

    private boolean bottomText = true;// 文字是否在底部显示,默认在底部
    private boolean clickable = true;// 是否可选择
    private int checkedPosition;// 默认的选中位置
    private Paint paintLine = new Paint();
    private Paint paintText = new Paint();
    private int textHeight;
    private int drawablePadding = 5;
    private Bitmap bitmap1, bitmap2, bitmap3;
    private int ic_passed=R.drawable.ic_passed;
    private int ic_target=R.drawable.ic_target;
    private int ic_normal=R.drawable.ic_normal;
    private int textSize=15;
    private int textColor=Color.WHITE;
    private int colorLinePassed=Color.WHITE;
    private int colorLineNormal=Color.GRAY;
    
    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray  typedArray=context.obtainStyledAttributes(attrs, R.styleable.FlowStepShowAttr);
        bottomText=typedArray.getBoolean(R.styleable.FlowStepShowAttr_flow_step_text_bottom, true);
        clickable=typedArray.getBoolean(R.styleable.FlowStepShowAttr_flow_step_clickable, true);
        drawablePadding=typedArray.getDimensionPixelSize(R.styleable.FlowStepShowAttr_flow_step_drawable_padding, 5);
        ic_passed=typedArray.getResourceId(R.styleable.FlowStepShowAttr_flow_step_passed_icon,R.drawable.ic_passed);
        ic_target=typedArray.getResourceId(R.styleable.FlowStepShowAttr_flow_step_target_icon,R.drawable.ic_target);
        ic_normal=typedArray.getResourceId(R.styleable.FlowStepShowAttr_flow_step_normal_icon,R.drawable.ic_normal);
        colorLinePassed=typedArray.getColor(R.styleable.FlowStepShowAttr_flow_step_passed_line_color, Color.WHITE);
        colorLineNormal=typedArray.getColor(R.styleable.FlowStepShowAttr_flow_step_normal_line_color, Color.GRAY);
        
        textColor=typedArray.getColor(R.styleable.FlowStepShowAttr_flow_step_text_color, Color.WHITE);
        textSize=typedArray.getDimensionPixelSize(R.styleable.FlowStepShowAttr_flow_step_text_size, 15);
        typedArray.recycle();
    }
    private void initSomeThing() {
        paintText.setTextSize(textSize);
        paintText.setColor(textColor);
        paintText.setTextAlign(Align.CENTER);
        Rect bounds = new Rect();
        paintText.getTextBounds("您好", 0, 2, bounds);
        textHeight = bounds.height();
        bitmap1 = BitmapFactory.decodeResource(getResources(),ic_passed);
        bitmap2 = BitmapFactory.decodeResource(getResources(), ic_target);
        bitmap3 = BitmapFactory.decodeResource(getResources(), ic_normal);

    }

    ArrayList<ShowTextParent> data = new ArrayList<ShowTextParent>();
    private int lineY;
    private int textY;
    private int length;
    private int interval;

    public void setClick(boolean click) {
        clickable = click;
        postInvalidate();
    }

    public void setData(List<ShowTextParent> lists, int position) {
        data.clear();
        data.addAll(lists);
        if(position>=0&&position<data.size()) {
            checkedPosition = position;
        }else {
            checkedPosition=0;
        }
        
        postInvalidate();
    }

    public void setData(List<ShowTextParent> lists) {
        setData(lists, 0);
    }

    public void setData(ShowTextParent[] arr, int position) {
        setData(Arrays.asList(arr), position);
    }

    public void setData(ShowTextParent[] arr) {
        setData(arr, 0);
    }

    public void setTextBottom(boolean bottom) {
        bottomText = bottom;
        postInvalidate();
    }

    public int getCheckedPosition() {
        return checkedPosition;
    }

    public void setCheckedPosition(int checkedPosition) {
        if (checkedPosition != this.checkedPosition) {
            this.checkedPosition = checkedPosition;
            postInvalidate();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(getMeasuredWidth(),
                textHeight * 2 + drawablePadding + getPaddingTop() + getPaddingBottom());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        lineY = getPaddingTop() + textHeight / 2;
        textY = getPaddingTop() + textHeight * 2 + drawablePadding;
        if (!bottomText) {
            lineY = getPaddingTop() + textHeight + drawablePadding + textHeight / 2;
            textY = getPaddingTop() + textHeight;
        }
        length = data.size();
        if (length > 0) {
            interval = (getWidth() - getPaddingLeft() - getPaddingRight()) / length;
            for (int i = 0; i < data.size(); i++) {
                int x = interval / 2 + interval * i;
                canvas.drawText(data.get(i).getShowText(), x, textY, paintText);

                Bitmap bitmap = getBitmap(i);
                canvas.drawBitmap(bitmap, x - bitmap.getWidth() / 2, lineY - bitmap.getHeight() / 2, null);
                if (i > 0) {
                    paintLine.setColor(i <= checkedPosition ? colorLinePassed: colorLineNormal);
                    canvas.drawLine(x - interval + getBitmap(i - 1).getWidth() / 2, lineY, x - bitmap.getWidth() / 2,
                            lineY, paintLine);
                }
            }
        }

    }

    private Bitmap getBitmap(int i) {
        if (i < checkedPosition) {
            return bitmap1;
        } else if (i > checkedPosition) {
            return bitmap3;
        } else {
            return bitmap2;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
            if (clickable) {
                int position = getClickPosition(event);
                if (position >= 0) {
                    if (listener != null && position != checkedPosition) {
                        listener.positionChanged(position);
                    }
                    checkedPosition = position;
                    postInvalidate();
                }
            }

            return true;
        }
        return super.onTouchEvent(event);
    }

    private int getClickPosition(MotionEvent event) {
        if (length > 0) {
            for (int i = 0; i < length; i++) {
                int x = interval / 2 + interval * i;
                RectF rect = new RectF(x - 20, lineY - 20, x + 20, lineY + 20);
                if (rect.contains(event.getX(), event.getY())) {
                    return i;
                }
            }
        }
        return -1;
    }

    private StateChangeListener listener;

    public void setListener(StateChangeListener listener) {
        this.listener = listener;
    }

    public interface StateChangeListener {
        public void positionChanged(int position);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        recycleBitmap(bitmap1);
        recycleBitmap(bitmap2);
        recycleBitmap(bitmap3);
    }
    private void recycleBitmap(Bitmap bitmap) {
        if(bitmap!=null&&!bitmap.isRecycled()) {
            bitmap.recycle();
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,513评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,312评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,124评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,529评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,937评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,913评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,084评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,816评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,593评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,788评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,267评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,601评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,265评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,158评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,953评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,066评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,852评论 2 277

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,594评论 25 707
  • 【Android 自定义View】 [TOC] 自定义View基础 接触到一个类,你不太了解他,如果贸然翻阅源码只...
    Rtia阅读 3,897评论 1 14
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,218评论 0 17
  • "这是我们精心设计的一套精装礼盒。 它很像一张黑胶唱片,收到的人将能感受到它高级的质感。 它更是一张“在线知识唱片...
    茉莉大大阅读 174评论 0 0
  • 不知不觉,来这里已经有11天了,该学的东西还没有完全学会。反而是越来越糊涂。特别是这两天,跟了以前的一款板子,由于...
    遇见敏姑娘阅读 302评论 0 0