快速简单的定制一个时间轴布局(LinearLayout)

来源:互联网 发布:三国杀立春套装 淘宝 编辑:程序博客网 时间:2024/05/17 02:19


很多情况下,我们都会遇到需要类似于时间轴的一个布局,网上也有很多,但是很多情况下我们其实并不需要那么多库,毕竟64k限制就在那,不管我们用还是不用,它依然在那。。。

而且更多时候,我们的时间轴也许并不需要那么多数据(比如转账流程?)

事实上这次的教程也是因为我司需要弄一个转账流程,这个转账流程包含了基本的三个状态:

1 - 转账开始

2 - 转账中

3 - 转账成功

而失败后重新转账可以看到前面的状态,也就是前面的三个状态的重复

一般而言,转账3~4次失败我们也就算了,同时因为布局比较简单,所以我这次就没打算用listview,而是简单的继承LinearLayout


当然,如果数据比较多,为了内存建议还是用listview好

那么下面正文开始:

 首先规划一下我们需要的元素,从图中我们可以看到的元素有:

      线(颜色,宽),点(大小,颜色),图标

 为了方便调整,我们还需要引入两个值

      点距离父控件左边的偏移值(调整左右间距),每个节点距离childView的偏移值(调整上下间距)

 

于是我们的attrs.xml就出来了

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <declare-styleable name="UnderLineLinearLayout">  
  4.         <!--时间轴偏移值-->  
  5.         <attr name="line_margin_side" format="dimension"/>  
  6.         <!--时间轴动态调整值-->  
  7.         <attr name="line_dynamic_dimen" format="dimension"/>  
  8.         <!--线宽-->  
  9.         <attr name="line_stroke_width" format="dimension"/>  
  10.         <!--线的颜色-->  
  11.         <attr name="line_color" format="color"/>  
  12.         <!--点的大小-->  
  13.         <attr name="point_size" format="dimension"/>  
  14.         <!--点的颜色-->  
  15.         <attr name="point_color" format="color"/>  
  16.         <!--图标-->  
  17.         <attr name="icon_src" format="reference"/>  
  18.     </declare-styleable>  
  19.   
  20. </resources>  


然后继承LinearLayout,开始我们的简易时间轴

  1. public UnderLineLinearLayout(Context context) {  
  2.        this(context, null);  
  3.    }  
  4.   
  5.    public UnderLineLinearLayout(Context context, AttributeSet attrs) {  
  6.        this(context, attrs, 0);  
  7.    }  
  8.   
  9.    public UnderLineLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {  
  10.        super(context, attrs, defStyleAttr);  
  11.        TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.UnderLineLinearLayout);  
  12.        lineMarginSide = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_line_margin_side, 10);  
  13.        lineDynamicDimen = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_line_dynamic_dimen, 0);  
  14.        lineStrokeWidth = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_line_stroke_width, 2);  
  15.        lineColor = attr.getColor(R.styleable.UnderLineLinearLayout_line_color, 0xff3dd1a5);  
  16.        pointSize = attr.getDimensionPixelSize(R.styleable.UnderLineLinearLayout_point_size, 8);  
  17.        pointColor = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_point_color, 0xff3dd1a5);  
  18.   
  19.        int iconRes = attr.getResourceId(R.styleable.UnderLineLinearLayout_icon_src, R.drawable.ic_ok);  
  20.        BitmapDrawable temp = (BitmapDrawable) context.getResources().getDrawable(iconRes);  
  21.        if (temp != null) mIcon = temp.getBitmap();  
  22.   
  23.        curOrientation = getOrientation();  
  24.        attr.recycle();  
  25.        initView(context);  
  26.    }  

构造器我们获取各种参数,至于变量就不解释了

