Android自定義控件實現(xiàn)時間軸
本文實例為大家分享了Android自定義控件實現(xiàn)時間軸的具體代碼,供大家參考,具體內(nèi)容如下
由于項目中有需求,就簡單的封裝一個,先記錄一下,有時間上傳到github。
1、先增加自定義屬性:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="global_TimelineLayout"> <!--時間軸左偏移值--> <attr name="global_line_margin_left" format="dimension" /> <!--時間軸上偏移值--> <attr name="global_line_margin_top" format="dimension" /> <!--線寬--> <attr name="global_line_stroke_width" format="dimension" /> <!--線的顏色--> <attr name="global_line_color" format="color" /> <!--點的大小--> <attr name="global_point_inner_size" format="dimension" /> <attr name="global_point_out_size" format="dimension" /> <!--點的上偏移值--> <attr name="global_point_margin_top" format="dimension" /> <!--點的顏色--> <attr name="global_point_inner_color" format="color" /> <attr name="global_point_out_color" format="color" /> <!--圖標(biāo)--> <attr name="global_icon_src" format="reference" /> <!--虛線--> <attr name="global_dash_gap" format="dimension" /> <attr name="global_dash_width" format="dimension" /> </declare-styleable> </resources>
2、自定義時間軸類:
/** * 時間軸控件 * <p>The following snippet shows how to include a linear layout in your layout XML file:</p> * * <com.taoche.mars.commonres.widget.TimelineLayout android:id="@+id/tl_02" android:layout_width="40dp" android:layout_height="match_parent" app:global_line_margin_left="10dp" app:global_line_margin_top="0dp" app:global_point_margin_top="10dp" app:global_point_inner_color="#377CFF" app:global_point_out_color="#FFE8F0FF" app:global_point_out_size="8dp" app:global_point_inner_size="4dp" app:global_dash_width="8dp" app:global_dash_gap="2dp" app:global_line_color="#C9DCFF"> </com.taoche.mars.commonres.widget.TimelineLayout> * * <p>The following snippet shows how to java file:</p> * 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 //內(nèi)圓半徑 private var mPointInnerSize: Int = 8 //外圓半徑 private var mPointOutSize: Int = 18 //內(nèi)圓顏色 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 //最后一個圖標(biāo)的位置 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 //虛線設(shè)置 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) //畫圓外環(huán) mPointPaint?.color = mPointOutColor canvas.drawCircle(mFirstX.toFloat(), mFirstY.toFloat(), mPointOutSize.toFloat(), mPointPaint) //畫圓內(nèi)環(huán) 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 //從開始的點到最后的圖標(biāo)之間,畫一條線 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) } }
布局中可以直接引用,如下:
<com.example.demo1224.TimelineLayout android:layout_width="wrap_content" android:layout_height="match_parent" app:line_margin_left="25dp" app:line_margin_top="0dp" app:point_margin_top="10dp" app:point_inner_color="#377CFF" app:point_out_color="#FFE8F0FF" app:point_out_size="8dp" app:point_inner_size="4dp" app:dash_width="8dp" app:dash_gap="2dp" app:line_color="#C9DCFF" android:orientation="vertical" android:background="@android:color/white"> </com.example.demo1224.TimelineLayout>
也可以在代碼里面動態(tài)設(shè)置相關(guān)屬性(相關(guān)屬性注釋,在自定義屬性時有說明):
timelineLayout.setPointMarginTop(10) timelineLayout.setLineMarginTop(10) timelineLayout.setPointMarginTop(40) timelineLayout.setInterrupt(true)
僅供大家參考!
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
android的RecyclerView實現(xiàn)拖拽排序和側(cè)滑刪除示例
在平時開發(fā)應(yīng)用的時候,經(jīng)常會遇到列表排序、滑動刪除的需求。這篇文章主要介紹了android的RecyclerView實現(xiàn)拖拽排序和側(cè)滑刪除示例,有興趣的可以了解一下。2017-02-02Kotlin實現(xiàn)半圓形進(jìn)度條的方法示例
這篇文章主要給大家介紹了關(guān)于Kotlin實現(xiàn)半圓形進(jìn)度條的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧。2018-03-03Android RecyclerView自由拖動item的實現(xiàn)代碼
這篇文章主要介紹了Android RecyclerView自由拖動item的實現(xiàn)代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-01-01Android中CountDownTimer倒計時器用法實例
這篇文章主要介紹了Android中CountDownTimer倒計時器用法,以實例形式分析了Android中CountDownTimer類的相關(guān)使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-10-10Android Activity Results API代替onActivityResul
說到onActivityResult,我們已經(jīng)非常熟悉來,通過在A activity啟動B activity并且傳入數(shù)據(jù)到B中,然后在A中通過onActivityResult來接收B中返回的數(shù)據(jù)。在最新的activity-ktx的beta版本中,谷歌已經(jīng)廢棄了onActivityResult2022-09-09Android中使用PagerSlidingTabStrip實現(xiàn)導(dǎo)航標(biāo)題的示例
本篇文章主要介紹了Android中使用PagerSlidingTabStrip實現(xiàn)導(dǎo)航標(biāo)題的示例,具有一定的參考價值,有興趣的可以了解一下。2017-01-01