本文主要是介绍快速简单的定制一个时间轴布局(UnderLineLinearLayout),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
github:
https://github.com/razerdp/UnderLineLinearLayout
先上图:
很多情况下,我们都会遇到需要类似于时间轴的一个布局,网上也有很多,但是很多情况下我们其实并不需要那么多库,毕竟64k限制就在那,不管我们用还是不用,它依然在那。。。
而且更多时候,我们的时间轴也许并不需要那么多数据(比如转账流程?)
事实上这次的教程也是因为我司需要弄一个转账流程,这个转账流程包含了基本的三个状态:
1 - 转账开始
2 - 转账中
3 - 转账成功
而失败后重新转账可以看到前面的状态,也就是前面的三个状态的重复
一般而言,转账3~4次失败我们也就算了,同时因为布局比较简单,所以我这次就没打算用listview,而是简单的继承LinearLayout
当然,如果数据比较多,为了内存建议还是用listview好
那么下面正文开始:
首先规划一下我们需要的元素,从图中我们可以看到的元素有:
线(颜色,宽),点(大小,颜色),图标
为了方便调整,我们还需要引入两个值
点距离父控件左边的偏移值(调整左右间距),每个节点距离childView的偏移值(调整上下间距)
于是我们的attrs.xml就出来了
[java] viewplain copy
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <declare-styleable name="UnderLineLinearLayout">
- <!--时间轴偏移值-->
- <attr name="line_margin_side" format="dimension"/>
- <!--时间轴动态调整值-->
- <attr name="line_dynamic_dimen" format="dimension"/>
- <!--线宽-->
- <attr name="line_stroke_width" format="dimension"/>
- <!--线的颜色-->
- <attr name="line_color" format="color"/>
- <!--点的大小-->
- <attr name="point_size" format="dimension"/>
- <!--点的颜色-->
- <attr name="point_color" format="color"/>
- <!--图标-->
- <attr name="icon_src" format="reference"/>
- </declare-styleable>
- </resources>
然后继承LinearLayout,开始我们的简易时间轴
[java] viewplain copy
- public UnderLineLinearLayout(Context context) {
- this(context, null);
- }
- public UnderLineLinearLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public UnderLineLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.UnderLineLinearLayout);
- lineMarginSide = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_line_margin_side, 10);
- lineDynamicDimen = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_line_dynamic_dimen, 0);
- lineStrokeWidth = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_line_stroke_width, 2);
- lineColor = attr.getColor(R.styleable.UnderLineLinearLayout_line_color, 0xff3dd1a5);
- pointSize = attr.getDimensionPixelSize(R.styleable.UnderLineLinearLayout_point_size, 8);
- pointColor = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_point_color, 0xff3dd1a5);
- int iconRes = attr.getResourceId(R.styleable.UnderLineLinearLayout_icon_src, R.drawable.ic_ok);
- BitmapDrawable temp = (BitmapDrawable) context.getResources().getDrawable(iconRes);
- if (temp != null) mIcon = temp.getBitmap();
- curOrientation = getOrientation();
- attr.recycle();
- initView(context);
- }
构造器我们获取各种参数,至于变量就不解释了
我们的主要方法都在onDraw里面,onDraw我们执行一个方法
[java] viewplain copy
- private void initView(Context context) {
- this.mContext = context;
- linePaint = new Paint();
- linePaint.setAntiAlias(true);
- linePaint.setDither(true);
- linePaint.setColor(lineColor);
- linePaint.setStrokeWidth(lineStrokeWidth);
- linePaint.setStyle(Paint.Style.FILL_AND_STROKE);
- pointPaint = new Paint();
- pointPaint.setAntiAlias(true);
- pointPaint.setDither(true);
- pointPaint.setColor(pointColor);
- pointPaint.setStyle(Paint.Style.FILL);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- if (drawLine) {
- drawTimeLine(canvas);
- }
- }
而我们的drawTimeLine的方法如下:
[java] viewplain copy
- private void drawTimeLine(Canvas canvas) {
- int childCount = getChildCount();
- if (childCount > 0) {
- //大于1,证明至少有2个,也就是第一个和第二个之间连成线,第一个和最后一个分别有点/icon
- if (childCount > 1) {
- switch (curOrientation) {
- case VERTICAL:
- drawFirstChildViewVertical(canvas);
- drawLastChildViewVertical(canvas);
- drawBetweenLineVertical(canvas);
- break;
- case HORIZONTAL:
- break;
- default:
- break;
- }
- }
- else if (childCount == 1) {
- switch (curOrientation) {
- case VERTICAL:
- drawFirstChildViewVertical(canvas);
- break;
- case HORIZONTAL:
- break;
- default:
- break;
- }
- }
- }
- }
按照我的设想,是想着横着也做一个的,但由于时间原因,就暂时未能实现,但其实实现原理都是一样的。
接下来就是最主要的几个方法了:
[java] viewplain copy
- private void drawFirstChildViewVertical(Canvas canvas) {
- if (getChildAt(0) != null) {
- int top = getChildAt(0).getTop();
- //记录值
- firstX = lineMarginSide;
- firstY = top + getChildAt(0).getPaddingTop() + lineDynamicDimen;
- //画一个圆
- canvas.drawCircle(firstX, firstY, pointSize, pointPaint);
- }
- }
- private void drawLastChildViewVertical(Canvas canvas) {
- if (getChildAt(getChildCount() - 1) != null) {
- int top = getChildAt(getChildCount() - 1).getTop();
- //记录值
- lastX = lineMarginSide - (mIcon.getWidth() >> 1);
- lastY = top + getChildAt(getChildCount() - 1).getPaddingTop() + lineDynamicDimen;
- //画一个图
- canvas.drawBitmap(mIcon, lastX, lastY, null);
- }
- }
- private void drawBetweenLineVertical(Canvas canvas) {
- for (int i = 0; i < getChildCount() - 1; i++) {
- //画剩下的
- canvas.drawLine(lineMarginSide, firstY, lineMarginSide, lastY, linePaint);
- //画了线,就画圆
- if (getChildAt(i) != null && i != 0) {
- int top = getChildAt(i).getTop();
- //记录值
- int Y = top + getChildAt(i).getPaddingTop() + lineDynamicDimen;
- canvas.drawCircle(lineMarginSide, Y, pointSize, pointPaint);
- }
- }
- }
这里说说思路:
首先我们在ondraw里面获取子控件的数量,然后通过子控件的属性定位我们的时间轴
第一步我们先确定第一个子控件的位置,这里因为垂直的时间轴,所以我们通过top+paddingTop来确定我们的结点Y位置,同时引用我们xml定义好的dynamic值来微调。同时记录下此时第一个结点的x,y
第二步我们确定最后一个控件的位置,方法同第一步,也记录下此时最后一个节点的x,y。同时调用drawBitmap画出我们的icon
第三步我们就画第一个和最后一个之间的子控件的线和结点。相关注释都在代码中标注好了,所以这里就不再详细阐述了
最后,因为是一个继承LinearLayout的ViewGroup,所以使用方法直接addView或者xml里面愉悦的塞进去吧-V-
这个工程还没扩展完成,以后如果有时间我希望能把水平方向的也弄出来。当然,如果诸位有更nice的修正欢迎PullRequest.
这是一个简单的时间轴定制,希望能够帮到你-V-(详细代码请看github)
附:
完整代码:
[java] viewplain copy
- package razerdp.widget;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Paint;
- import android.graphics.drawable.BitmapDrawable;
- import android.util.AttributeSet;
- import android.widget.LinearLayout;
- /**
- * Created by 大灯泡 on 2016/1/21.
- * 简易带有时间轴的linearlayout
- */
- public class UnderLineLinearLayout extends LinearLayout {
- //=============================================================元素定义
- private Bitmap mIcon;
- //line location
- private int lineMarginSide;
- private int lineDynamicDimen;
- //line property
- private int lineStrokeWidth;
- private int lineColor;
- //point property
- private int pointSize;
- private int pointColor;
- //=============================================================paint
- private Paint linePaint;
- private Paint pointPaint;
- //=============================================================其他辅助参数
- //第一个点的位置
- private int firstX;
- private int firstY;
- //最后一个图的位置
- private int lastX;
- private int lastY;
- //默认垂直
- private int curOrientation = VERTICAL;
- private Context mContext;
- //开关
- private boolean drawLine = true;
- public UnderLineLinearLayout(Context context) {
- this(context, null);
- }
- public UnderLineLinearLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public UnderLineLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.UnderLineLinearLayout);
- lineMarginSide = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_line_margin_side, 10);
- lineDynamicDimen = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_line_dynamic_dimen, 0);
- lineStrokeWidth = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_line_stroke_width, 2);
- lineColor = attr.getColor(R.styleable.UnderLineLinearLayout_line_color, 0xff3dd1a5);
- pointSize = attr.getDimensionPixelSize(R.styleable.UnderLineLinearLayout_point_size, 8);
- pointColor = attr.getDimensionPixelOffset(R.styleable.UnderLineLinearLayout_point_color, 0xff3dd1a5);
- int iconRes = attr.getResourceId(R.styleable.UnderLineLinearLayout_icon_src, R.drawable.ic_ok);
- BitmapDrawable temp = (BitmapDrawable) context.getResources().getDrawable(iconRes);
- if (temp != null) mIcon = temp.getBitmap();
- curOrientation = getOrientation();
- attr.recycle();
- initView(context);
- }
- private void initView(Context context) {
- this.mContext = context;
- linePaint = new Paint();
- linePaint.setAntiAlias(true);
- linePaint.setDither(true);
- linePaint.setColor(lineColor);
- linePaint.setStrokeWidth(lineStrokeWidth);
- linePaint.setStyle(Paint.Style.FILL_AND_STROKE);
- pointPaint = new Paint();
- pointPaint.setAntiAlias(true);
- pointPaint.setDither(true);
- pointPaint.setColor(pointColor);
- pointPaint.setStyle(Paint.Style.FILL);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- if (drawLine) {
- drawTimeLine(canvas);
- }
- }
- private void drawTimeLine(Canvas canvas) {
- int childCount = getChildCount();
- if (childCount > 0) {
- //大于1,证明至少有2个,也就是第一个和第二个之间连成线,第一个和最后一个分别有点/icon
- if (childCount > 1) {
- switch (curOrientation) {
- case VERTICAL:
- drawFirstChildViewVertical(canvas);
- drawLastChildViewVertical(canvas);
- drawBetweenLineVertical(canvas);
- break;
- case HORIZONTAL:
- break;
- default:
- break;
- }
- }
- else if (childCount == 1) {
- switch (curOrientation) {
- case VERTICAL:
- drawFirstChildViewVertical(canvas);
- break;
- case HORIZONTAL:
- break;
- default:
- break;
- }
- }
- }
- }
- private void drawFirstChildViewVertical(Canvas canvas) {
- if (getChildAt(0) != null) {
- int top = getChildAt(0).getTop();
- //记录值
- firstX = lineMarginSide;
- firstY = top + getChildAt(0).getPaddingTop() + lineDynamicDimen;
- //画一个圆
- canvas.drawCircle(firstX, firstY, pointSize, pointPaint);
- }
- }
- private void drawLastChildViewVertical(Canvas canvas) {
- if (getChildAt(getChildCount() - 1) != null) {
- int top = getChildAt(getChildCount() - 1).getTop();
- //记录值
- lastX = lineMarginSide - (mIcon.getWidth() >> 1);
- lastY = top + getChildAt(getChildCount() - 1).getPaddingTop() + lineDynamicDimen;
- //画一个图
- canvas.drawBitmap(mIcon, lastX, lastY, null);
- }
- }
- private void drawBetweenLineVertical(Canvas canvas) {
- for (int i = 0; i < getChildCount() - 1; i++) {
- //画剩下的
- canvas.drawLine(lineMarginSide, firstY, lineMarginSide, lastY, linePaint);
- //画了线,就画圆
- if (getChildAt(i) != null && i != 0) {
- int top = getChildAt(i).getTop();
- //记录值
- int Y = top + getChildAt(i).getPaddingTop() + lineDynamicDimen;
- canvas.drawCircle(lineMarginSide, Y, pointSize, pointPaint);
- }
- }
- }
- }
这篇关于快速简单的定制一个时间轴布局(UnderLineLinearLayout)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!