Android开发入门之View类详解及其小例子

来源:互联网 发布:java。 大数据 编辑:程序博客网 时间:2024/06/04 18:21

Class Overview

This class represents the basic building block for user interface components. A View occupies a rectangular area on the screen and is responsible for drawing and event handling. View is the base class forwidgets, which are used to create interactive UI components (buttons, text fields, etc.). The ViewGroup subclass is the base class for layouts, which are invisible containers that hold other Views (or other ViewGroups) and define their layout properties.

Developer Guides

For information about using this class to develop your application's user interface, read the User Interface developer guide.

Using Views

All of the views in a window are arranged in a single tree. You can add views either from code or by specifying a tree of views in one or more XML layout files. There are many specialized subclasses of views that act as controls or are capable of displaying text, images, or other content.

Once you have created a tree of views, there are typically a few types of common operations you may wish to perform:

  • Set properties: for example setting the text of a TextView. The available properties and the methods that set them will vary among the different subclasses of views. Note that properties that are known at build time can be set in the XML layout files.
  • Set focus: The framework will handled moving focus in response to user input. To force focus to a specific view, callrequestFocus().
  • Set up listeners: Views allow clients to set listeners that will be notified when something interesting happens to the view. For example, all views will let you set a listener to be notified when the view gains or loses focus. You can register such a listener using setOnFocusChangeListener(android.view.View.OnFocusChangeListener). Other view subclasses offer more specialized listeners. For example, a Button exposes a listener to notify clients when the button is clicked.
  • Set visibility: You can hide or show views using setVisibility(int).

Note: The Android framework is responsible for measuring, laying out and drawing views. You should not call methods that perform these actions on views yourself unless you are actually implementing aViewGroup.

Implementing a Custom View

To implement a custom view, you will usually begin by providing overrides for some of the standard methods that the framework calls on all views. You do not need to override all of these methods. In fact, you can start by just overridingonDraw(android.graphics.Canvas).

image

从这个表中可以看出, onMeasure(int,int)是测量本View和子View的size,而onLayout(boolean,int,int,int,int)是分配子View的size, position,而onDraw(canvas)是渲染本View的content.

IDs

Views may have an integer id associated with them. These ids are typically assigned in the layout XML files, and are used to find specific views within the view tree. A common pattern is to:

  • Define a Button in the layout file and assign it a unique ID.
     <Button     android:id="@+id/my_button"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:text="@string/my_button_text"/> 
  • From the onCreate method of an Activity, find the Button
          Button myButton = (Button) findViewById(R.id.my_button); 

View IDs need not be unique throughout the tree, but it is good practice to ensure that they are at least unique within the part of the tree you are searching.

Position

The geometry of a view is that of a rectangle. A view has a location, expressed as a pair of left and top coordinates, and two dimensions, expressed as a width and a height. The unit for location and dimensions is the pixel.

It is possible to retrieve the location of a view by invoking the methods getLeft() and getTop(). The former returns the left, or X, coordinate of the rectangle representing the view. The latter returns the top, or Y, coordinate of the rectangle representing the view. These methods both return the location of the view relative to its parent. For instance, when getLeft() returns 20, that means the view is located 20 pixels to the right of the left edge of its direct parent.

In addition, several convenience methods are offered to avoid unnecessary computations, namely getRight() and getBottom(). These methods return the coordinates of the right and bottom edges of the rectangle representing the view. For instance, calling getRight()is similar to the following computation: getLeft() + getWidth() (see Size for more information about the width.)

Size, padding and margins

The size of a view is expressed with a width and a height. A view actually possess(占据,控制) two pairs of width and height values.

The first pair is known as measured width and measured height. These dimensions define how big a view wants to be within its parent (see Layout for more details.) The measured dimensions can be obtained by calling getMeasuredWidth() andgetMeasuredHeight().//第一对宽高指离父容器的距离,可以用getMeasuredWidth() and getMeasuredHeight()获得.

