基于基本布局类:View和ViewGroup,android提供了一个先进而又强大的组件模型,方便你构建UI。首先,该平台预制了很多View 和ViewGroup的子类——就是那些widget和Layout,你可以用这些预制的子类构建你的UI。

可用widgets比如有ButtonTextView,EditTextListViewCheckBoxRadioButtonGallerySpinner, 具有特定用途的有AutoCompleteTextViewImageSwitcher, 和TextSwitcher.

可用的布局有LinearLayoutFrameLayoutRelativeLayout等等,Common Layout Objects章节有更多的示例。

如果这些预制的widget或Layout类都不能满足你的需求,你可以创建自己的View子类。如果你仅仅需要对已有的wigget或者Layout做些微调,那么你简单的继承这个widget或者布局类并覆写它的方法就可以了。

创建自己的View子类可以让你对屏幕中元素的外观和功能进行精确的控制。你可以参照下面的示例,这些示例对你自定义View有一些建议:

  • 你可以创建一个完全自定义绘制的View,例如用2D渲染一个音量控制按钮,绘制出外观像模拟电子控制的按钮。
  • 你可以把多个View组合为一个全新的单个View,比如做出一个像组合框的View(一个弹出列表和文字输入框的结合体),或者是一个双重选择控制器(左右两边都有一个列表,你可以重新分配列表中的item在哪个列表中),等等……
  • 你可以覆写EditText组件在屏幕上绘制的方法(Notepad Tutorial教程就是用这种方法创建了一个有条纹效果的页面)。
  • 你可以捕获更多的事件,例如key presses,并用你自定义的方法来处理这个事件(比如在游戏设计中)。

下面的部分是展开介绍如何创建一个自定义View,如何用在你的程序用使用这些自定义View。参看View类以获取更多的详细信息。

The Basic Approach

下面是对如何创建自己的View组件的一个简要概括:

  1. 创建自己的类,让它继承一个既有的View类或其子类
  2. 覆写父类的某些方法。被覆写的方法都以“on”开头,例如,onDraw()onMeasure(), 和onKeyDown().这和你处理生命周期时覆写Activity或者ListAtivity的onXXX方法或者其它回调方法一样。
  3. 使用这新的扩展类。这些完成后,你这个新的类就可以用在其父类出现的任何地方。

Tip:子类可以作为内部类定义在使用它的Activity类里面。这有利于控制外部对它们的访问,但是并不是一定要这么干(或许你想创建一个public View,可以再你的APP中广泛使用它)。

Fully Customized Components

完全自定义控件可以创建出你想要的图形。或许是一个像老式模拟仪表的音量显示器,或者是一个伴唱字幕,上面有一个跟随字幕文字移动的球便于你通过卡拉OK机伴唱。也就是说无论你怎么组合内置的那些控件都无法满足你的要求。

还好,你可以很容易地创建出你想要的控件,你可以控制它的外观和行为,这只受限于你的思维、屏幕的尺寸、可用电量(要知道,你的程序最终要在电量比桌面电脑少的多的设备上运行)。

要完全创建一个自定义控件:

  1. 毫无疑问,你最可能继承的类就是View,所以通常需要从继承这个类来开始创建你那牛B的控件。
  2. 你要提供一个能从XML文件获取属性和参数的构造函数,并且你也要使用这些属性和参数(或许是颜色和音量仪表所占的空间,或者是指针的宽度和振幅,等等……)
  3. 也许你还要创建自己的时间监听器,属性访问器和修改器,或许你的控件中还有更多复杂的操作。
  4. 你很可能要去覆写onMeasure(),如果想让你的控件显示一些东西,同样要覆写onDraw() 。虽然这两个方法都有缺省操作,但是缺省onDraw什么都不干,缺省onMeasure()通常设置View的Size为你不想要的100×100大小。
  5. 如果需要,你还要覆写其它onXXX()方法。

Extend onDraw() and onMeasure()

