View

来源:互联网 发布:淘宝商城童装男童装 编辑:程序博客网 时间:2024/06/05 11:40

概述

该类是所有用户界面组件的基本类。一个view占据了屏幕的一块矩形区域,并负责绘制和事件处理。View是widgets的基类
widgets通常用来创建可交互的ui界面(按钮,文本框等)。它的子类ViewGroup是layouts的基类,layouts本身不可见,用来容纳其他Views和ViewGroups,并且定义他们的布局属性。

开发指导

有关于使用该类开发你自己应用程序的界面,请阅读【用户界面开发指南】

使用Views

窗体中的所有views都在一个简单树形结构中,你可以通过代码指定一个views的树来添加控件,或者使用xml布局文件。有一些专门的view被用来显示文字,图片或其它内容。
一旦你创建了一个窗体视图,一般有几个公共的操作需要执行:
  • 设置属性
  • 设置焦点
  • 设置监听器
  • 设置可见性

实现一个自定义view

为了实现一个自定义view,你需要覆盖一些framework在所有view中都会被调用的方法。并不需要覆盖所有的方法,事实上,可以先从覆盖 onDraw(android.graphics.Canvas).开始。
类别方法描述Creation构造函数第一个构造函数在view创建时会被调用。第二个构造函数试图解析并应用任何在布局文件中定义的属性(attributes )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的可见性改变时 调用

IDs

view也许有一个与之相关联的整型id。这些id通常在xml布局文件中被指定,用来在view tree中找到这个view。一个常见的使用场景:
在布局文件中定义一个Button并且指定唯一ID
<Button
android:id="@+id/my_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/my_button_text"/>

在Activity中的onCreate方法中,找到该Button
Button myButton = (Button) findViewById(R.id.my_button);
view的id在整个树中不需要唯一,但是需要确保你查找的树中要查找的view的id是唯一的。

位置

view的几何构造是一个矩形。一个view有位置信息,通过一对left和top坐标描述,这两个的尺寸又是通过宽度和高度来表示。位置和尺寸的单位是像素(pixel)。
通过调用getLeft() 和getTop().可以取得view的位置信息。前者返回left或者X坐标,后者返回top或者Y坐标。返回的位置信息都是相对于父view而言的。例如,getLeft()返回了20,意味着该view位于父view的左边缘向右偏移20像素的位置。
另外,使用一些便利的方法避免不必要的计算, getRight() 和getBottom()这些方法返回距离右部和底部边缘的偏移量
getRight()的计算有点像getLeft() + getWidth()

大小,内边距(padding)和外边距(margins)
view的大小通过了宽和高来表达。一个view实际上拥有两对宽高值。
第一对通过测量的宽度和高度得知。这个维度定义了视图在其父view中有多大。测量的尺寸可以通过调用getMeasuredWidth() 和getMeasuredHeight().获得。
第二对通过直接得知的宽高或者是绘制时的宽高。这个维度定义了view在屏幕中的实际大小。在绘制的时候和布局完成时,这对值可能会不同于测量的宽高。该宽高值可以由getWidth() and getHeight().获得。
测量它的尺寸,需要考虑其内边距。内边距通过相对于view本身的上下左右偏移量表示。通过使用一个特别的像素量,内边距可用于抵消view的内容。例如,左内边距为2将会将靠左边缘的内容向右推2个像素。内边距的设置和获取:setPadding(int, int, int, int) or setPaddingRelative(int, int, int, int) getPaddingLeft()getPaddingTop(),getPaddingRight()getPaddingBottom()getPaddingStart()getPaddingEnd().

尽管view可定义内边距,但并未提供任何支持外边距的方法。然而,view groups提供了相应的支持。详情请查看 ViewGroup 和ViewGroup.MarginLayoutParams 

布局

布局有两个过程:测量过程和布局过程。测量过程实现measure(int, int) 并且自顶向下遍历view tree。当递归发生时,在这颗树中的每一个view的尺寸大小都进行叠加。最后,存储了每个view的测量值。布局过程发生在 layout(int, int, int, int) 时,也是自顶向下的。在这个过程中每个父节点都负责使用在测量过程中计算出的大小数值定位其所有的子节点。
当一个view的measure()方法返回时, getMeasuredWidth() 和getMeasuredHeight()就可以获取到值了,并不包括该节点下的所有子节点。一个view的测量宽高值必须遵循父view的约束条件。这样便能保证在测量结束时所有的父节点都能接受所有子节点的尺寸。父view会多次为其子view调用measure()。例如,父类会去测量那些未指明大小的子view一次以确定它们的大小,如果它们的和太小或太大,会再次为它们调用measure()并传递实际数字。
测量过程中通过使用两个类来进行沟通。View.MeasureSpec 类被子view用来告知其父view要如何测量和定位。LayoutParams基类仅仅通过宽高来描述view期望的大小。每一个测量,都能指定以下的一个:
  • 一个确切的数字
  • MATCH_PARENT,意味着view的大小将会和父view一样大(减去内边距)
  • WRAP_CONTEN,意味着view会变成刚好能容纳其内容的大小(加上内边距)
LayoutParams有许多子类用来描述不同的ViewGroup。例如,AbsoluteLayout 有自己的LayoutParams ,增加了X和Y值。
MeasureSpecs 通常被用来降低父节点对子节点的要求。一个MeasureSpecs可以指定如下三个模式中的一个:
UNSPECIFIED:父节点决定一个子节点的期望大小。例如,一个LinearLayout 会为其子view调用measure(),将其高设置为UNSPECIFIED、宽设置为EXACTLY 240。用以找出当给定宽为240pix时能有多高。
EXACTLY:父视图为子视图指定一个确切的数值大小。子视图必须使用这个大小,并且确保子视图的所有子视图会适合这个尺寸。
AT_MOST:父视图为子视图实施一个最大值。子视图必须保证它和它的所有子视图会适合这个尺寸。
初始化一个布局,调用 requestLayout()调用这个方法通常是由view认为不再适合在当前的边界。