The second pair is simply known as width and height, or sometimes drawing width and drawing height. These dimensions define the actual size of the view on screen, at drawing time and after layout. These values may, but do not have to, be different from the measured width and height. The width and height can be obtained by calling getWidth() and getHeight().//第二对宽高指自己的,可以用getWidth() and getHeight()获得.

To measure its dimensions, a view takes into account its padding. The padding is expressed in pixels for the left, top, right and bottom parts of the view. Padding can be used to offset the content of the view by a specific amount of pixels. For instance, a left padding of 2 will push the view's content by 2 pixels to the right of the left edge. Padding can be set using the setPadding(int, int, int, int) method and queried by calling getPaddingLeft()getPaddingTop()getPaddingRight()getPaddingBottom().

Even though a view can define a padding, it does not provide any support for margins. However, view groups provide such a support. Refer to ViewGroup and ViewGroup.MarginLayoutParams for further information.这里说的应该是: 虽然view有定义padding的方法, 但是他没有提供对margins的支持, 但是view groups提供了支持.

Layout

Layout is a two pass process(步骤): a measure pass and a layout pass. The measuring pass is implemented in measure(int, int) and is a top-down(自上而下的) traversal(遍历) of the view tree. Each view pushes dimension specifications down the tree during the recursion(递归). At the end of the measure pass, every view has stored its measurements. The second pass happens in layout(int, int, int, int) and is also top-down. During this pass each parent is responsible for positioning all of its children using the sizes computed in the measure pass.这里说的太清楚了.

When a view's measure() method returns, its getMeasuredWidth() and getMeasuredHeight() values must be set, along with those for all of that view's descendants(子孙,后裔). A view's measured width and measured height values must respect(遵守) the constraints(约束) imposed by the view's parents. This guarantees that at the end of the measure pass, all parents accept all of their children's measurements. A parent view may call measure() more than once on its children. For example, the parent may measure each child once with unspecified dimensions to find out how big they want to be, then call measure() on them again with actual numbers if the sum of all the children's unconstrained sizes is too big or too small.

The measure pass uses two classes to communicate dimensions. The View.MeasureSpec class is used by views to tell their parents how they want to be measured and positioned. The base LayoutParams class just describes how big the view wants to be for both width and height. For each dimension, it can specify one of:

  • an exact number
  • MATCH_PARENT, which means the view wants to be as big as its parent (minus padding)
  • WRAP_CONTENT, which means that the view wants to be just big enough to enclose its content (plus padding).

下面这句话非常重点: 不同的ViewGroup的子类有自己的LayoutParames的子类, 这就是有时RelativieLayout里的孩子导包的时候导ViewGroup.LayoutParams运行出错的原因.必须指定具体.

There are subclasses of LayoutParams for different subclasses of ViewGroup.For example, AbsoluteLayout has its own subclass of LayoutParams which adds an X and Y value.

MeasureSpecs are used to push requirements down the tree from parent to child. A MeasureSpec can be in one of three modes:

  • UNSPECIFIED: This is used by a parent to determine the desired dimension of a child view. For example, a LinearLayout may call measure() on its child with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how tall the child view wants to be given a width of 240 pixels.
  • EXACTLY: This is used by the parent to impose an exact size on the child. The child must use this size, and guarantee that all of its descendants will fit within this size.
  • AT_MOST: This is used by the parent to impose a maximum size on the child. The child must gurantee that it and all of its descendants will fit within this size.

To intiate a layout, call requestLayout(). This method is typically called by a view on itself when it believes that is can no longer fit within its current bounds.

Drawing

Drawing is handled by walking the tree and rendering each view that intersects(交叉,贯穿) the invalid region. Because the tree is traversed in-order, this means that parents will draw before (i.e., behind) their children, with siblings drawn in the order they appear in the tree. If you set a background drawable for a View, then the View will draw it for you before calling back to its onDraw() method.

Note that the framework will not draw views that are not in the invalid region.//这TM是双重否定表强调?

To force a view to draw, call invalidate().

Event Handling and Threading