这个onDraw()方法传进一个Canvas参数,你可以在它上面实现任何你想要的2D图形,还有标准的或者自定义的控件(译注:这里指标准图形:直线、点圆……和自定义图形:利用标准图形或者图片绘制自己想要的图形),有样式的文本,或者你能想的到的任何东西。

注意:这并不适用于3D图形绘制。你如果你想绘制3D图形,你必须继承SurfaceView类而不是View类,而且在一个单独的线程中进行绘制动作。详情参看GLSurfaceViewActivity示例。

onMeasure()方法用的多一点。onMeasure()方法是子控件与其父控件之间绘制规则的关键环节。应该覆写onMeasure()以高效、精确的报告它所占用的尺寸。这有点小复杂,因为父控件会对子控件有一个限制(作为onMeasure的参数传递进来的),并且一旦计算好measured width和measured height后,必须调用setMeasuredDimension()方法,如果你在覆写onMeasure()方法的时候没有调用这个方法,就会在测量过程中抛出一个异常。

简而言之,执行onMeasure()的过程如下:

  1. 调用被覆写的onMeasure()方法,并用宽度和高度的测量限制条件(就是widthMeasureSpec和 heightMeasureSpec这两个参数,它们都是代表测量尺寸的限制条件的整形编码)作为参数传入,它们都是对你计算measuredWidth和measuredHeight的限制条件,可用限制条件种类的完整说明在View.onMeasure(int,int)的说明文档中(该文档还对整个测量过程做出了非常好的描述)。
  2. 你的控件的onMeasure()方法要预测出一个测量宽度和测量高度,这两个尺寸将用于绘制这个控件。尽管它可以选择无视测量限制条件(在这种情况下,父控件有权选择如何做,包括裁剪,滚动,抛出异常或者再次调用该onMeasure()方法),但是测量值最好符合传入的限制条件。
  3. 一旦计算出宽和高,必须调用setMeasuredDimension(int width,int height),并传入测量结果。否则将会抛出异常。

下面是View中一些标准方法的摘要,这些方法都会被系统框架调用:

种类 方法 描述
构造 构造函数

一种构造函数是在从代码里创建View时被调用,另一种是从一个布局文件中inflate视图时被调用。第二种应该解析并运用任何定义在布局文件中的属性。

onFinishInflate() 一个View及其子View被inflated后,就调用此方法。
布局 onMeasure(int, int) 调用该方法来计算该View及其子View的尺寸需求。
onLayout(boolean, int, int, int, int) 当该View给它的所有子View分配大小和位置时调用该方法。
onSizeChanged(int, int, int, int) 当该View的大小发生改变后调用该方法。
绘制 onDraw(Canvas) 当该View绘制其内容时调用该方法。
事件处理 onKeyDown(int, KeyEvent) 当有新的按键事件时调用该方法。
onKeyUp(int, KeyEvent) 当有按键释放事件时调用该方法。
onTrackballEvent(MotionEvent) 当有轨迹球事件时调用该方法。
onTouchEvent(MotionEvent) 当有触屏事件时调用该方法。
焦点 onFocusChanged(boolean, int, Rect) 当该View获得或失去焦点是调用该方法。
onWindowFocusChanged(boolean)

当包含该View的window获得或是去焦点是调用该方法 。

注意:这和View的焦点是分开的:要能接收按键事件,View和它的window必须都是已经获得焦点的。如果有一个window显示在你的window之上那么它就获取了焦点,而你的window就失去了焦点,但是(你的window中的)View的焦点还是没有变。

Attaching onAttachedToWindow() 当该view被附加到一个window上时调用该方法。
onDetachedFromWindow() 当该View从window分离时调用该方法。
onWindowVisibilityChanged(int) 当包含该View的window显示或者隐藏时调用该方法。

A Custom View Example

API Demos中的 CustomView 示例提供了一个自定义控件的例子。自定义的控件创建在 LabelVie 类中。

