原
Android提供了用于构建UI的基础上,基本布局类一个复杂和强大的组件化模式:View和 ViewGroup。首先,该平台包含各种预构建的View和ViewGroup子类 - 分别称为小部件和布局 - 可用于构建UI。
可用的widget的部分名单包括Button, TextView, EditText, ListView, CheckBox, RadioButton, Gallery, Spinner,和多个专用 AutoCompleteTextView, ImageSwitcher和 TextSwitcher。
在现有的布局LinearLayout, FrameLayout,RelativeLayout,等。有关更多示例,请参阅常见布局对象。
如果没有预构建的小部件或布局满足您的需求,您可以创建自己的View子类。如果您只需对现有的窗口小部件或布局进行微调,则可以简单地对窗口小部件或布局进行子类化并覆盖其方法。
创建您自己的View子类可以精确控制屏幕元素的外观和功能。为了让您了解使用自定义视图获得的控制权,以下是您可以对它们执行的一些示例:
您可以创建完全自定义渲染的视图类型,例如使用2D图形渲染的“音量控制”旋钮,其类似于模拟电子控制。
您可以将一组视图组件组合到一个新的单个组件中,也许可以制作类似ComboBox(弹出列表和自由输入文本字段的组合),双窗格选择器控件(带有列表的左窗格和右窗格每个地方你可以重新分配哪个项目在哪个列表中),等等。
您可以覆盖EditText组件在屏幕上呈现的方式( 记事本教程使用它可以很好地创建一个记事本页面)。
您可以捕获按键等其他事件并以某种自定义的方式处理它们(例如游戏)。
下面的部分将介绍如何创建自定义视图并在您的应用程序中使用它们。有关详细的参考信息,请参阅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图形,其他标准或自定义组件,样式文本或任何你能想到的东西。
注意: 这不适用于3D图形。如果你想使用3D图形,你必须扩展SurfaceView 而不是视图,并从一个单独的线程中绘制。有关详细信息,请参阅GLSurfaceViewActivity示例。
onMeasure()是多一点参与。onMeasure() 是组件与其容器之间呈现合约的关键部分。onMeasure()应该被覆盖以有效和精确地报告其包含部分的测量结果。根据父级(传递给onMeasure()方法)的限制要求以及要求setMeasuredDimension()在计算出已计算的宽度和高度后调用该方法的要求,这会稍微复杂一些。如果您未能通过重写的onMeasure()方法调用此方法,则结果将在测量时发生异常。
在很高的层面上,实施onMeasure()看起来像这样:
重写的onMeasure()方法被称为宽度和高度测量规范(widthMeasureSpec和 heightMeasureSpec参数,都是代表尺寸的整数代码),应将其视为对您应该生成的宽度和高度测量的限制的要求。参考文档View.onMeasure(int, int)(参考文档在解释整个测量操作方面做得相当好)中可以找到这些规范要求的那些限制的完整参考。
您的组件的onMeasure()方法应计算渲染组件所需的测量宽度和高度。它应该尽量保持传入的规格,尽管它可以选择超过它们(在这种情况下,父母可以选择做什么,包括剪裁,滚动,抛出异常,或要求onMeasure()再次尝试,也许是不同的测量规格)。
一旦计算宽度和高度,setMeasuredDimension(int width, int height)必须使用计算的测量值调用该方法。不这样做将导致抛出异常。
以下是框架调用视图的一些其他标准方法的摘要:
复合控制
如果您不想创建完全自定义的组件,而是希望将由一组现有控件组成的可重用组件组合在一起,则创建复合组件(或复合控件)可能适合帐单。简而言之,这将更多的原子控制(或视图)汇集到一组可以被视为单一事物的逻辑组中。例如,组合框可以被认为是单行EditText字段和附加PopupList的相邻按钮的组合。如果按下按钮并从列表中选择某项,它将填充EditText字段,但用户也可以直接在EditText中输入某些内容(如果他们喜欢的话)。
在Android中,实际上有两种其他视图可以轻松实现此目的:Spinner而且 AutoCompleteTextView,不管怎样,组合框的概念都是一个易于理解的示例。
要创建复合组件:
通常的出发点是某种布局,所以创建一个扩展布局的类。也许在组合框的情况下,我们可能会使用水平方向的LinearLayout。请记住,其他布局可以嵌套在内部,因此复合组件可以是任意复杂和结构化的。请注意,就像使用Activity一样,您可以使用声明性(基于XML的)方法来创建包含的组件,也可以使用代码将它们嵌套编程。
在新类的构造函数中,接受超类所需的任何参数,并首先将它们传递给超类构造函数。然后,您可以设置其他视图以在新组件中使用; 这是您创建EditText字段和PopupList的位置。请注意,您也可以将自己的属性和参数引入可以由您的构造函数拖出并使用的XML。
您还可以为包含的视图可能生成的事件创建侦听器,例如,用于List Item的侦听器方法单击Listener以在进行列表选择时更新EditText的内容。
您也可以使用访问器和修饰符创建自己的属性,例如,允许在组件中初始设置EditText值,并在需要时查询其内容。
在扩展布局的情况下,您不需要重写 onDraw()和onMeasure()方法,因为布局将具有可能工作得很好的默认行为。但是,如果需要,仍可以覆盖它们。
您可以重写其他on...方法,例如 onKeyDown(),可能在按某个键时从组合框的弹出列表中选择某些默认值。
总而言之,使用布局作为自定义控件的基础具有许多优点,其中包括:
您可以像使用活动屏幕一样使用声明性XML文件指定布局,也可以通过编程创建视图并将它们嵌入到代码中的布局中。
在onDraw()与onMeasure()方法(再加上大部分的其他on...方法)将可能有合适的行为,所以你不必重写它们。
最后,您可以快速构建任意复杂的复合视图,并将它们重用,就好像它们是单个组件一样。
修改现有的视图类型
有一个更简单的选项来创建自定义视图,在某些情况下很有用。如果有一个组件与您想要的非常相似,那么您可以简单地扩展该组件,并覆盖您想要更改的行为。你可以用完全自定义的组件完成所有的事情,但是通过从View层次结构中的更专业化的类开始,你也可以获得许多免费的行为,可能完全是你想要的。
例如, NotePad应用程序演示了使用Android平台的许多方面。其中包括扩展一个EditText视图来制作一个记事本。这不是一个完美的例子,为此做的API可能会改变,但它确实证明了原则。
如果您还没有这样做,请将NotePad样本导入到Android Studio中(或者使用提供的链接查看源代码)。特别要注意的定义 LinedEditText在 NoteEditor.java文件。
这里有一些事情要注意在这个文件中:
定义
该类使用以下行定义:
public static class LinedEditText extends EditText
LinedEditText被定义为NoteEditor 活动内的一个内部类,但是它是公共的,所以 如果需要的话,它可以NoteEditor.LinedEditText从NoteEditor类外部访问 。
这static意味着它不会生成所谓的“合成方法”,允许它从父类访问数据,这意味着它实际上表现为一个单独的类,而不是与强相关的东西NoteEditor。如果它们不需要从外部类访问状态,保持生成的类很小,并允许从其他类轻松使用,则这是创建内部类的更简洁的方法。
它扩展了EditText,这是我们在这种情况下选择定制的视图。当我们完成后,新班级将能够取代普通EditText视图。
类初始化
一如既往,超级被称为第一。此外,这不是默认的构造函数,而是一个参数化的构造函数。当从XML布局文件膨胀时,EditText由这些参数创建,因此,我们的构造函数需要将它们接受并传递给超类构造函数。
重写的方法
此示例仅覆盖一个方法,onDraw()但您可能需要在创建自定义组件时覆盖其他方法。
对于此示例,覆盖该onDraw()方法允许我们在EditText视图画布上绘制蓝色线条(画布被传递到重写的onDraw()方法中)。在方法结束之前调用super.onDraw()方法。应该调用超类方法,在这种情况下,我们在绘制完想要包含的行之后最后执行它。
使用自定义组件
我们现在有我们的自定义组件,但我们如何使用它?在记事本实施例中,定制组件直接从所述声明性布局中使用,所以看一看note_editor.xml在 RES /布局文件夹。
<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标记来引用的,该 标记是用Java编程语言引用内部类的标准方法。
如果您的自定义视图组件未定义为内部类,则可以替代地使用XML元素名称声明视图组件,并排除该class属性。例如:
<com.example.android.notepad.LinedEditText
id="@+id/note"
... />
请注意,LinedEditText该类现在是一个单独的类文件。当这个类嵌套在NoteEditor类中时,这种技术将无法工作。
定义中的其他属性和参数是传递给自定义组件构造函数的参数,然后传递给EditText构造函数,因此它们与您将用于EditText视图的参数相同。请注意,也可以添加您自己的参数,我们将在下面再次介绍这一点。
这就是它的全部。无可否认,这是一个简单的例子,但这就是要点 - 创建自定义组件只是像你需要的那样复杂。
一个更复杂的组件可能会覆盖更多的on...方法,并引入一些自己的帮助方法,实质上可以自定义其属性和行为。唯一的限制是你的想象力和你需要的组件。
联系我
QQ:94297366
微信打赏:https://pan.baidu.com/s/1dSBXk3eFZu3mAMkw3xu9KQ
公众号推荐:
转载于:https://blog.51cto.com/4789781/2135005