The basic cycle of a view is as follows:

  1. An event comes in and is dispatched to the appropriate view. The view handles the event and notifies any listeners.
  2. If in the course of processing the event, the view's bounds may need to be changed, the view will call requestLayout().
  3. Similarly, if in the course of processing the event the view's appearance may need to be changed, the view will callinvalidate().
  4. If either requestLayout() or invalidate() were called, the framework will take care of measuring, laying out, and drawing the tree as appropriate.

Note: The entire view tree is single threaded. You must always be on the UI thread when calling any method on any view. If you are doing work on other threads and want to update the state of a view from that thread, you should use a Handler.

Focus Handling

The framework will handle routine focus movement in response to user input. This includes changing the focus as views are removed or hidden, or as new views become available. Views indicate their willingness(乐意) to take focus through the isFocusable() method. To change whether a view can take focus, call setFocusable(boolean). When in touch mode (see notes below) views indicate whether they still would like focus via isFocusableInTouchMode() and can change this via setFocusableInTouchMode(boolean).

Focus movement is based on an algorithm(算法) which finds the nearest neighbor in a given direction. In rare(稀有的) cases, the default algorithm may not match the intended behavior of the developer. In these situations, you can provide explicit overrides by using these XML attributes in the layout file:

 nextFocusDown nextFocusLeft nextFocusRight nextFocusUp 

To get a particular view to take focus, call requestFocus().

Touch Mode

When a user is navigating a user interface via directional keys such as a D-pad(方向键), it is necessary to give focus to actionable items such as buttons so the user can see what will take input. If the device has touch capabilities, however, and the user begins interacting with the interface by touching it, it is no longer necessary to always highlight, or give focus to, a particular view. This motivates(促使) a mode for interaction named 'touch mode'.

For a touch capable device, once the user touches the screen, the device will enter touch mode. From this point onward(向前的,前进的), only views for which isFocusableInTouchMode() is true will be focusable, such as text editing widgets. Other views that are touchable, like buttons, will not take focus when touched; they will only fire the on click listeners.

Any time a user hits a directional key, such as a D-pad direction, the view device will exit touch mode, and find a view to take focus, so that the user may resume interacting with the user interface without touching the screen again.

The touch mode state is maintained across Activitys. Call isInTouchMode() to see whether the device is currently in touch mode.

Scrolling

The framework provides basic support for views that wish to internally(内部的,内在的) scroll their content. This includes keeping track of the X and Y scroll offset as well as mechanisms for drawing scrollbars. SeescrollBy(int, int)scrollTo(int, int), andawakenScrollBars() for more details.

Tags

Unlike IDs, tags are not used to identify views. Tags are essentially an extra piece of information that can be associated with a view. They are most often used as a convenience to store data related to views in the views themselves rather than by putting them in a separate structure.

Animation

You can attach an Animation object to a view using setAnimation(Animation) or startAnimation(Animation). The animation can alter the scale, rotation, translation and alpha of a view over time. If the animation is attached to a view that has children, the animation will affect the entire subtree rooted by that node. When an animation is started, the framework will take care of redrawing the appropriate views until the animation completes.

Starting with Android 3.0, the preferred way of animating views is to use the android.animation package APIs.

Security

Sometimes it is essential that an application be able to verify that an action is being performed with the full knowledge and consent (同意)of the user, such as granting a permission request, making a purchase or clicking on an advertisement. Unfortunately, a malicious(恶意的) application could try to spoof(哄骗) the user into performing these actions, unaware, by concealing(隐藏,隐瞒) the intended purpose of the view. As a remedy(补正), the framework offers a touch filtering mechanism that can be used to improve the security of views that provide access to sensitive functionality.

To enable touch filtering, call setFilterTouchesWhenObscured(boolean) or set the android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework will discard touches that are received whenever the view's window is obscured by another visible window. As a result, the view will not receive touches whenever a toast, dialog or other window appears above the view's window.