LabelView 简单演示了自定义控件的方方面面:

  • 为一个完全自定义控件扩展View类。
  • 采用有参数的构造函数,该方法接受View的inflation参数(这些参数定义在XML中)。其中一些参数传给父类(的构造函数处理),但是重点是LabelView定义并使用了几个自定义属性。
  • 定义了一些public方法,这些方法可以让这个控件有你想要的样子,例如 setText(),setTextSize()setTextColor()等等。
  • 覆写onMeasure的方法来测量和保存这个控件的绘制大小。(注意:在LableView中,实际工作是由一个叫measureWidth()的private方法来做的。)
  • 覆写onDraw()方法来在提供的canvas上绘制label。

你可以在示例的custom_view_1.xml中看到自定义LabelView的一些用法,重点是,你可以看到android:命名控件参数和自定义的app:命名控件参数混合使用。那些app:参数是LabelView识别并使用的自定义参数,并且这些参数定义在示例程序的资源定义类R类的一个样式内部类中。

Compound Controls

如果你不想创建一个完全自定义的控件,而是想用现有的控件组装一个可重用的控件,那么做一个Compound Component(或者叫Compund Control)或许正好满足需求。在一个小容器内(nutshell),把一些更小的控件(或者说View)组成一个逻辑分组,这个逻辑分组可以作为一个整体使用。例如,一个Combo Box 可以看作是由一个单行文本编辑框和旁边的一个按钮组成,这个按钮附加了一个弹出列表。如果你点击这个按钮并从列表中做出选择,那么选择的东西就会显示在文本编辑框中,如果用于愿意,也可以直接在文本编辑框中输入。

在Android中,其实另外两个现在成View是这么做的:Spinner 和AutoCompleteTextView,但是,Combo Box的概念更容易理解。

创建一个组合控件:

  1. 通常开始于某种布局,所以创建一个继承Layout的类。拿Combo box来说,我们可能要用一个LinearLayout,采用水平排列。记住里面可以嵌套其它的布局,所以一个组合控件可以任意组合构造。注意,就像用Activity一样,你即可以用声明(XML-based)的方法去创建包含的控件,也可以用代码构建它们。
  2. 在新类的构造函数中,接收任何父类想要的参数,并且第一时间把它们传给父类构造函数。接下来你可以安装新控件要用的其它View,就是你要在这里创建文本编辑框和弹出列表。你可能还要在XML中描述自己的属性和参数,这些属性参数都将被提取出来为你的构造函数所用。
  3. 你还可以创建监听器,监听器可以监听你所包含View所产生的事件,例如,当对列表进行选择操作时,一个List Item Click Listener 的监听方法可以用来更新文本编辑器的内容。
  4. 你可能还要用访问器和修改器来创建自己的属性,例如,允许该控件中的文本编辑框的值可以初始化,并且可以在需要是查询其内容。
  5. 在继承了Layout的情况下,你不需要覆写onDraw()和onMeasure()方法,因为Layout的缺省行为已经做的很好了。但是如果需要你还是可以覆写它们。
  6. 你可能还要覆写其它onXXX方法,比如onKeyDown,当某些键被按下时可以取出Combo box中弹出列表的某些默认值。

总而言之,基于Layout创建自定义控件的优势包括:

  • 你可以像Activity屏幕那样用声明性的XML文件来指定布局,也可以用代码创建View,并把它们嵌入到这个布局里面。
  • onDraw()和onMeasure()方法(还有其他很多onXXX方法)很可能已经有了合适的行为,所以你不必覆写它们。
  • 最后,你可以快速、任意地把多个控件组合起来并且把它们当成单个控件那样复用。

Examples of Compound Controls

随SDK发布的Demos工程中,在Views/List下有两个List的示例-Example4和Example6,做了一个SpeechView的演示,该控件扩展了LinearLayout显示演讲摘要。演示代码相应的类是List4.java和List6.java。

