Android自定义视图一:扩展现有的视图,添加新的XML属性

简介:

这个系列是老外写的,干货!翻译出来一起学习。如有不妥,不吝赐教!

  1. Android自定义视图一:扩展现有的视图,添加新的XML属性
  2. Android自定义视图二:如何绘制内容
  3. Android自定义视图三:给自定义视图添加“流畅”的动画
  4. Android自定义视图四:定制onMeasure强制显示为方形

简介

这个系列详细的介绍了如何穿件Android自定义视图。主要涉及的内容有如何绘制内容,layout和measure的原理,如何继承实现view group以及如何给其子视图添加动画。第一篇主要讲述如何扩展和使用现有的视图,以及如何添加特有的XML属性。

特定的任务使用特定的视图

Android提供的view都是比较通用的,哪里都可以用。但是在开发应用的过程中需要对这些通用的view加以修改。很多时候这些代码都添加到了Activity中,这样是的Activity的代码杂乱,影响维护。

假设你在开发一个最用用户训练数据的应用。比如用户的总运动时长,总运动距离以及不同的运动类型等。为了友好的把数据展现给用户,你需要根据用户运动的时间长度做不同的处理。比如他运动了2378秒,那么显示的肯定是48分钟。18550秒,那显示的肯定是5小时9分钟。

创建一个自定义视图

处理上面的问题最好就是定义一个view。这个view里包含了处理上面时间的功能。我们来创建一个自定义view:DurationTextView

class DurationTextView : TextView {
    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
    }
}

TextView和其他的view一样有三个构造函数:一个是只需要Context的,一个是上面给出的需要两个参数ContextAttributeSet,还有一个需要这两个参数之外的关于style的参数。一般来说,上面给出的构造方法就可以满足。下面在布局中使用上面定义的view。

<demo.customview.customviewdemo.Views.DurationTextView
    android:id="@+id/duration_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

注意,这里需要给出自定义视图的全名称。

添加展示逻辑

现在这个视图和标准的TextView没什么太大的区别。我们为这个view添加一个duration属性来设置和读取duration值。

var duration: Float
get() = _duration
set(value) {
    _duration = value

    var durationInMinutes: Int = Math.round(_duration / 60)
    var hours: Int = durationInMinutes / 60
    var minutes: Int = durationInMinutes % 60

    var hourText: String = ""
    var minuteText: String = ""

    if (hours > 0) {
        hourText = "$hours ${if (hours == 1) "hour" else "hours"}"
    }

    if (minutes > 0) {
        minuteText = "$minutes ${if (minutes == 1) "minute" else "minutes"}"
    }

    if (hours == 0 && minutes == 0) {
        minuteText = "Less than 1 minute"
    }

    var durationText = TEXT_TEMPLATE.format(hourText, minuteText)

    text = durationText
}

companion object {
    val TEXT_TEMPLATE = "Duration: %s %s"
}

这个方法接受一个Float型的参数,训练时间的秒数。然后通过上面的转换逻辑把这个秒数转成用户友好的文字值。最后赋值给TextView的text。转换的逻辑非常简单,就是把秒数转为分钟数,最后转为小时和分钟的值。分钟和小时数如果大于1的时候单位就显示为minutes和hours,等于1的时候为minute和hour。

用起来

现在就可以试试效果了。在Activity的onCreate()方法里添加下面的代码:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    var durationTextView1 = findViewById(R.id.duration_view1) as DurationTextView
    durationTextView1.duration = 2378.0f

    var durationTextView2 = findViewById(R.id.duration_view2) as DurationTextView
    durationTextView2.duration = 3670.0f

    var durationTextView3 = findViewById(R.id.duration_view3) as DurationTextView
    durationTextView3.duration = 18550.0f
}

运行结果如下图:

看起来还不错吧。

添加XML属性

如果我们能够这个view添加一个方法来设置文本展示的模板,就像设定duration一样。但是,这个template其实并不会想duration一样需要经常的设置,更多的是一个类似于常数一样的存在。所以对于添加一个方法来说,添加一个XML属性更加合适。