我们的主要方法都在onDraw里面,onDraw我们执行一个方法

  1. private void initView(Context context) {  
  2.         this.mContext = context;  
  3.   
  4.         linePaint = new Paint();  
  5.         linePaint.setAntiAlias(true);  
  6.         linePaint.setDither(true);  
  7.         linePaint.setColor(lineColor);  
  8.         linePaint.setStrokeWidth(lineStrokeWidth);  
  9.         linePaint.setStyle(Paint.Style.FILL_AND_STROKE);  
  10.   
  11.         pointPaint = new Paint();  
  12.         pointPaint.setAntiAlias(true);  
  13.         pointPaint.setDither(true);  
  14.         pointPaint.setColor(pointColor);  
  15.         pointPaint.setStyle(Paint.Style.FILL);  
  16.     }  
  17.   
  18.     @Override  
  19.     protected void onDraw(Canvas canvas) {  
  20.         super.onDraw(canvas);  
  21.         if (drawLine) {  
  22.             drawTimeLine(canvas);  
  23.         }  
  24.     }  

而我们的drawTimeLine的方法如下:

  1. private void drawTimeLine(Canvas canvas) {  
  2.         int childCount = getChildCount();  
  3.   
  4.         if (childCount > 0) {  
  5.             //大于1,证明至少有2个,也就是第一个和第二个之间连成线,第一个和最后一个分别有点/icon  
  6.             if (childCount > 1) {  
  7.                 switch (curOrientation) {  
  8.                     case VERTICAL:  
  9.                         drawFirstChildViewVertical(canvas);  
  10.                         drawLastChildViewVertical(canvas);  
  11.                         drawBetweenLineVertical(canvas);  
  12.                         break;  
  13.                     case HORIZONTAL:  
  14.                         break;  
  15.                     default:  
  16.                         break;  
  17.                 }  
  18.             }  
  19.             else if (childCount == 1) {  
  20.                 switch (curOrientation) {  
  21.                     case VERTICAL:  
  22.                         drawFirstChildViewVertical(canvas);  
  23.                         break;  
  24.                     case HORIZONTAL:  
  25.                         break;  
  26.                     default:  
  27.                         break;  
  28.                 }  
  29.             }  
  30.         }  
  31.     }  

按照我的设想,是想着横着也做一个的,但由于时间原因,就暂时未能实现,但其实实现原理都是一样的。

接下来就是最主要的几个方法了:

  1. private void drawFirstChildViewVertical(Canvas canvas) {  
  2.        if (getChildAt(0) != null) {  
  3.            int top = getChildAt(0).getTop();  
  4.            //记录值  
  5.            firstX = lineMarginSide;  
  6.            firstY = top + getChildAt(0).getPaddingTop() + lineDynamicDimen;  
  7.            //画一个圆  
  8.            canvas.drawCircle(firstX, firstY, pointSize, pointPaint);  
  9.        }  
  10.    }  
  11.   
  12.    private void drawLastChildViewVertical(Canvas canvas) {  
  13.        if (getChildAt(getChildCount() - 1) != null) {  
  14.            int top = getChildAt(getChildCount() - 1).getTop();  
  15.            //记录值  
  16.            lastX = lineMarginSide - (mIcon.getWidth() >> 1);  
  17.            lastY = top + getChildAt(getChildCount() - 1).getPaddingTop() + lineDynamicDimen;  
  18.            //画一个图  
  19.            canvas.drawBitmap(mIcon, lastX, lastY, null);  
  20.        }  
  21.    }  
  22.   
  23.    private void drawBetweenLineVertical(Canvas canvas) {  
  24.        for (int i = 0; i < getChildCount() - 1; i++) {  
  25.            //画剩下的  
  26.            canvas.drawLine(lineMarginSide, firstY, lineMarginSide, lastY, linePaint);  
  27.            //画了线,就画圆  
  28.            if (getChildAt(i) != null && i != 0) {  
  29.                int top = getChildAt(i).getTop();  
  30.                //记录值  
  31.                int Y = top + getChildAt(i).getPaddingTop() + lineDynamicDimen;  
  32.                canvas.drawCircle(lineMarginSide, Y, pointSize, pointPaint);  
  33.            }  
  34.        }  
  35.    }  