Modifying an Existing View Type

在某些情况下有更简单更实用的方式去创建自定义控件。如果现有控件中有和你的需求非常相近的控件,你可以简单的扩展这个控件并只改变你想改变的行为就行了。通过完全自定义控件你当然可以做任何事,但是从View树种的一个特定类作为起点你同样可以做很多事,并且很可能只用做你想做的事。

例如,SDK的示例中有个NotePad application的工程。该工程演示了android平台很多方面的应用,很多都是扩展EditText View来制作一个有条纹效果的记事本。这并非完美的例子。并且所用的早期API现在可能有变,但是它演示了这种基本思路。

如果你没有这样干过,把这个NotePad示例导入Eclipse吧(或者通过这里的链接看一下源代码)。其中特别留意NoteEditor.java中MyEditText的定义。

一些要注意的要点:

1.定义

 这个类用下面一行代码定义:

 public static class MyEditText extends EditText

  • 它是做为NoteEditor Activity的一个内部类定义的,但是它是publict的,所以如果需要可以在NoteEditor的外部通过NoteEditor.MyEditText来访问。
  • 它是static的,就是说它不会产生访问外部类数据的所谓“synthetic methods”,也就意味着它是一个独立的类而不是和NoteEditor有很深的关联。如果它不需要访问外部类的状态,那么用这种方法创建内部类比较简洁,并且使内部类短小精悍,也可以被其它类放边使用。
  • 它继承自EditText,我们选择基于EditText来定制控件。完成后,新的类将代替普通的EditText View。

2.类的初始化

  通常,要先调用父类(的构造函数)。此外,这里用的不是默认构造函数而是由参数的构造函数。当通过inflat xml文件创建EditText的时候用的是有参数(的构造函数),因此我们的构造函数也需要接收这些参数并把它   们传给父类的构造函数

3.覆写方法

    在这个例子中,只覆写了一个方法:onDraw()-但是你创建自己的控件时很可能需要覆写其它的方法。

  对于NotePad示例,覆写onDraw()方法可以让我们在EditText View的Canvas(这个Canvas是通过被覆写的onDraw()方法传递进来的)绘制蓝色的条纹。父类的onDraw()是在该方法的结尾调用的。这父类的方法是应该调用,但是在这种情况下,我们是在画好蓝色条纹后调用它。

4.使用自定义控件

   现在有了自定义控件,但是我们要如何使用呢?在NotePad示例中,自定义控件时直接在描述性布局文件中使用的,所以我们看看res/layout文件夹下的note_editor.xml文件:

   

<viewclass="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编程中引用内部类的标准方法。如果你的自定义控件不是内部类,那么你就可以在xml文件中用element名称来声明控件,不需要class属性。例如:

    

<com.android.notepad.MyEditTextid="@+id/note"... />

  注意这种情况是MyEditText是一个独立的类文件。如果是嵌套类的话这种写法就不会正常工作。

  • 其它的属性和参数是用来传递给自定义控件的构造函数的,然后再传给EditText的构造函数,所以他们和你使用EditText时传递的参数一样。同样,也可以加入你自己的参数,我们下面会讲到这些。

这就是所有的内容。当然,这是比较简单的case,但是自定义控件的复杂度只和你的需求有关。

更复杂的控件需要覆写更多的onXXX方法,也需要引入它的辅助方法,大量的定制它的属性发方法。这决定于你的思维和你的需求。

    

转载于:https://www.cnblogs.com/rockyzhao/archive/2012/09/17/2680183.html

