Custom Components(自定义组件)
来源:互联网 发布:微商城怎么查询数据库 编辑:程序博客网 时间:2024/05/17 03:50
概述
安卓为构建你自己的UI提供了一个成熟且强大的自定义模型,基于基本的布局类:
View
和 ViewGroup
. 开始使用它之前,平台包含了许多预先构建好了的view和viewgroup的子类——分别叫做组件(widgets )和布局(layouts )——你可以使用它们来构建你的UI。一部分可用组件清单包括
Button
, TextView
, EditText
, ListView
, CheckBox
,RadioButton
, Gallery
, Spinner和更有特殊用途的
AutoCompleteTextView
,ImageSwitcher
, and TextSwitcher
.可用的布局
LinearLayout
, FrameLayout
, RelativeLayout
,和其它。更多例子请查看 Common Layout Objects.如果这之中没有你所需要的组件或布局,你可以创建你自己的view子类。如果你只需要小范围的调整一个已经存在的组件或布局,你可以简单的继承该组件或布局,并且覆盖它的方法。
创建你自己的view子类让你精确的控制屏幕的外观和功能元素。你在自定义view上给定的一些控制想法,这里有一些例子来说明你可以用他们来做什么:
- 你可以创建一个完整的自定义显示的view类型,例如使用2D绘图显示一个“音量控制”按钮,和类似的模拟电子控制。
- 你可以组合一组view组件成为一个新的单一组件,或许像一个ComboBox (一个组合了浮动列表和自由输入文本框的控件),一个双面选择控制器(dual-pane selector contro,左和右窗格都有一个列表,你可以重新组织哪个item在哪个列表中),等等。
- 你可以通过覆盖的方法让一个EditText组件呈现在屏幕上( Notepad Tutorial 是该方法的一个成功案例,创建了一个线性的记事本页)。
- 你可以捕获其它事件并且用一下自定义方法来处理他们(如游戏一样)
接下去的章节展示了如何创建自定义view 并且在你的app中使用它们。更多有用的消息,请查看
View
类中的介绍。基本方法( Basic Approach)
这你是一个抽象的概述,在开始创建视图组件时你需要了解的东西:
为你自己的类继承一个已经存在的view类或者子类
覆盖一下父类的方法。父类可覆盖的方法以"on "开头,例如,
onDraw()
, onMeasure()
, 和onKeyDown()
. 这与在Activity
或 ListActivity中的
on...事件相似,你可以覆盖它的生命周期和其它的功能钩子。使用你新继承的类。一旦完成,你新继承的类可以被用来替代基类的view 。
技巧:扩展类可以作为一个activity 中的内部类被定义并且使用它。这是很有用的,因为它控制访问权限,但是不是必须的(或许你想为你的应用创建一个公共的view)
完全的自定义控件(Fully Customized Components)
完全自定义控件可创建你希望如何显示的生动的组件。或许一个图形音量表( graphical VU meter)看起来像一个老式的模拟仪表,或者一个一起唱歌的长文本视图(sing-a-long text view),当一个光标沿着歌词移动时你可以跟着卡拉ok机器一起唱。无论哪种方式,都是让你内置组件做他不会做的事,不论你是怎么组合他们的。
幸运的是,你可以很容易的以任何方式创建一个你喜欢的外观和行为的组件。限制它的或许仅仅只有你的想象力,屏幕的大小和可用的处理能力(记住,你的应用最终或许运行在一些低性能的平台上)
为创建一个完全的自定义控件:
- 你可以继承的最平常的类,view,这样你通常会以继承该类来创建你的新的上级组件开始。
- 你可以提供一个构造器,该构造器可以从xml文件中取得属性和参数,并且你可以使用你自定义的属性和参数(也许是声量器的颜色和范围,或者是宽度和针的电阻,等等)
- 你或许想要在你的自定义类中创建你自己的事件监听者,属性访问器和修改器,和更多成熟的行为。
- 如果你想要这个组件显示一些什么东西,你几乎肯定想覆盖onMeasure() 和onDraw()。 当这些都没有被覆盖时,默认的
onDraw()
将不什么都不做,默认的onMeasure() 将大小设置为100*100——这可能不是你想要的。 - 其它on...方法可以在需要时被覆盖
Extend onDraw()
and onMeasure()
onDraw() method 方法传递了你的Canvas(画布),该画布可以实现任何你想要的:2D绘图,其它标准或者自定义控件,字体样式,或者任何你能想到的东西。
注:它不支持3D绘图,如果你想使用3Dh绘图,你必须继承SurfaceView来代替view,并且使用单独的线程来进行绘制操作。查看GLSurfaceViewActivity 示例获取更多信息
onMeasure() 稍微复杂一些。
onMeasure()
是你的组件呈现在容器上的关键。onMeasure()
应该被覆盖用来提高效率并且提供准确的测量值。这是一个来自它父视图的稍微复杂的需求限制(该父视图通过onMeasure()方法传递了过来)并且 一旦计算完成 便会根据需求调用 含有测量的宽度和高度的setMeasuredDimension()
方法。如果你不在onMeasure() 方法中调用该方法,结果将会在运行时抛出错误(exception)。概括的说,实现onMeasure() 方法会看起来像这样:
- 覆盖的onMeasure() 方法被调用时需传递宽度和高度两个测量规范(
widthMeasureSpec
和heightMeasureSpec
参数,两个都是int 类型来表示尺寸 dp)它应该被当作限制你测量的宽度和高度的要求来对待。一个完整的参考这些规范需要的限制能够在View.onMeasure(int, int)引用文档中找到(该文档很好的说明了整个测量操作流程) - 你组件的onMeasure() method 方法应该计算测量的宽度和高度值,这两个值将会被要求给予该组件。它应该试图保持在传入的规范之中,尽管可以选择超过规范(在该案例中,父视图可以选择这样做,包括裁剪,卷动,抛出一个错误或者请求再次调用
onMeasure(),或许有不同的测量规范
)。 - 一旦宽度和高度被计算出来,setMeasuredDimension(int width, int height) 方法一定会被调用,并且传递计算出来的测量值。如果不这么做将会抛出一个错误。
这里总结了一些框架在view 中调用的一些标准方法:
onFinishInflate()
Called after a view and all of its children has been inflated from XML.LayoutonMeasure(int, int)
在确定view及其所有子节点的大小时 调用onLayout(boolean, int, int, int, int)
当view需要为其所用的子节点分配位置和大小时 调用onSizeChanged(int, int, int, int)
当view的大小改变时 调用DrawingonDraw(android.graphics.Canvas)
当view需要绘制其内容时 调用Event processingonKeyDown(int, KeyEvent)
当新的按键按下事件发生时 调用onKeyUp(int, KeyEvent)
当按键弹起事件发生时 调用onTrackballEvent(MotionEvent)
当轨迹球移动事件发生 调用onTouchEvent(MotionEvent)
当屏幕点击事件发生 调用FocusonFocusChanged(boolean, int, android.graphics.Rect)
当view获得或失去焦点时 调用onWindowFocusChanged(boolean)
当包含view的window获得或失去焦点时 调用AttachingonAttachedToWindow()
当view附加到window上时 调用onDetachedFromWindow()
当view从window上分离时 调用onWindowVisibilityChanged(int)
当包含view的window的可见性改变时 调用一个自定义view的例子
在 API Demos 中提供了一个自定义的视图。该视图定义为一个LabelView 类。
该LabelView 示例作为一个自定义组件展示了一些不同的方面:
- 继承自view类
- 参数化构造器可以拿到view展开时的参数(定义在xml文件中的参数)。一些参数v传递了进来并且给了父view ,但是更重要的是,这里有一些自定义的属性并且在labelview中使用了。
- 你希望看到一个标签组件的标准公共方法类型,例如
setText()
,setTextSize()
,setTextColor()之类的。
- 一个被覆盖的
onMeasure
方法用来决定和设置呈现出来的组件大小。(注意,在该例子中,真正工作的是私有的measureWidth()方法) - 一个被覆盖的onDraw() 方法 来在提供的画布上绘制标签
你可以看到一些使用示例,在labelview 的custom_view_1.xml 中。另外,你可以看到一个混合使用了
android:
命名空间参数和自定义的app: 命名空间参数。这些app:
参数是自定义的仅被LableView 识别和起作用的,它在样式(styleable )内部类 中被定义,该内部类 在R.resources 中定义。复合组件(Compound Controls )
如果你不希望创建一个完全的自定义控件,而是希望放在一起。一个 由一组现有的控件组成一个可用组件,然后创建一个混合组件(Compound Component or Compound Control)或许适合你的要求。在一个极小容器中,汇集了更多的原始控件(或者视图)到一个逻辑上的项目组(group of items),该组可作为一个单一事物来对待。例如,一个组合框(Combo Box)可以被看作是一个简单的线性Edittext和一个相邻的按钮贴在一个弹出列表(PopupList)上。如果你按下按钮并且从列表中选择一些东西,它填充到Edittext 字段中,但是用户仍然可以直接在Edittext中输入东西。
在安卓中,实际上有两个view可以实现这一事情:
Spinner
和AutoCompleteTextView,
但是不管怎样,组合框的概念是一个易于理解的示例。为创建一个组合控件:
- 通过从某种类型的布局(Layout)开始,这样,继承一个layout创建一个类。或许在组合框的案例中我们或许使用了水平的线性布局。记住,其它布局可以被嵌套在里面,因此该组合控件可以任意的组合和构造。就像用activity一样,你可以使用声明(基于xml)来创建组件,或者在代码中嵌套它。
- 在新类的构造器中,获取父类期望的任何参数,并且首先通过父类的构造器将其传递过去。然后你可以在你新的构件中建立其它视图;这就是你创建edittext和popuplist 的地方。注意,你或许需要引入你自己的属性和参数到xml中,这些属性和参数可以在别处使用 并且被你的构造器使用。
- 你也可以为你的view可能发生的事件创建监听者,例如,为一个列表项点击(List Item Click )创建一个监听者来更新edittext 的内容。
- 你或许需要创建你自己的属性的存取器和修改器 ,例如,允许edittext 值可以被设置初始值并且在需要时查询内容。
- 继承一个layout 时,你不需要覆盖
onDraw()
和onMeasure()
方法,因为布局会有默认的行为或许会工作得很好。然而,你仍然可以在需要的时候覆盖他们 - 你或许会覆盖其它on...方法,例如onKeyDown(),或许时从该组合框的popup list 中选择一个确定的值,当一个确切的按钮被按下时
综上所述,使用layout 作为组合控件的基础有如下优点:
- 你可以在声明性的xml文件中使用它,就像使用一个activity屏幕一样,或者用代码创建一个视图并且将其嵌套进布局中。
onDraw()
和onMeasure()
方法(加上其他的on...方法)将会有适当的行为,因此你不需要覆盖他们。- 最后,你可以十分快速的构建组合控件视图,并且作为一个单一控件重用他们
组合控件实例
在API Demo 工程中,有两个列表示例——在Views/Lists之下的Example 4 and Example 6 展示了一个SpeechView ,它继承自 LinearLayout来组合展示了Speech 引用。在示例代码中的对应代码是
List4.java
和List6.java
.更改一个已经存在的视图类型
这是一个创建自定义布局的更为简单的选择,如果有一个与你想要的组件十分相似的组件,你可以直接继承它并且覆盖你想要改变的行为。在完全的自定义控件中,你可以做你任何想做的事情,但是通过直接继承一个指定类开始的方法中,你可以获取到很多行为但或许都不是你想要的。
例如,SDK中的NotePad application 案例。这展示了许多使用安卓平台的许多方面,其中的一个是继承一个Edittext 视图来构造一个线性记事本。这并非一个完美的示例,在早期的api上运行可能会看起来有所不同,但它确实展示了原理。
如果你还没有这么做,将这个按钮添加到Eclipse (或者直接使用记事本查看源码)。尤其要注意 NoteEditor.java 文件中的MyEditText定义。
需要注意的一些点
1.定义
该类是这么定义的:
public static class MyEditText extends EditText
- 它作为NoteEditor activity 的内部类被定义的,但是它是public 这样可以使用NoteEditor.MyEditText从NoteEditor类的外部被访问到。
- 它是static 意味着它不会产生所谓的“合成方法”来允许它从父类中存取数据,这也叫意味着它是作为一个独立的类而不是依赖于
NoteEditor
。
这是一个简洁的方法来创建内部类,如果它不需要从外部类中获取数据。使生成的类更小,并且允许在其它类中更易使用。 - 它继承自
EditText
,这是在该案例中我们选择的来进行自定义的view.当我们完成时,这个新的类将可作为传统EditText
,视图的替代品。
2. 类的初始化
同往常一样,首先调用父类。此外,这不是默认的构造函数,但是一个参数化的。该Edittext 使用这些参数被创建,这些参数来自于xml布局文件,至此,我们的构造器需要获取并且将它们传递给父类的构造器。
3.覆盖方法
在该案例中,只有一个方法被覆盖了:onDraw()—but 但这样很容易被误认为是创建一个你自己的自定义控件。
对于NotePad 案例,覆盖
onDraw()
方法允许我们在Editext 视图画布上绘制蓝色的线条(该画布通过onDraw()
方法传递了过来)。super.onDraw() 方法在该方法的最后被调用。父类方法应该被调用,但是在该案例中,我们在绘制了线条之后才这么做。4.使用该自定义控件
现在,我们有了自己的自定义控件,但是如何去使用他呢?在NotePad 案例中,该自定义控件直接在布局文件中使用,因此看一看res/layout文件夹下的note_editor.xml:
<view
class="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文件中被创建,并且它的class 使用了具体的全部包名。注意我们定义的内部类是使用如下形式引用的NoteEditor$MyEditText ,该标记是在java语言中引用内部类的标准方法。
如果你的自定义视图没有作为内部类定义,你可以选择如下两项,在xml元素名中声明该控件的名称,或者包含class 属性在该属性中指明:
<com.android.notepad.MyEditText
id="@+id/note"
... />
注意,现在的MyEditText 是一个独立的类。当该类嵌套在NoteEditor 类中时,这样做是无效的。
其它的属性和参数都会传递到该自定义组件的构造函数中,之后传递给EditText的构造器,因此它和你使用EditText视图时有着相似的参数。注意,可以添加你自己的参数,并且将会在下面提及。
这就是所有的关于如何自定义控件的方法。不可否认这是一个简单的情况,但重点是——创建自定义组件只需要这么复杂。
一个更加成熟的组件或许会覆盖更多的on...事件并且引入一些自己的帮助类,大体上,自定义它的属性和行为。唯一限制你的就是你的想象力和你期望该组件要做什么。
0 0
- Custom Components(自定义组件)
- Building Custom Components/建立自定义组件
- 创建自定义组件Building Custom Components
- Building Custom Components/建立自定义组件
- Custom Components「自定义组件」翻译
- Android API——自定义组件(Custom Components)
- Custom Components
- Custom Components
- Custom Components
- vue自定义公共组件components
- Android 用户界面---定制组件(Custom Components)(一)
- Android 用户界面---定制组件(Custom Components)(二)
- Build custom components
- Building Custom Components
- 定制控件Custom Components
- Android - Custom Components
- Extjs4 官方文档翻译系列二:组件(components)、自定义组件
- Android学习笔记————初识控件自定义(Custom Components)
- Linux常用命令
- matlab读取视频VideoReader类
- socket06---僵尸进程的避免
- ffmpeg结构体以及函数介绍(二)
- iOS 双击tableView回顶部
- Custom Components(自定义组件)
- css3总结
- 实习记录(四)
- ffmpeg结构体以及函数介绍(三)
- Swift编程基础之输出数组中最大值与其下标问题
- boost::ptr_vector
- 如何安全退出已调用多个 Activity 的 Application?
- 自定义可水平滚动的View
- Android Studio Execution failed for task ':app:transformClassesWithInstantRunForDebug'