首先添加values/attrs.xml文件,XML属性就在这个文件中定义。我们只需要添加一个字符串类型的,名称为template的属性。添加之后attrs.xml文件看起来是这样的:

<resources>
    <declare-styleable name="TemplateTextView">
        <attr name="template" format="string" />
    </declare-styleable>
</resources>

我们声明了一个名称为TemplateTextViewdeclare-styleable节点。名字可以任意起,不过最好还是在哪个view里使用就叫做什么。这里叫做TemplateTextView是因为后面这个XML属性会用与很多其他的自定义view中。来看看是怎么使用这个属性的。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="demo.customview.customviewdemo.MainActivity">

    <demo.customview.customviewdemo.Views.DurationTextView
        android:id="@+id/duration_view1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Customized"
        android:textSize="20sp"
        app:template="%s was spent running" />
        
        <!-- ...... -->

</LinearLayout>

在格式化代码(快捷键Ctrl+Alt+L,或者Cmd+Alt+L)后在LinearLayout中会增加一行xmlns:app="http://schemas.android.com/apk/res-auto"这一句声明了一个namespace,这样APP就可以理解我们刚刚在自定义view的布局中添加的属性了。当然需要使用这条声明里指定的app为前缀:app:template="%s was spent running"

现在就需要我们在代码里读取并应用新添加的属性值了。首先添加一个var template:String? = null的属性,准备接收解析的字符串模板。

var attributes = context.obtainStyledAttributes(attributeSet, R.styleable.TemplateTextView)
template = attributes.getString(R.styleable.TemplateTextView_template)

if (template == null || !(template?.contains("%s", ignoreCase = true) ?: false)) {
    template = TEXT_TEMPLATE
}

attributes.recycle()

第一行使用了AttributeSet类型的参数attributeSet,这个参数包含了在attrs.xml文件中定义的全部的属性。 方法obtainStyledAttributes()主要做了两件事:

  1. 过滤全部的自定义属性,并把这些属性的定义和给定的值关联起来。
  2. 返回你在第二个参数所指定的属性组合。

R.styleable.TemplateTextView就是我们自己定义的属性数组,这里只有一个元素。R.styleable.TemplateTextView_template是我们自定义属性数组里的那个叫做template的元素。然后我们使用typed array来获取这个属性的值。如果没有设置模板,或者模板中不包含处理字符串的%s的话就是用我们之前定义的默认的文字模板来代替。

但是有一点需要格外注意:不管有没有获取到属性值,都要回收TypedArray对象attributes.recycle()

上下两个分别设定了不同的template,中间的不设定,运行一下看看修改后的效果如何:

对于大多数的Android视图XML属性都有对应的方法来通过代码的方式设置对应的值。对于自定义视图是否需要这么做,主要取决于你打算怎么用。添加一个方法也没什么问题。

下一篇主要简述如何绘制视图的内容,并自定义一个显示折线图的视图。

欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 572064792 | Nodejs:329118122 做人要厚道,转载请注明出处!














本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sunshine-anycall/p/5448108.html ,如需转载请自行联系原作者