Custom Components 翻译相关推荐

  1. Android 用户界面---定制组件(Custom Components)

    基于布局类View和ViewGroup的基本功能,Android为创建自己的UI界面提供了先进和强大的定制化模式.首先,平台包含了各种预置的View和ViewGroup子类---Widget和layo ...

  2. 【翻译】安卓新播放器EXOplayer介绍

    [翻译]安卓新播放器EXOplayer介绍 http://developer.android.com/guide/topics/media/exoplayer.html 前言: Playing vid ...

  3. RaSa2.5.x配置之二:管道组件(Pipeline Components)

    目录 语言模型(Language Models) MitieNLP SpacyNLP HFTransformersNLP 分词器(Tokenizers) WhitespaceTokenizer Jie ...

  4. react.js做小程序_如何使用React.js构建现代的聊天应用程序

    react.js做小程序 In this tutorial, I will guide you to build your own group chat application using React ...

  5. unity开发入门_Unity游戏开发终极入门指南

    unity开发入门 Unity is a great tool for prototyping everything from games, to interactive visualisations ...

  6. react 组件样式_如何使用样式化组件为React组件创建视觉变体

    react 组件样式 by Gilad Dayagi 通过吉拉德·达亚吉 如何使用样式化组件为React组件创建视觉变体 (How to create visual variants for Reac ...

  7. DeepR —训练TensorFlow模型进行生产

    Authors Guillaume Genthial, Romain Beaumont, Denis Kuzin, Amine Benhalloum 作家 Guillaume Genthial , R ...

  8. [推荐]大量 Blazor 学习资源(三)

    大量 Blazor 学习资源系列文章: [推荐]大量 Blazor 学习资源(一) [推荐]大量 Blazor 学习资源(二) 这次主要内容有 Blazor 相关视频,因为本身视频是英文的,所以就保持 ...

  9. 自动化yaml文件_从YAML到TypeScript:开发人员对云自动化的看法

    自动化yaml文件 The rise of managed cloud services, cloud-native, and serverless applications brings both ...

最新文章

  1. centos6.8服务器配置之SVN配置
  2. ZOJ 3781 最短路(想法好题目)
  3. python写自动答题脚本_问卷星的自动答题脚本
  4. mysql 备份库的shell_MySQL数据库的shell脚本自动备份
  5. MySQL分库分表总结参考
  6. 10个管理工作时间的小技巧
  7. 乘法原理的例题和答案_吃透高考数学17个必考题型,基础再差也能考130!(内附解题技巧+例题解析)...
  8. 【优化分类】基于matlab麻雀算法优化核极限学习机KELM分类【含Matlab源码 1791期】
  9. 原生js实现点击“上一张”、“下一张”按钮切换图片
  10. MATLAB的图像显示函数imshow()详解
  11. COM:求助根系分泌物:受胁迫植物从土壤中招募益生菌的适应性机制
  12. Comparative Evaluation of Genome Assemblers from Long-Read Sequencing for Plants and Crops
  13. 浙江大学计算机考研2020,浙江大学计算机考研经验分享
  14. 响应式开发原理及Bootstrap栅格布局详解
  15. Java入门-Java学习路线课程面试篇:取商 / 和取余(模) % 符号的使用
  16. 手机收不到第三方发送的短信及验证码
  17. mili u盘 android手机,mili otg数据线如何使用?
  18. 小程序一键生成系统网站源码
  19. 目标检测中的数据增强,包括bbox的变换
  20. xposed微信插件大全

热门文章

  1. 文本分类的14种算法
  2. 今年要如何准备?想去阿里/美团/头条做机器学习工程师
  3. swing获取文本框内容_Swing 使用 JTable详解
  4. python访问字符串中的部分字符的操作_python中字符串的常见操作方法
  5. 用计算机算非,在线计算器上的与、或、非、异或等逻辑运算键如何使用?
  6. html5pc转微信小程序,微信电脑版终于支持小程序 新版PC版微信实测
  7. pytorch tensor操作:tensor与numpy转换
  8. 基于python的文件加密传输_Python优雅的加密传输文件
  9. Android仿人人客户端(v5.7.1)——Auth授权认证(整理流程,重构代码)
  10. 手机版php7怎么安装,Centos7 安装 PHP7最新版的详细教程