转载请标明出处:http://blog.csdn.net/newhope1106/article/details/53525120 首先来看看效果图吧,可以根据需要设置出很炫的效果
android中经常会用到时间轴,那么如何实现时间轴呢?首先我们了解时间轴的构成 (1)时间球 (2)直线 (3)位置 下面介绍一个时间轴实现的开源代码: https://github.com/newhope1106/TimeLineView 把这几个问题解决再掌握基本的绘制过程就可以实现时间轴了。下面先来看代码。

(1)定义属性,用户可以自定义的属性值

<?xml version="1.0" encoding="utf-8"?>                                                

(2)代码实现
import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.view.View;/** * @author appleye * @date 2016-12-02 * 时间轴控件 */public class TimeLineView extends View {    /**顶部时间球*/    private Drawable mTopTimeBall;    /**底部时间球*/    private Drawable mBottomTimeBall;    /**顶部时间球到view的时间线*/    private Drawable mStartLine;    /**顶部时间球到底部的时间线*/    private Drawable mEndLine;    /**时间球大小*/    private int mBallSize;    /**时间线宽度*/    private int mLineWidth;    /**顶部时间球中心距离顶部的距离*/    private int mBallCenterMarginTop;    private Rect mBounds;    private Context mContext;    /**顶部时间线是否可见*/    private boolean mIsTopLineVisible = false;    /**底部时间球是否可见*/    private boolean mIsBottomBallVisible = false;    public TimeLineView(Context context, AttributeSet attrs) {        super(context, attrs);        mContext = context;        init(attrs);    }    private void init(AttributeSet attrs) {        /*获取xml中设置的属性值*/        TypedArray typedArray = getContext().obtainStyledAttributes(attrs,R.styleable.timeline_style);        mTopTimeBall = typedArray.getDrawable(R.styleable.timeline_style_ball);        mBottomTimeBall = typedArray.getDrawable(R.styleable.timeline_style_ball);        mStartLine = typedArray.getDrawable(R.styleable.timeline_style_line);        mEndLine = typedArray.getDrawable(R.styleable.timeline_style_line);        mBallSize = typedArray.getDimensionPixelSize(R.styleable.timeline_style_ballSize, 25);        mLineWidth = typedArray.getDimensionPixelSize(R.styleable.timeline_style_lineWidth, 2);        mBallCenterMarginTop = typedArray.getDimensionPixelSize(R.styleable.timeline_style_ballCenterMargin, 0);        typedArray.recycle();        /*没有设置drawable属性值,则采用缺省值*/        if(mTopTimeBall == null) {            mTopTimeBall = mContext.getResources().getDrawable(R.drawable.ball);        }        if(mBottomTimeBall == null) {            mBottomTimeBall = mContext.getResources().getDrawable(R.drawable.ball);        }        if(mStartLine == null) {            mStartLine = mContext.getResources().getDrawable(R.drawable.time_line);        }        if(mEndLine == null) {            mEndLine = mContext.getResources().getDrawable(R.drawable.time_line);        }    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int w = mBallSize + getPaddingLeft() + getPaddingRight();        int h = mBallSize + getPaddingTop() + getPaddingBottom();        int widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);        int heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);        setMeasuredDimension(widthSize, heightSize);        initTimeLineView();    }    /**     * 初始化时间轴控件的位置大小等     * */    private void initTimeLineView() {        int paddingLeft = getPaddingLeft();        int paddingRight = getPaddingRight();        int paddingTop = getPaddingTop();        int paddingBottom = getPaddingBottom();        int width = getWidth();// Width of current custom view        int height = getHeight();        /*有效的宽度*/        int effectWidth = width - paddingLeft - paddingRight;        /*有效高度*/        int effectHeight = height - paddingTop - paddingBottom;        /*时间球实际大小不能大于有效宽高度*/        int ballSize = Math.min(mBallSize, Math.min(effectWidth, effectHeight));        /*顶部时间球位置*/        if(mTopTimeBall != null) {            mTopTimeBall.setBounds(paddingLeft, paddingTop + mBallCenterMarginTop,                    paddingLeft + ballSize, paddingTop + ballSize + mBallCenterMarginTop);            mBounds = mTopTimeBall.getBounds();        } else {            mBounds = new Rect(paddingLeft, 0, paddingLeft + ballSize, 0);        }        int centerX = mBounds.centerX();        int lineLeft = centerX - (mLineWidth >> 1);        if(mIsTopLineVisible && mStartLine!=null) {            mStartLine.setBounds(lineLeft, 0, mLineWidth + lineLeft, mBounds.top);        }        if(mEndLine != null) {            mEndLine.setBounds(lineLeft, mBounds.bottom, mLineWidth + lineLeft, height);        }        if(mIsBottomBallVisible && mBottomTimeBall != null){            mBottomTimeBall.setBounds(paddingLeft,height - paddingBottom - ballSize,                    paddingLeft + ballSize, height - paddingBottom);        }    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        if(mTopTimeBall != null) {            mTopTimeBall.draw(canvas);        }        if(mIsTopLineVisible && mStartLine != null) {            mStartLine.draw(canvas);        }        if(mEndLine != null) {            mEndLine.draw(canvas);        }        if(mIsBottomBallVisible && mBottomTimeBall != null) {            mBottomTimeBall.draw(canvas);        }    }    /**     * 设置顶部时间球     * */    public void setTopTimeBallDrawable(Drawable ball) {        mTopTimeBall = ball;        initTimeLineView();    }    /**     * 设置底部时间球     * */    public void setBottomTimeDrawable(Drawable ball) {        mBottomTimeBall = ball;        initTimeLineView();    }    /**     * 时间球大小     * */    public void setTimeBallSize(int ballSize) {        mBallSize = ballSize;        initTimeLineView();    }    /**     * 时间球中心位于顶部的距离     * */    public void setBallMarginTop(int top) {        mBallCenterMarginTop = top;        initTimeLineView();    }    /**     * 时间轴宽度     * */    public void setLineWidth(int width) {        mLineWidth = width;        initTimeLineView();    }    /**     * 顶部时间线是否可见     * */    public void setTopLineVisible(boolean visible) {        mIsTopLineVisible = visible;    }    /**     * 底部时间球是否可见     * */    public void setBottomBallVisible(boolean visible) {        mIsBottomBallVisible = visible;    }}
上述代码200行左右,核心的代码也非常少,在控件的构造方法里面,把用户自定义的值获取到,如果没有定义,使用缺省值。在onMeasure里面计算好宽高,以及时间球,直线的位置,然后在控件的onDraw方法中把它绘制好。基本逻辑比较简单 (3)使用,把它加到xml布局当中,设置一些属性值,也可以在代码中重新设置一些值
代码重新设置属性,具体代码可以查看源码里面的demo
TimeLineView timeLineView = (TimeLineView) convertView.findViewById(R.id.time_line);textView.setText(mData.get(position));timeLineView.setTopLineVisible(false);timeLineView.setBottomBallVisible(false);if(position != 0) {    timeLineView.setTopLineVisible(true);}if(getCount() - 1 == position) {    timeLineView.setBottomBallVisible(true);}switch (position % 3) {    case 0 :{        timeLineView.setTopTimeBallDrawable(getResources().getDrawable(R.drawable.green_ball));        break;    }    case 1 :{        timeLineView.setTopTimeBallDrawable(getResources().getDrawable(R.drawable.yellow_ball));        break;    }    case 2 :{        timeLineView.setTopTimeBallDrawable(getResources().getDrawable(R.drawable.pink_ball));        break;    }}/*调用下面强制绘制,否则会出现显示错位问题*/timeLineView.invalidate();
注意: 在listview中使用的时候,由于adapter使用了缓存,因此如果时间轴控件显示不一致的情况下,使用缓存会导致显示错位问题,这时可以调用invalidate强制绘制即可。具体的实现,在 https://github.com/newhope1106/TimeLineView有demo可以看到效果。



更多相关文章

  1. ImageView通过matrix实现手势缩放
  2. android 网络下载图片 效率对比
  3. Flutter开始干系列-一个完整的登录实践
  4. Android(安卓)滑动效果基础篇(四)—— Gallery + GridView
  5. 第三方QQ登录不回调 (Android)
  6. android 默认浏览器 无法下载,此手机不支持此内容(自定义文件or AP
  7. 使用InjectView和findViewById说拜拜
  8. Android(安卓)高手进阶教程(十三)之----Android(安卓)数据库SQLi
  9. 认识 android-job

随机推荐

  1. Linux和Windows下查看、设置环境变量的比
  2. 这个冬天,他们实现了梦想中的华丽转身…
  3. 在Linux中的脚本中安装应用程序
  4. linux shell 里面,真值为0,假值为非0
  5. linux 多线程基础
  6. linux 内核协议栈
  7. Linux进程间通信(二):信号集函数 sigemptyse
  8. Linux C语言实现的Socket通信
  9. 总结一下linux中的分段机制
  10. 如何在Linux中以编程方式获取给定相对路