时间轴控件TimeLineView的实现
16lz
2021-01-24
转载请标明出处:http://blog.csdn.net/newhope1106/article/details/53525120 首先来看看效果图吧,可以根据需要设置出很炫的效果
android中经常会用到时间轴,那么如何实现时间轴呢?首先我们了解时间轴的构成 (1)时间球 (2)直线 (3)位置 下面介绍一个时间轴实现的开源代码: https://github.com/newhope1106/TimeLineView 把这几个问题解决再掌握基本的绘制过程就可以实现时间轴了。下面先来看代码。
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可以看到效果。 更多相关文章
- ImageView通过matrix实现手势缩放
- android 网络下载图片 效率对比
- Flutter开始干系列-一个完整的登录实践
- Android(安卓)滑动效果基础篇(四)—— Gallery + GridView
- 第三方QQ登录不回调 (Android)
- android 默认浏览器 无法下载,此手机不支持此内容(自定义文件or AP
- 使用InjectView和findViewById说拜拜
- Android(安卓)高手进阶教程(十三)之----Android(安卓)数据库SQLi
- 认识 android-job