Android 提供了一个复杂而强大的组件化模型,用于基于
基本布局类
View
和
ViewGroup
。该平台包含
各种预构建的 View
和 ViewGroup
子类(称为 widget)和
分别用于构建界面。
可用的部分微件包括 Button
、TextView
、EditText
、ListView
、CheckBox
、RadioButton
、Gallery
、Spinner
,以及具有特殊用途的 AutoCompleteTextView
、ImageSwitcher
和 TextSwitcher
。
可用的布局包括
LinearLayout
,
FrameLayout
,
RelativeLayout
,
等。如需查看更多示例,请参阅
常见布局。
如果所有预构建的 widget 或布局都无法满足您的需求,您可以创建自己的
View
子类。如果您只需要对现有 widget 进行小幅调整,或者
您可以为 widget 或布局创建子类并重写其方法。
通过创建自己的 View
子类,您可以精确控制外观和
函数。下面介绍了自定义视图可为您带来的控制力
下面列举了一些示例来说明您可以如何使用它们:
-
您可以创建完全自定义呈现的
View
类型,例如“Volume 对照组”按钮,使用 2D 图形呈现,类似于模拟电子控件。 -
您可以将一组
View
组件组合成一个新的单个组件,例如: 创建类似组合框(弹出列表和自由输入文本字段的组合)、 双窗格选择器控件(一个左右窗格,每个窗格都有一个列表,您可以在其中重新分配 等等。 -
您可以替换
EditText
组件在屏幕上的渲染方式。通过 <ph type="x-smartling-placeholder"></ph> NotePad 示例应用使用此效果很好地创建了一个带线条的记事本页面。 - 您可以捕获其他事件(例如按键),并以自定义方式处理这些事件,例如
以下部分介绍了如何创建自定义视图并在应用中使用它们。对于
请参阅
View
类。
基本方法
下面简要介绍了创建您自己的View
所需了解的事项
组件:
-
使用您自己的类扩展现有的
View
类或子类。 -
替换父类中的某些方法。要替换的父类方法开头
on
- 例如,onDraw()
,onMeasure()
, 和onKeyDown()
。 这类似于以下项目中的on
事件:Activity
或ListActivity
替换生命周期和其他功能钩子。 - 使用您的新扩展类。完成后,您可以使用新的扩展类来代替 所依据的视图
完全自定义的组件
您可以创建完全自定义的图形组件, 。例如,您需要一个看起来像老式模拟量表的图形 VU 计,或者是跟唱文本视图 跟着卡拉 OK 机一起唱歌,这个弹跳的球会随着歌词一起移动。你可能需要 内置组件无法执行的操作,无论你以何种方式组合使用。
幸运的是,您可以创建外观和行为如您所愿的组件,功能仅限于 屏幕大小和可用处理能力 完全由您自己决定 应用可能需要在功耗明显低于桌面系统的情况下运行 工作站。
如需创建完全自定义的组件,请考虑以下事项:
-
您可以扩展的最通用的视图是
View
,因此通常从扩展开始 以便创建新的超级组件。 - 您可以提供一个构造函数,它可以从 XML 中获取属性和参数, 使用您自己的此类属性和参数,例如 VU 计的颜色和范围,或 针的宽度和阻尼
- 您可能需要创建自己的事件监听器、属性访问器和修饰符,以及 在组件类中实现更复杂的行为
-
您几乎肯定需要替换
onMeasure()
,并且还可能需要 如果您希望组件显示内容,请替换onDraw()
。虽然这两种语言都具有 默认行为,默认的onDraw()
不执行任何操作,而默认的onMeasure()
始终会将尺寸设为 100x100,您可能并不希望这样设置。 -
您还可以根据需要替换其他
on
方法。
扩展 onDraw() 和 onMeasure()
onDraw()
方法提供
Canvas
,您可以
实现您想要的任何内容:2D 图形、其他标准或自定义组件、样式文本或
还有其他您能想到的事物吗?
onMeasure()
涉及更多。onMeasure()
至关重要
组件与其容器之间的渲染协定的onMeasure()
必须是
替换后可高效、准确地报告其所含部分的测量结果。这是
而父级的限制要求则稍微复杂一些,后者传递到
onMeasure()
方法,并需要调用
setMeasuredDimension()
方法,并测量相应的宽度和高度。
计算。如果您不通过已替换的 onMeasure()
方法调用此方法,
会导致衡量时出现异常。
概括来讲,实现 onMeasure()
如下所示:
-
使用宽度和高度调用替换的
onMeasure()
方法 这些规范被视为对宽度和高度的限制要求 测量出的测量数据。widthMeasureSpec
和heightMeasureSpec
参数都是表示维度的整数代码。对 相关规范要求的限制,请参阅View.onMeasure(int, int)
本参考文档还介绍了整个测量操作。 -
组件的
onMeasure()
方法会计算测量宽度和高度, 呈现组件所需的资源它必须尽量符合通过的规范 但也可能会超过它们在这种情况下,家长可以选择执行哪些操作,包括 裁剪、滚动、抛出异常或要求onMeasure()
重试; 可能采用不同的衡量规范 -
计算宽度和高度后,调用
setMeasuredDimension(int width, int height)
方法, 测量结果。否则会导致异常。
下面总结了框架对视图调用的其他标准方法:
类别 | 方法 | 说明 |
---|---|---|
创建 | 构造函数 | 有一种构造函数形式,会在从代码创建视图时调用 以及从布局文件膨胀视图时调用的表单。第二种形式 解析和应用布局文件中定义的属性。 |
|
在视图及其所有子项都从 XML 扩充之后调用。 | |
布局 |
|
调用以确定此视图及其所有子级的大小要求。 |
|
在此视图必须为其所有子视图分配大小和位置时调用。 | |
|
在此视图的大小发生更改时调用。 | |
绘制 |
|
在视图必须渲染其内容时调用。 |
事件处理 |
|
在发生按键按下事件时调用。 |
|
在发生 key up 事件时调用 | |
|
在发生轨迹球动作事件时调用。 | |
|
在发生触摸屏动作事件时调用。 | |
专注 |
|
在视图获得或失去焦点时调用。 |
|
在包含视图的窗口获得或失去焦点时调用。 | |
附加 |
|
在视图附加到窗口时调用。 |
|
在视图与其窗口分离时调用。 | |
|
在包含视图的窗口的可见性发生更改时调用。 |
复合控件
如果您不想创建完全自定义的组件,而是希望将
将可重复使用的组件组合在一起,该组件由一组现有控件组成,然后创建一个复合
组件(或复合控件)可能最合适。总而言之,这项变更整合了
原子控件或视图分解为可视为单个项的逻辑组。
例如,组合框可以是单行 EditText
字段的组合
以及一个附有弹出式列表的相邻按钮。如果用户点按按钮并从
列表,它会填充 EditText
字段,但用户也可以输入一些内容
直接导入到 EditText
中。
在 Android 中,还有另外两个视图可用于执行此操作:Spinner
和
AutoCompleteTextView
。无论如何,这个组合框概念都是一个很好的例子。
如需创建复合组件,请执行以下操作:
-
与
Activity
一样,请使用声明式(基于 XML)方法 来创建包含的组件或通过编程方式从代码中嵌套它们。通过 通常从某种类型的Layout
开始,因此请创建一个扩展Layout
。对于组合框,您可以使用LinearLayout
和 横向。你可以在其中嵌套其他布局 任意复杂和结构化。 -
在新类的构造函数中,接受父类所需的任何形参并传递
先传递到父类构造函数。然后,您可以设置其他视图
在新组件中您可以在这里创建
EditText
字段和 弹出式列表。您可以在 构造函数可以提取和使用它们。 -
(可选)为包含的视图可能生成的事件创建监听器。例如
listener 方法,以便更新列表项的点击监听器
如果选择了列表,则为
EditText
。 -
(可选)使用访问器和修饰符创建自己的属性。例如,让
EditText
值最初在组件中设置,并在出现以下情况时查询其内容: 所需的资源。 -
(可选)替换
onDraw()
和onMeasure()
。在以下情况下,通常没有必要这样做: 扩展Layout
,因为布局具有可能正常运行的默认行为。 -
(可选)替换其他
on
方法(如onKeyDown()
),例如选择特定的 在点按某个键时,从组合框弹出式列表中获取默认值。
使用 Layout
作为自定义控件的基础有诸多优势,
包括:
- 您可以使用声明式 XML 文件指定布局,就像使用 activity 屏幕一样, 或者,您可以通过编程方式创建视图,并通过代码将它们嵌套到布局中。
-
onDraw()
和onMeasure()
方法,以及大多数其他方法on
方法具有合适的行为,因此您不必替换它们。 - 您可以快速构建任意复杂的复合视图,并像使用它们一样重复使用它们。 单个组件。
修改现有视图类型
如果存在与您所需的组件类似的组件,您可以扩展该组件并替换
您想要更改的行为。借助完全定制的 Google Cloud 工具,
组件,但通过从 View
层次结构中更专用的类着手,您可以
从而实现免费执行您想要的行为。
例如,
记事本
示例应用演示了使用 Android 平台的多个方面。其中包括扩展了
EditText
视图可创建带线条的记事本。这并非完美的示例,
这样做可能会改变,但体现了原则。
如果您尚未执行此操作,请将记事本示例导入 Android Studio 或查看
来源。请特别留意 LinedEditText
的定义
在
NoteEditor.java
文件。
下面是此文件中的一些注意事项:
-
定义
该类使用以下行进行定义:
public static class LinedEditText extends EditText
LinedEditText
定义为NoteEditor
中的一个内部类 activity,但它是公共 activity,因此可以作为NoteEditor.LinedEditText
进行访问 从NoteEditor
类的外部进行调用。此外,
LinedEditText
为static
,这意味着它不会生成 所谓的“合成方法”访问父类中的数据也就是说, 作为一个单独的类,而不是与NoteEditor
密切相关的类。 如果内部类不需要从 输出。它使生成的类保持较小,并便于其他 类。LinedEditText
扩展了EditText
(即要在其中自定义的视图) 这种情况。完成后,新类可以代替常规EditText
视图。 -
类初始化
与往常一样,首先调用父类。这不是默认构造函数, 参数化一个。
EditText
是使用以下参数创建的: 从 XML 布局文件扩充而来。因此,构造函数需要获取这些对象并将其传递给 父类构造函数。 -
替换的方法
此示例仅替换
onDraw()
方法,但您可能需要替换 您可以自定义其他组件在此示例中,通过替换
onDraw()
方法,您可以在以下位置绘制蓝色线条:EditText
视图画布。画布会被传递到onDraw()
方法结合使用。super.onDraw()
方法会在 方法结束。必须调用父类方法。在本例中,请在末尾 绘制要包含的线条。 -
自定义组件
现在,您已经有了自定义组件,但如何使用它呢?在记事本示例中, 自定义组件直接从声明式布局中使用,因此请查看
note_editor.xml
在res/layout
文件夹:<view xmlns:android="http://schemas.android.com/apk/res/android" class="com.example.android.notepad.NoteEditor$LinedEditText" android:id="@+id/note" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" android:padding="5dp" android:scrollbars="vertical" android:fadingEdge="vertical" android:gravity="top" android:textSize="22sp" android:capitalize="sentences" />
将自定义组件创建为 XML 中的通用视图,并将类指定为 使用完整的软件包。您定义的内部类可使用
NoteEditor$LinedEditText
表示法,这是引用内部 类。如果您的自定义视图组件未定义为内部类,您可以声明该视图 组件的名称,并排除
class
属性。例如:<com.example.android.notepad.LinedEditText id="@+id/note" ... />
请注意,
LinedEditText
类现在是一个单独的类文件。当 类嵌套在NoteEditor
类中,则此方法不起作用。定义中的其他属性和参数是传递给自定义 然后传递到
EditText
构造函数。 它们与您用于EditText
视图的参数相同。可以添加 您自己的参数。
您可以根据自己的需要创建自定义组件。
更复杂的组件可以替换更多的 on
方法,并引入其
自己的辅助方法,从而充分地自定义其属性和行为。唯一的限制是
以及您需要组件执行的操作。