Android自定义控件实现时间轴

本文实例为大家分享了Android自定义控件实现时间轴的具体代码,供大家参考,具体内容如下

由于项目中有需求,就简单的封装一个,先记录一下,有时间上传到github。

1、先增加自定义属性:



 
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    

2、自定义时间轴类:

/**
     * 时间轴控件
 * 

The following snippet shows how to include a linear layout in your layout XML file:

* * * *

The following snippet shows how to java file:

* timelineLayout.setPointMarginTop(10) timelineLayout.setLineMarginTop(10) timelineLayout.setPointMarginTop(40) timelineLayout.setInterrupt(true) */ class TimeLinearLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : LinearLayout(context, attrs, defStyleAttr) { private var mContext: Context? = null private var mLineMarginLeft: Int = 10 private var mLineMarginTop: Int = 0 private var mPointMarginTop: Int = 0 private var mLineStrokeWidth: Int = 2 private var mLineColor: Int = 0 //内圆半径 private var mPointInnerSize: Int = 8 //外圆半径 private var mPointOutSize: Int = 18 //内圆颜色 private var mPointInnerColor: Int = 0 //外圆颜色 private var mPointOutColor: Int = 0 //虚线宽 private var mDashWidth: Int = 0 //虚线空白宽 private var mDashGap: Int = 0 //是否中断 private var mInterrupt: Boolean = false private var mIcon: Bitmap? = null //线的画笔 private var mLinePaint: Paint? = null //点的画笔 private var mPointPaint: Paint? = null //第一个点的位置 private var mFirstX = 0 private var mFirstY = 0 //最后一个图标的位置 private var mLastX = 0 private var mLastY = 0 init { setLayerType(View.LAYER_TYPE_SOFTWARE, null) //开启硬件加速 val ta = context.obtainStyledAttributes(attrs, R.styleable.global_TimelineLayout) mLineMarginLeft = ta.getDimensionPixelOffset(R.styleable.global_TimelineLayout_global_line_margin_left, 10) mLineMarginTop = ta.getDimensionPixelOffset(R.styleable.global_TimelineLayout_global_line_margin_top, 0) mPointMarginTop = ta.getDimensionPixelOffset(R.styleable.global_TimelineLayout_global_point_margin_top, 0) mLineStrokeWidth = ta.getDimensionPixelOffset(R.styleable.global_TimelineLayout_global_line_stroke_width, 2) mLineColor = ta.getColor(R.styleable.global_TimelineLayout_global_line_color, -0xc22e5b) mPointInnerSize = ta.getDimensionPixelSize(R.styleable.global_TimelineLayout_global_point_inner_size, 8) mPointOutSize = ta.getDimensionPixelSize(R.styleable.global_TimelineLayout_global_point_out_size, 18) mPointInnerColor = ta.getColor(R.styleable.global_TimelineLayout_global_point_inner_color, -0xc22e5b) mPointOutColor = ta.getColor(R.styleable.global_TimelineLayout_global_point_out_color, -0x170f01) mDashGap = ta.getDimensionPixelOffset(R.styleable.global_TimelineLayout_global_dash_gap, 0) mDashWidth = ta.getDimensionPixelOffset(R.styleable.global_TimelineLayout_global_dash_width, 0) val iconRes = ta.getResourceId(R.styleable.global_TimelineLayout_global_icon_src, View.NO_ID) if (iconRes > View.NO_ID) { val drawable = ContextCompat.getDrawable(context,iconRes) as? BitmapDrawable if (drawable != null) { mIcon = drawable.bitmap } } ta.recycle() setWillNotDraw(false) initView(context) } fun setLineMarginTop(lineMarginTop:Int){ this.mLineMarginTop = lineMarginTop } fun setPointMarginTop(pointMarginTop:Int){ this.mPointMarginTop = pointMarginTop } fun setInterrupt(interrupt:Boolean){ this.mInterrupt = interrupt } private fun initView(context: Context) { mContext = context mLinePaint = Paint() mLinePaint?.apply { isAntiAlias = true isDither = true color = mLineColor strokeWidth = mLineStrokeWidth.toFloat() style = Paint.Style.FILL_AND_STROKE //虚线设置 if (mDashGap > 0 && mDashWidth > 0) { //mLinePaint.setPathEffect(new DashPathEffect(new float[]{20,5}, 20)); pathEffect = DashPathEffect(floatArrayOf(mDashWidth.toFloat(), mDashGap.toFloat()), mDashWidth.toFloat()) } } mPointPaint = Paint() mPointPaint?.apply { isAntiAlias = true isDither = true color = mPointInnerColor style = Paint.Style.FILL } } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) drawTimeline(canvas) } private fun drawTimeline(canvas: Canvas) { drawBetweenLine(canvas) drawFirstPoint(canvas) drawLastIcon(canvas) } private fun drawFirstPoint(canvas: Canvas) { val top = top mFirstX = paddingLeft + mLineMarginLeft + max(mPointOutSize, mPointInnerSize) mFirstY = top + paddingTop + mPointMarginTop + max(mPointOutSize, mPointInnerSize) //画圆外环 mPointPaint?.color = mPointOutColor canvas.drawCircle(mFirstX.toFloat(), mFirstY.toFloat(), mPointOutSize.toFloat(), mPointPaint) //画圆内环 mPointPaint?.color = mPointInnerColor canvas.drawCircle(mFirstX.toFloat(), mFirstY.toFloat(), mPointInnerSize.toFloat(), mPointPaint) } private fun drawLastIcon(canvas: Canvas) { /*if (child != null) { int top = child.getTop(); mLastX = mLineMarginLeft; mLastY = top + child.getPaddingTop() + mLineMarginTop; //画图 canvas.drawBitmap(mIcon, mLastX - (mIcon.getWidth() >> 1), mLastY, null); }*/ val top = top mLastX = mLineMarginLeft + paddingLeft mLastY = top + paddingTop + mLineMarginTop //画图 if (mIcon != null) { canvas.drawBitmap(mIcon, mLastX - (mIcon!!.width shr 1).toFloat(), height - mIcon!!.height.toFloat(), null) } } private fun drawBetweenLine(canvas: Canvas) { val top = top mFirstX = paddingLeft + mLineMarginLeft + max(mPointOutSize, mPointInnerSize) mFirstY = top + paddingTop + mLineMarginTop mLastX = paddingLeft + mLineMarginLeft + max(mPointOutSize, mPointInnerSize) mLastY = if(!mInterrupt) {top + paddingTop + mLineMarginTop + height} else mPointMarginTop //从开始的点到最后的图标之间,画一条线 canvas.drawLine(mFirstX.toFloat(), mFirstY.toFloat(), mLastX.toFloat(), mLastY.toFloat(), mLinePaint) //画圆 //val y = top + paddingTop + mLineMarginTop + mPointInnerSize //canvas.drawCircle(mFirstX, y, mPointSize, mPointPaint); } override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) val mode = MeasureSpec.getMode(widthMeasureSpec) var measuredWidth = MeasureSpec.getSize(widthMeasureSpec) val measuredHeight = MeasureSpec.getSize(heightMeasureSpec) if (mode == MeasureSpec.AT_MOST) { measuredWidth = paddingLeft + mLineMarginLeft + max(mPointOutSize, mPointInnerSize) * 2 } setMeasuredDimension(measuredWidth, measuredHeight) } }

布局中可以直接引用,如下:


            

也可以在代码里面动态设置相关属性(相关属性注释,在自定义属性时有说明):

timelineLayout.setPointMarginTop(10)
    timelineLayout.setLineMarginTop(10)
    timelineLayout.setPointMarginTop(40)
    timelineLayout.setInterrupt(true)

仅供大家参考!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

你可能感兴趣的:(Android自定义控件实现时间轴)