相关文章
|
Android开发 UED 计算机视觉
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
本文介绍了一款受游戏“金铲铲之战”启发的Android自定义View——线条等待动画的实现过程。通过将布局分为10份,利用`onSizeChanged`测量最小长度,并借助画笔绘制动态线条,实现渐变伸缩效果。动画逻辑通过四个变量控制线条的增长与回退,最终形成流畅的等待动画。代码中详细展示了画笔初始化、线条绘制及动画更新的核心步骤,并提供完整源码供参考。此动画适用于加载场景,提升用户体验。
773 5
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
|
Android开发
Android自定义view之利用PathEffect实现动态效果
本文介绍如何在Android自定义View中利用`PathEffect`实现动态效果。通过改变偏移量,结合`PathEffect`的子类(如`CornerPathEffect`、`DashPathEffect`、`PathDashPathEffect`等)实现路径绘制的动态变化。文章详细解析了各子类的功能与参数,并通过案例代码展示了如何使用`ComposePathEffect`组合效果,以及通过修改偏移量实现动画。最终效果为一个菱形图案沿路径运动,源码附于文末供参考。
274 0
|
XML Java Android开发
Android自定义view之网易云推荐歌单界面
本文详细介绍了如何通过自定义View实现网易云音乐推荐歌单界面的效果。首先,作者自定义了一个圆角图片控件`MellowImageView`,用于绘制圆角矩形图片。接着,通过将布局放入`HorizontalScrollView`中,实现了左右滑动功能,并使用`ViewFlipper`添加图片切换动画效果。文章提供了完整的代码示例,包括XML布局、动画文件和Java代码,最终展示了实现效果。此教程适合想了解自定义View和动画效果的开发者。
548 65
Android自定义view之网易云推荐歌单界面
|
XML 前端开发 Android开发
一篇文章带你走近Android自定义view
这是一篇关于Android自定义View的全面教程,涵盖从基础到进阶的知识点。文章首先讲解了自定义View的必要性及简单实现(如通过三个构造函数解决焦点问题),接着深入探讨Canvas绘图、自定义属性设置、动画实现等内容。还提供了具体案例,如跑马灯、折线图、太极图等。此外,文章详细解析了View绘制流程(measure、layout、draw)和事件分发机制。最后延伸至SurfaceView、GLSurfaceView、SVG动画等高级主题,并附带GitHub案例供实践。适合希望深入理解Android自定义View的开发者学习参考。
992 84
|
前端开发 Android开发 UED
讲讲Android为自定义view提供的SurfaceView
本文详细介绍了Android中自定义View时使用SurfaceView的必要性和实现方式。首先分析了在复杂绘制逻辑和高频界面更新场景下,传统View可能引发卡顿的问题,进而引出SurfaceView作为解决方案。文章通过Android官方Demo展示了SurfaceView的基本用法,包括实现`SurfaceHolder.Callback2`接口、与Activity生命周期绑定、子线程中使用`lockCanvas()`和`unlockCanvasAndPost()`方法完成绘图操作。
367 3
|
Android开发 开发者
Android自定义view之围棋动画(化繁为简)
本文介绍了Android自定义View的动画实现,通过两个案例拓展动态效果。第一个案例基于`drawArc`方法实现单次动画,借助布尔值控制动画流程。第二个案例以围棋动画为例,从简单的小球直线运动到双向变速运动,最终实现循环动画效果。代码结构清晰,逻辑简明,展示了如何化繁为简实现复杂动画,帮助读者拓展动态效果设计思路。文末提供完整源码,适合初学者和进阶开发者学习参考。
253 0
Android自定义view之围棋动画(化繁为简)
|
Java Android开发 开发者
Android自定义view之围棋动画
本文详细介绍了在Android中自定义View实现围棋动画的过程。从测量宽高、绘制棋盘背景,到创建固定棋子及动态棋子,最后通过属性动画实现棋子的移动效果。文章还讲解了如何通过自定义属性调整棋子和棋盘的颜色及动画时长,并优化视觉效果,如添加渐变色让白子更明显。最终效果既可作为围棋动画展示,也可用作加载等待动画。代码完整,适合进阶开发者学习参考。
330 0
|
XML 存储 JSON
Android网络与数据存储——网络编程数据处理(网络请求解析Json,解析xml)
Android网络与数据存储——网络编程数据处理(网络请求解析Json,解析xml)
471 0
|
XML Android开发 数据格式
Android 解析AndroidManifest.xml文件
1. 格式解析 1). AndroidManifest.xml文件格式 看雪大神--原图地址 图1.png 图中可以清晰的看出AndroidManifest.
1502 0
|
XML Android开发 数据格式
Android XStream 解析xml数据变成bean,支持CDATA
参考 1、Android 用 XStream 将复杂xml解析为javabean 2、XStream支持CDATA标签 3、Retrofit 用Soap协议访问WebService 详解 实例 留着上一篇retrofit访问webservice后,...
2136 0