这里说说思路:

  首先我们在ondraw里面获取子控件的数量,然后通过子控件的属性定位我们的时间轴

  第一步我们先确定第一个子控件的位置,这里因为垂直的时间轴,所以我们通过top+paddingTop来确定我们的结点Y位置,同时引用我们xml定义好的dynamic值来微调。同时记录下此时第一个结点的x,y

  第二步我们确定最后一个控件的位置,方法同第一步,也记录下此时最后一个节点的x,y。同时调用drawBitmap画出我们的icon

  第三步我们就画第一个和最后一个之间的子控件的线和结点。相关注释都在代码中标注好了,所以这里就不再详细阐述了

  最后,因为是一个继承LinearLayout的ViewGroup,所以使用方法直接addView或者xml里面愉悦的塞进去吧-V-

这个工程还没扩展完成,以后如果有时间我希望能把水平方向的也弄出来。当然,如果诸位有更nice的修正欢迎PullRequest.


这是一个简单的时间轴定制,希望能够帮到你-V-(详细代码请看github)

附:

完整代码:

  1. package razerdp.widget;  
  2.   
  3. import android.content.Context;  
  4. import android.content.res.TypedArray;  
  5. import android.graphics.Bitmap;  
  6. import android.graphics.Canvas;  
  7. import android.graphics.Paint;  
  8. import android.graphics.drawable.BitmapDrawable;  
  9. import android.util.AttributeSet;  
  10. import android.widget.LinearLayout;  
  11.   
  12. /** 
  13.  * Created by 大灯泡 on 2016/1/21. 
  14.  * 简易带有时间轴的linearlayout 
  15.  */  
  16. public class UnderLineLinearLayout extends LinearLayout {  
  17.     //=============================================================元素定义  
  18.     private Bitmap mIcon;  
  19.     //line location  
  20.     private int lineMarginSide;  
  21.     private int lineDynamicDimen;  
  22.     //line property  
  23.     private int lineStrokeWidth;  
  24.     private int lineColor;  
  25.     //point property  
  26.     private int pointSize;  
  27.     private int pointColor;  
  28.   
  29.     //=============================================================paint  
  30.     private Paint linePaint;  
  31.     private Paint pointPaint;  
  32.     //=============================================================其他辅助参数  
  33.     //第一个点的位置  
  34.     private int firstX;  
  35.     private int firstY;  
  36.     //最后一个图的位置  
  37.     private int lastX;  
  38.     private int lastY;  
  39.     //默认垂直  
  40.     private int curOrientation = VERTICAL;  
  41.     private Context mContext;  
  42.   
  43.     //开关  
  44.     private boolean drawLine = true;  
  45.   
  46.     public UnderLineLinearLayout(Context context) {  
  47.         this(context, null);  
  48.     }  
  49.   
  50.     public UnderLineLinearLayout(Context context, AttributeSet attrs) {  
  51.         this(context, attrs, 0);  
  52.     }  
  53.   
  54.     public UnderLineLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {  
  55.         super(context, attrs, defStyleAttr);  
  56.         TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.UnderLineLinearLayout);  
  57.         lineMarginSide = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_line_margin_side, 10);  
  58.         lineDynamicDimen = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_line_dynamic_dimen, 0);  
  59.         lineStrokeWidth = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_line_stroke_width, 2);  
  60.         lineColor = attr.getColor(R.styleable.UnderLineLinearLayout_line_color, 0xff3dd1a5);  
  61.         pointSize = attr.getDimensionPixelSize(R.styleable.UnderLineLinearLayout_point_size, 8);  
  62.         pointColor = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_point_color, 0xff3dd1a5);  
  63.   
  64.         int iconRes = attr.getResourceId(R.styleable.UnderLineLinearLayout_icon_src, R.drawable.ic_ok);  
  65.         BitmapDrawable temp = (BitmapDrawable) context.getResources().getDrawable(iconRes);  
  66.         if (temp != null) mIcon = temp.getBitmap();  
  67.   
  68.         curOrientation = getOrientation();  
  69.         attr.recycle();  
  70.         initView(context);  
  71.     }  
  72.   
  73.     private void initView(Context context) {  
  74.         this.mContext = context;  
  75.   
  76.         linePaint = new Paint();  
  77.         linePaint.setAntiAlias(true);  
  78.         linePaint.setDither(true);  
  79.         linePaint.setColor(lineColor);  
  80.         linePaint.setStrokeWidth(lineStrokeWidth);  
  81.         linePaint.setStyle(Paint.Style.FILL_AND_STROKE);  
  82.   
  83.         pointPaint = new Paint();  
  84.         pointPaint.setAntiAlias(true);  
  85.         pointPaint.setDither(true);  
  86.         pointPaint.setColor(pointColor);  
  87.         pointPaint.setStyle(Paint.Style.FILL);  
  88.     }  
  89.   
  90.     @Override  
  91.     protected void onDraw(Canvas canvas) {  
  92.         super.onDraw(canvas);  
  93.         if (drawLine) {  
  94.             drawTimeLine(canvas);  
  95.         }  
  96.     }  
  97.   
  98.     private void drawTimeLine(Canvas canvas) {  
  99.         int childCount = getChildCount();  
  100.   
  101.         if (childCount > 0) {  
  102.             //大于1,证明至少有2个,也就是第一个和第二个之间连成线,第一个和最后一个分别有点/icon  
  103.             if (childCount > 1) {  
  104.                 switch (curOrientation) {  
  105.                     case VERTICAL:  
  106.                         drawFirstChildViewVertical(canvas);  
  107.                         drawLastChildViewVertical(canvas);  
  108.                         drawBetweenLineVertical(canvas);  
  109.                         break;  
  110.                     case HORIZONTAL:  
  111.                         break;  
  112.                     default:  
  113.                         break;  
  114.                 }  
  115.             }  
  116.             else if (childCount == 1) {  
  117.                 switch (curOrientation) {  
  118.                     case VERTICAL:  
  119.                         drawFirstChildViewVertical(canvas);  
  120.                         break;  
  121.                     case HORIZONTAL:  
  122.                         break;  
  123.                     default:  
  124.                         break;  
  125.                 }  
  126.             }  
  127.         }  
  128.     }  
  129.   
  130.     private void drawFirstChildViewVertical(Canvas canvas) {  
  131.         if (getChildAt(0) != null) {  
  132.             int top = getChildAt(0).getTop();  
  133.             //记录值  
  134.             firstX = lineMarginSide;  
  135.             firstY = top + getChildAt(0).getPaddingTop() + lineDynamicDimen;  
  136.             //画一个圆  
  137.             canvas.drawCircle(firstX, firstY, pointSize, pointPaint);  
  138.         }  
  139.     }  
  140.   
  141.     private void drawLastChildViewVertical(Canvas canvas) {  
  142.         if (getChildAt(getChildCount() - 1) != null) {  
  143.             int top = getChildAt(getChildCount() - 1).getTop();  
  144.             //记录值  
  145.             lastX = lineMarginSide - (mIcon.getWidth() >> 1);  
  146.             lastY = top + getChildAt(getChildCount() - 1).getPaddingTop() + lineDynamicDimen;  
  147.             //画一个图  
  148.             canvas.drawBitmap(mIcon, lastX, lastY, null);  
  149.         }  
  150.     }  
  151.   
  152.     private void drawBetweenLineVertical(Canvas canvas) {  
  153.         for (int i = 0; i < getChildCount() - 1; i++) {  
  154.             //画剩下的  
  155.             canvas.drawLine(lineMarginSide, firstY, lineMarginSide, lastY, linePaint);  
  156.             //画了线,就画圆  
  157.             if (getChildAt(i) != null && i != 0) {  
  158.                 int top = getChildAt(i).getTop();  
  159.                 //记录值  
  160.                 int Y = top + getChildAt(i).getPaddingTop() + lineDynamicDimen;  
  161.                 canvas.drawCircle(lineMarginSide, Y, pointSize, pointPaint);  
  162.             }  
  163.         }  
  164.     }  
  165. }  


0 0
原创粉丝点击