For more fine-grained control over security, consider overriding the onFilterTouchEventForSecurity(MotionEvent) method to implement your own security policy. See also FLAG_WINDOW_IS_OBSCURED.

 

1、重写一个View。

代码如下:

复制代码
public  class  RotateTextView  extends  TextView {private  static  final  String  NAMESPACE = “http://www.ywlx.net/apk/res/easymobi”;private  static  final  String  ATTR_ROTATE = “rotate”;private  static  final  int  DEFAULTVALUE_DEGREES = 0;private  int  degrees ;public  RotateTextView(Context context, AttributeSet attrs) {super(context, attrs);degrees = attrs.getAttributeIntValue(NAMESPACE, ATTR_ROTATE, DEFAULTVALUE_DEGREES);}@Overrideprotected  void  onDraw(Canvas canvas) {canvas.rotate(degrees,getMeasuredWidth()/2,getMeasuredHeight()/2);super.onDraw(canvas);}}
复制代码

使用自定义RotateTextView如下:

复制代码
<cn.easymobi.application.memorytest.RotateTextViewandroid:layout_width=”wrap_content”android:layout_height=”wrap_content”android:padding=”8dip”android:gravity=”center”android:id=”@+id/tvBottom_color”android:textSize=”15dip”android:textColor=”@color/black”easymobi:rotate=”10″android:layout_marginTop=”468dip”/>
复制代码

个人觉得这个例子挺不错的,简单易懂,而且涉及的内容比较单一。需要更详细的讲解看文章http://labs.ywlx.net/?p=284 。

 

2、重写一个ViewGroup。

代码如下:

复制代码
public class MyViewGroup extends ViewGroup {      public MyViewGroup(Context context) {          super(context);          this.initOtherComponent(context);      }      private void initOtherComponent(Context context) {          Button aBtn = new Button(context);          // set id 1           aBtn.setId(1);          aBtn.setText("a btn");          this.addView(aBtn);          Button bBtn = new Button(context);          // set id 2           bBtn.setId(2);          bBtn.setText("b btn");          this.addView(bBtn);      }      @Override      protected void onLayout(boolean changed, int l, int t, int r, int b) {          int childCount = getChildCount();          for (int i = 0; i < childCount; i++) {              View child = getChildAt(i);              switch (child.getId()) {              case 1:                  // 1 is aBtn                   Log.d("MyViewGroup", "btn1 setting");                  child.setVisibility(View.VISIBLE);                  child.measure(r - l, b - t);                  child.layout(0, 0, child.getMeasuredWidth(), child                          .getMeasuredHeight());                  break;              case 2:                  // 2 is bBtn                   Log.d("MyViewGroup", "btn2 setting");                  child.setVisibility(View.VISIBLE);                  child.measure(r - l, b - t);                 child.layout(0, 50, child.getMeasuredWidth(), child                          .getMeasuredHeight() + 50);                  break;              default:                  //               }          }      }  }  
复制代码

这个例子主要是说明layout 和Measure的使用。

 

3、两个例子的总结。

重写一个view一般情况下只需要重写OnDraw方法。那么什么时候需要重写OnMeasure、OnLayout、OnDraw方法呢,这个问题只要把这几个方法的功能弄清楚你就应该知道怎么做了。在此我也简单的讲一下(描述不正确请拍砖,欢迎交流)。

①如果需要改变View绘制的图像,那么需要重写OnDraw方法。(这也是最常用的重写方式。)

②如果需要改变view的大小,那么需要重写OnMeasure方法。

③如果需要改变View的(在父控件的)位置,那么需要重写OnLayout方法。

④根据上面三种不同的需要你可以组合出多种重写方案,你懂的。

 

 

 

Android开发环境搭建所需资源、安装和配置步骤图解       海量android源码和学习教程与资料集 

数字电视接口规范大全(行业标准)                     程序员必备:英语口语学习教程大全 

20本Linux电子书学习教程                             2013年25家IT高科技公司薪酬排行榜  

2013年Android平台8大预测                            优秀Android开发人员必须注意的10个误区