自定义视图一:扩展现有的视图,添加新的XML属性
这个系列是老外写的,干货!翻译出来一起学习。如有不妥,不吝赐教! 简介这个系列详细的介绍了如何穿件Android自定义视图。主要涉及的内容有如何绘制内容,layout和measure的原理,如何继承实现view group以及如何给其子视图添加动画。第一篇主要讲述如何扩展和使用现有的视图,以及如何添加特有的XML属性。 特定的任务使用特定的视图Android提供的view都是比较通用的,哪里都可以用。但是在开发应用的过程中需要对这些通用的view加以修改。很多时候这些代码都添加到了Activity中,这样是的Activity的代码杂乱,影响维护。 假设你在开发一个最用用户训练数据的应用。比如用户的总运动时长,总运动距离以及不同的运动类型等。为了友好的把数据展现给用户,你需要根据用户运动的时间长度做不同的处理。比如他运动了2378秒,那么显示的肯定是48分钟。18550秒,那显示的肯定是5小时9分钟。 创建一个自定义视图处理上面的问题最好就是定义一个view。这个view里包含了处理上面时间的功能。我们来创建一个自定义view: class DurationTextView : TextView { constructor(context: Context,attributeSet: AttributeSet) : super(context,attributeSet) { } }
<demo.customview.customviewdemo.Views.DurationTextView android:id="@+id/duration_view" android:layout_width="match_parent" android:layout_height="wrap_content" />
注意,这里需要给出自定义视图的全名称。 添加展示逻辑现在这个视图和标准的 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"
}
这个方法接受一个 用起来现在就可以试试效果了。在Activity的 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>
我们声明了一个名称为TemplateTextView的declare-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)后在 现在就需要我们在代码里读取并应用新添加的属性值了。首先添加一个 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()
第一行使用了
但是有一点需要格外注意:不管有没有获取到属性值,都要回收TypedArray对象, 上下两个分别设定了不同的template,中间的不设定,运行一下看看修改后的效果如何: 对于大多数的Android视图XML属性都有对应的方法来通过代码的方式设置对应的值。对于自定义视图是否需要这么做,主要取决于你打算怎么用。添加一个方法也没什么问题。 下一篇主要简述如何绘制视图的内容,并自定义一个显示折线图的视图。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |