【Android】Android自定义组件

自定义组件

Android提供了一个复杂而强大的组件化模型,用于构建你的UI,基于基本的布局类:View和ViewGroup。 首先,平台包括各种预构建的View和ViewGroup子类(分别称为widget和layout),你可以使用它们来构建UI。

可用小部件的部分列表包括Button,TextView,EditText,ListView,CheckBox,RadioButton,Gallery,Spinner和更专用的AutoCompleteTextView,ImageSwitcher和TextSwitcher。可用的布局包括LinearLayout,FrameLayout,RelativeLayout等等。

如果没有预构建的widget或layout满足你的需要,你可以创建你自己的View子类。 如果只需要对现有的widget或layout进行小的调整,则可以简单地子类化窗口小部件或布局并覆盖其方法。

创建自己的View子类可以精确控制屏幕元素的外观和功能。 为了了解你通过自定义视图获得的控件,下面是一些你可以使用它们的例子:

  • 你可以创建完全自定义的视图类型,例如使用2D图形渲染的“音量控制”旋钮,类似于模拟电子控制。

  • 您可以将一组View组件组合成一个新的单个组件,也许可以做一些类似ComboBox(弹出列表和自由输入文本字段的组合),双窗格选择器控件(左窗格和右窗格列表 每个都可以重新分配哪个项目在哪个列表中),等等。

  • 你可以重写一个EditText组件在屏幕上的呈现方式(记事本教程使用这个很好的效果,创建一个内衬记事本页面)。

  • 你可以捕获其他事件,如按键,并以某种自定义方式处理它们(如游戏)。

基本方法


以下是开始创建自己的View组件时需要了解的内容的概述:

  • 使用你自己的类扩展现有的View类或子类。

  • 覆盖超类中的一些方法。 超类方法覆盖以“on”开始,例如onDraw(),onMeasure()和onKeyDown()。 这类似于Activity或ListActivity中的on …事件,为生命周期和其他功能而覆盖。

  • 使用你的新扩展类。 一旦完成,你的新扩展类可以用来代替它所基于的视图。
    提示:扩展类可以在使用它们的activity中定义为内部类,这样能控制对它们的访问,但不是必需的(也许你想创建一个新的公共视图在你的应用程序中更广泛使用)。

完全自定义控件


完全定制的组件可用于创建你希望出现的图形组件。也许一个图形VU表看起来像一个老模拟仪表,或一个长一长的文本视图,弹跳球沿着字移动,所以你可以一起唱卡拉OK机。无论如何,你想要的东西,内置组件不会做,无论你如何组合它们。

幸运的是,你可以轻松地创建组件,外观和行为是任何你喜欢的方式,可能只是由你的想象力,屏幕的大小和可用的处理能力(记住,最终你的应用程序可能必须运行在一些明显较少电源比桌面工作站)。

要创建完全自定义的组件:

  • 你可以扩展的最通用的视图,不必要的,View,所以你通常会开始扩展这个创建你的新的超级组件。

  • 您可以提供一个构造函数,它可以从XML中获取属性和参数,也可以使用自己的属性和参数(可能是VU表的颜色和范围,或针的宽度和阻尼等)

  • 你可能想要创建自己的事件监听器,属性访问器和修饰符,以及可能在你的组件类中更复杂的行为。

  • 你几乎肯定想要覆盖onMeasure(),并且也可能需要重写onDraw()如果你想让组件显示的东西。虽然两者都有默认行为,默认onDraw()将不会做任何事情,默认onMeasure()将始终设置100x100的大小 - 这可能不是你想要的。

  • 其他on …方法也可以根据需要重写。

扩展onDraw()和onMeasure()

onDraw()方法为你提供了一个Canvas,你可以在其上实现任何想要的:2D图形,其他标准或自定义组件,样式文本或任何其他你可以想到的。

注意:这不适用于3D图形。 如果要使用3D图形,则必须扩展SurfaceView而不是View,并从单独的线程中绘制。

onMeasure()是一个更多的参与者。 onMeasure()是你的组件和它的容器之间的一个关键的渲染契约。 onMeasure()应该被覆盖,以有效和准确地报告其包含的部分的测量。 这通过来自父代(其被传递到onMeasure()方法)的限制的要求以及通过在计算出已测量的宽度和高度之后调用setMeasuredDimension()方法的要求而略微更复杂。 如果无法从重写的onMeasure()方法调用此方法,则结果将在测量时是异常。

在高级别,实现onMeasure()看起来像这样:

  • 覆盖的onMeasure()方法使用宽度和高度测量规范(widthMeasureSpec和heightMeasureSpec参数,均为表示尺寸的整数代码)进行调用,应被视为对你应该生成的宽度和高度测量的限制的要求。有关这些规范可能需要的限制类型的完整参考可以在View.onMeasure(int,int)下的参考文档中找到(本参考文档也很好地解释了整个测量操作)。

  • 组件的onMeasure()方法应该计算渲染组件所需的测量宽度和高度。它应该尽量保持在传入的规范,虽然它可以选择超过它们(在这种情况下,父代可以选择做什么,包括剪切,滚动,抛出异常,或要求onMeasure()再试一次,可能具有不同的测量规格)。

  • 计算宽度和高度后,必须使用计算的度量调用setMeasuredDimension(int width,int height)方法。不这样做将导致抛出异常。

自定义视图示例

API演示中的CustomView示例提供了自定义视图的示例。自定义视图在LabelView类中定义。

LabelView示例演示了自定义组件的许多不同方面:

  • 扩展完全自定义组件的View类。

  • 参数化构造函数接受视图膨胀参数(XML中定义的参数)。其中一些传递到View超类,但更重要的是,有一些自定义属性定义和用于LabelView。

  • 你希望看到的标签组件的类型的标准公共方法,例如setText(),setTextSize(),setTextColor()等。

  • 重写的onMeasure方法来确定和设置组件的渲染大小。 (注意,在LabelView中,真正的工作是通过一个私有的measureWidth()方法完成的。)

  • 覆盖的onDraw()方法将标签绘制到所提供的画布上。

你可以在样本中的custom_view_1.xml中查看LabelView自定义视图的一些示例用法。特别是,你可以看到android:namespace参数和自定义app:命名空间参数的混合。这些app:参数是LabelView识别和使用的自定义类,并且在样本R资源定义类中的可内部类中定义。

复合控件


如果不想创建一个完全自定义的组件,而是想将一组可重用的组件组成一组现有的控件,则创建一个复合组件(或复合控件)可能符合要求。简而言之,这将一些更多的控件(或视图)合并成一个逻辑组的项目,可以被视为一件事。例如,组合框可以被认为是单行EditText字段和具有附加的PopupList的相邻按钮的组合。如果按下按钮并从列表中选择某个内容,它将填充EditText字段,但如果用户喜欢,也可以直接在EditText中键入内容。

在Android中,实际上有两个其他视图可以做到这一点:Spinner和AutoCompleteTextView,但不管怎样,Combo Box的概念是一个容易理解的例子。

创建复合组件:

  • 通常的起点是某种布局,因此创建一个扩展布局的类。也许在组合框的情况下,我们可能使用具有水平方向的LinearLayout。请记住,其他布局可以嵌套在内部,因此复合组件可以任意复杂和结构化。请注意,就像Activity一样,你可以使用声明式(基于XML)方法创建包含的组件,也可以从代码中以编程方式嵌套它们。

  • 在新类的构造函数中,采用超类期望的任何参数,并将它们传递给超类构造函数。然后,你可以设置其他视图以在新组件中使用;这里是创建EditText字段和PopupList的地方。请注意,你也可以在XML中引入自己的属性和参数,你可以将它们拉出并由构造函数使用。

  • 你还可以为包含的视图可能生成的事件创建监听器,例如,如果执行列表选择,则列表项单击监听器的监听器方法将更新EditText的内容。

  • 你还可以使用访问器和修饰符创建自己的属性,例如,允许在组件中初始设置EditText值,并在需要时查询其内容。

  • 在扩展布局的情况下,您不需要覆盖onDraw()和onMeasure()方法,因为布局将具有可能工作正常的默认行为。但是,如果需要,你仍然可以覆盖它们。
    你可以覆盖其他on …方法,如onKeyDown(),以便在按下某个键时从组合框的弹出列表中选择某些默认值。

总而言之,使用布局作为自定义控件的基础具有许多优点,包括:

  • 你可以像使用活动屏幕一样使用声明性XML文件来指定布局,也可以通过编程方式创建视图,并从代码中将它们嵌入到布局中。

  • onDraw()和onMeasure()方法(加上大多数其他on …方法)可能有合适的行为,所以你不必重写它们。

  • 最后,你可以非常快速地构造任意复杂的复合视图,并重新使用它们,就像它们是单个组件一样。

复合控制的示例

在SDK附带的API Demo项目中,有两个List示例 - 示例4和示例6在视图/列表下演示了一个SpeechView,它扩展了LinearLayout以创建一个用于显示语音引号的组件。示例代码中的相应类为List4.java和List6.java。

修改现有视图类型


有一个更容易的选项创建自定义视图在某些情况下是有用的。如果有一个组件已经非常类似于你想要的,你可以简单地扩展该组件,只是覆盖你想改变的行为。你可以使用完全自定义的组件做所有的事情,但是从View层次结构中更专门的类开始,你还可以免费获得很多可能完全符合你想要的行为。

例如,SDK在示例中包括NotePad应用程序。这展示了使用Android平台的许多方面,其中包括扩展EditText视图,以制作一个内衬的记事本。这不是一个完美的例子,这样做的API可能改变从这个早期预览,但它确实展示原则。

如果您还没有这样做,请将NotePad示例导入Android Studio(或者使用提供的链接查看源代码)。特别看看NoteEditor.java文件中MyEditText的定义。

这里有一些要点

  1. 定义
    类像下面这行定义:
    public static class MyEditText extends EditText

    • 它被定义为NoteEditor活动内的一个内部类,但它是公共的,因此,如果需要,它可以作为NoteEditor.MyEditText从NoteEditor类的外部访问。

    • 它是静态的,意味着它不会生成所谓的“合成方法”,允许它从父类访问数据,这反过来意味着它真的表现为一个单独的类,而不是与NoteEditor强烈相关的东西。这是一个更清洁的方法来创建内部类,如果他们不需要访问外部类的状态,保持生成的类小,并允许它很容易从其他类使用。

    • 它扩展了EditText,这是我们在这种情况下选择自定义的视图。当我们完成后,新类将能够替换正常的EditText视图。

  2. 类初始化
    和往常一样,超类是首先考虑的。此外,这不是默认构造函数,而是参数化的构造函数。 EditText是从XML布局文件扩充时使用这些参数创建的,因此,我们的构造函数需要同时接受它们并将它们传递给超类构造函数。

  3. 重写方法
    在此示例中,只有一个方法要覆盖:onDraw() - 但是当您创建自己的自定义组件时,可能很容易需要其他方法。
    对于NotePad示例,覆盖onDraw()方法允许我们在EditText视图画布上绘制蓝线(画布被传递到覆盖的onDraw()方法中)。在方法结束之前调用super.onDraw()方法。应该调用超类方法,但是在这种情况下,我们在绘制要包括的行之后在结尾处进行。

  4. 使用自定义组件
    我们现在有了我们的自定义组件,但是我们如何使用它呢?在NotePad示例中,自定义组件直接从声明布局使用,因此请查看res / layout文件夹中的note_editor.xml。

    "com.android.notepad.NoteEditor$MyEditText"
    id="@+id/note"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:drawable/empty"
    android:padding="10dip"
    android:scrollbars="vertical"
    android:fadingEdge="vertical" />
    • 自定义组件在XML中创建为通用视图,并且使用完整包指定类。 还要注意,我们定义的内部类是使用NoteEditor $ MyEditText标记引用的,这是一种标准的方式来引用Java编程语言中的内部类。
      如果你的自定义View组件未定义为内部类,那么你也可以使用XML元素名称声明View组件,并排除类属性。 例如:
      "@+id/note"
      ... />

          注意,MyEditText类现在是一个单独的类文件。 当类嵌套在NoteEditor类中时,此技术将不起作用。

    • 定义中的其他属性和参数是传递到自定义组件构造函数中的属性和参数,然后传递给EditText构造函数,因此它们与你用于EditText视图的参数相同。 注意,也可以添加你自己的参数,我们将在下面再次涉及。

这就是它的所有。 不可否认,这是一个简单的情况,但这是重点 - 创建自定义组件只是那么复杂,因为你需要它。

一个更复杂的组件可以覆盖更多的on方法,并引入一些自己的帮助方法,基本上定制其属性和行为。 唯一的限制是你的想象力和你需要组件做什么。

你可能感兴趣的:(Android)