绘制

绘制由遍历树并且呈现每一个view。因为树是顺序遍历的,这意味着父视图绘制在前,子视图在后,之后才是同层次的视图。如果你在View中绘制一个背景,在调用onDrwa()之前就会被绘制。
注:框架不会在无效区域以外的地方绘制视图,并且在后台小心翼翼的为你绘制。你可以强制绘制视图,调用invalidate().

事件处理和线程

view的基本循环如下:
  1. 事件传递进来并派遣制适当的view,该view处理该事件并且通知所有监听者。
  2. 如果在处理事件的过程中,该view的边界需要被改变,该view需要调用requestLayout().
  3. 类似的,在处理事件的过程中,该view的外观会被改变,该view需要调用invalidate().
  4. 如果不调用requestLayout() or invalidate() ,框架会适当的留心测量、布局和绘图树。
注:整个视图树是一个单线程。你必须在ui线程中调用任何与之有关的方法。如果你在其他线程中工作的时候想更新view的状态,可以使用Handler.

焦点处理

框架将处理程序集中运动响应用户输入。这包括通过 隐藏view或移除view或一个新view变为可用 来改变焦点,View通过isFocusable()函数来表明想获得焦点的意愿。改变一个view是否能获得焦点,调用setFocusable(boolean)在触摸模式view通过isFocusableInTouchMode() 表明是否可以一直获得焦点,可调用setFocusableInTouchMode(boolean).改变。
焦点的变动是基于一个最近原则的算法实现的。在罕见的情况下,默认算法或许与开发人员的预期不一致。这时,你可以通过在xml布局文件中使用如下属性显示的进行覆盖
nextFocusDown
nextFocusLeft
nextFocusRight
nextFocusUp
给特别的view获取焦点,调用requestFocus().

触摸模式

当用户有一个方向键控制的导航界面时,给予可操作项目(例如按钮)焦点是十分有必要的,这样用户就能看见什么可以获取输入。如果设备有触摸功能,用户通过触摸它,开始与界面交互,这时并没有太大的必要去突出它,或者给它焦点,这激发了一个名为“触摸模式”的互动模式。

具有触摸能力的设备,一旦用户触摸了屏幕,设备就会进入触摸模式。从此刻起,只有view使用了isFocusableInTouchMode() 为真才会变为可聚焦的,例如文本编辑框。其它的views仍旧可触摸,例如buttons,当触摸它时文本框并不会失去焦点;它们(buttons)只会在点击事件中激发
任何时候用户直接点击按键,如方向键,设备便会退出触摸模式,并且找到一个view让其获得焦点,这样用户可以通过再次点击屏幕来进入触摸模式。
触摸模式状态在Activitys中维持着,调用isInTouchMode() 查看此刻是否是触摸模式。

滚动

框架提供了关于在view内部内容的基本滚动支持。包括持续跟踪X和Y滚动抵消以及绘制滚动条。查看【滚动相关】获取更多内容

标签
不同于ID,标签不被用来标识view。标签本质上是与view相关的一个额外的信息。它们通常被用于方便存储与view相关的数据而不是用一个单独的结构存储。

属性

View类公开了一个ALPHA 属性,和所有的变换相关的属性(例如TRANSLATION_X and TRANSLATION_Y)一样。这些属性在类似于setter/getter形式的Property表单中 起作用。这些属性能够被用来设置在相关view上呈现出来的持续状态。属性和方法也可以用来集合Animator-动画。详情请看动画章节

动画
始于安卓3.0版本,首选的动画视图便是使用android.animation包下的API。这些动画基类改变View上实际的属性值,如透明度和X轴变换。可以将其与3.0之前的动画基类相比,不仅仅是显示绘制过程。另外ViewPropertyAnimator 类让视图动画更加高效和方便。
另外,您可以使用3.0之前的动画类动呈现画视图。可以给view附加一个 Animation 对象,通过setAnimation(Animation) or startAnimation(Animation)动画可以改变尺度、旋转、翻转和透明视图。如果被添加动画的视图有子视图,动画效果会作用于以其为根的整个子树。当动画开始时,框架会注意重绘适当的view指导动画结束

安全

有时候一个应用程序能够验证并同意用户执行的行动是至关重要的,例如授予权限请求,购买或者点击一个广告。不幸的是,恶意的应用程序会视图恶搞用户执行这些操作,在用户察觉不到的情况下,隐蔽的在view中执行。作为一个补救措施,框架提供了一个触摸过滤机制用来提高view提供访问敏感功能时的安全性。
启用触摸过滤,只需调用setFilterTouchesWhenObscured(boolean) 或者设置  android:filterTouchesWhenObscured 布局属性为true。当启用时,如果view的窗口被其它可见窗口遮挡,框架将会丢弃每次收到的触摸。结果,每当一个toast,dialog或者其他窗口出现在该view的窗口之上时,该view将永远也收不到触摸。
更加细化的控制安全性,考虑覆盖onFilterTouchEventForSecurity(MotionEvent) 方法来实现自己的安全方针。


扩展阅读

【用户界面开发指南】http://android-doc.com/guide/topics/ui/index.html
【外边距相关】http://android-doc.com/reference/android/view/ViewGroup.MarginLayoutParams.html
【滚动相关】 scrollBy(int, int), scrollTo(int, int),awakenScrollBars()
【动画相关】http://android-doc.com/reference/android/view/View.html#Animation
0 0