热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android自定义控件实现时间轴

这篇文章主要为大家详细介绍了Android自定义控件实现时间轴,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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

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

1、先增加自定义属性:

<&#63;xml version="1.0" encoding="utf-8"&#63;>

 
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    

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&#63; = null, defStyleAttr: Int = 0) : LinearLayout(context, attrs, defStyleAttr) { private var mContext: Context&#63; = 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&#63; = null //线的画笔 private var mLinePaint: Paint&#63; = null //点的画笔 private var mPointPaint: Paint&#63; = 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&#63; 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&#63;.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&#63;.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&#63;.color = mPointOutColor canvas.drawCircle(mFirstX.toFloat(), mFirstY.toFloat(), mPointOutSize.toFloat(), mPointPaint) //画圆内环 mPointPaint&#63;.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)

仅供大家参考!

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


推荐阅读
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 本文介绍了在Python中检查字符串是否为字母、数字或空白字符的几种方法,包括使用str.isalnum()、str.isalpha()、str.isdigit()和str.isspace()等函数进行判断。 ... [详细]
author-avatar
琪琪
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有