自定义View(7)官方教程:自定义View(含onMeasure),自定义一个Layout(混合组件),重写一个现有组件

Custom Components

  Android offers a sophisticated and powerful componentized model for building your UI, based on the fundamental layout classes: View and ViewGroup. To start with, the platform includes a variety of prebuilt View and ViewGroup subclasses — called widgets and layouts, respectively — that you can use to construct your UI.

  A partial list of available widgets includes ButtonTextView,EditTextListViewCheckBoxRadioButtonGallery,Spinner, and the more special-purpose AutoCompleteTextView,ImageSwitcher, and TextSwitcher.

  Among the layouts available are LinearLayoutFrameLayoutRelativeLayout, and others. For more examples, see Common Layout Objects.

  If none of the prebuilt widgets or layouts meets your needs, you can create your own View subclass. If you only need to make small adjustments to an existing widget or layout, you can simply subclass the widget or layout and override its methods.

  Creating your own View subclasses gives you precise control over the appearance and function of a screen element. To give an idea of the control you get with custom views, here are some examples of what you could do with them:

  • You could create a completely custom-rendered View type, for example a "volume control" knob rendered using 2D graphics, and which resembles an analog electronic control.
  • You could combine a group of View components into a new single component, perhaps to make something like a ComboBox (a combination of popup list and free entry text field), a dual-pane selector control (a left and right pane with a list in each where you can re-assign which item is in which list), and so on.
  • You could override the way that an EditText component is rendered on the screen (the Notepad Tutorial uses this to good effect, to create a lined-notepad page).
  • You could capture other events like key presses and handle them in some custom way (such as for a game).

  The sections below explain how to create custom Views and use them in your application. For detailed reference information, see the View class.

2.The Basic Approach(自定义View的基本过程)

  Here is a high level overview of what you need to know to get started in creating your own View components:

 下面是自定义一个view 过程的基本概述
  1. Extend an existing View class or subclass with your own class.
    继承 View
  2. Override some of the methods from the superclass. The superclass methods to override start with 'on', for example, onDraw()onMeasure(), and onKeyDown(). This is similar to the on... events inActivity or ListActivity that you override for lifecycle and other functionality hooks.
    重写重要函数,onDraw,onMeasure,onTouchEvent等
  3. Use your new extension class. Once completed, your new extension class can be used in place of the view upon which it was based.
    使用刚自定义的view

  Tip: Extension classes can be defined as inner classes inside the activities that use them. This is useful because it controls access to them but isn't necessary (perhaps you want to create a new public View for wider use in your application).

3.Fully Customized Components

  Fully customized components can be used to create graphical components that appear however you wish. Perhaps a graphical VU meter that looks like an old analog gauge, or a sing-a-long text view where a bouncing ball moves along the words so you can sing along with a karaoke machine. Either way, you want something that the built-in components just won't do, no matter how you combine them.

 完全自定义一个ui组件,可以让显示更生动,要比内嵌的好很多。

  Fortunately, you can easily create components that look and behave in any way you like, limited perhaps only by your imagination, the size of the screen, and the available processing power (remember that ultimately your application might have to run on something with significantly less power than your desktop workstation).

 自定义的ui组件很灵活,定义步骤如下:

  To create a fully customized component:

  1. The most generic view you can extend is, unsurprisingly, View, so you will usually start by extending this to create your new super component.
    继承View
  2. You can supply a constructor which can take attributes and parameters from the XML, and you can also consume your own such attributes and parameters (perhaps the color and range of the VU meter, or the width and damping of the needle, etc.)
    提供一个可以根据xml文件提取属性或参数的构造方法
  3. You will probably want to create your own event listeners, property accessors and modifiers, and possibly more sophisticated behavior in your component class as well.
    可以定义一些与本view配合工作的监听器
  4. You will almost certainly want to override onMeasure() and are also likely to need to override onDraw() if you want the component to show something. While both have default behavior, the default onDraw() will do nothing, and the default onMeasure() will always set a size of 100x100 — which is probably not what you want.
    通常需要重写重要的方法,如:onMeasure,onDraw,onMeasure默认设置大小为100*100,onDraw默认什么也不做。
  5. Other on... methods may also be overridden as required.
    重写你需要的其它onXXX系列方法

3.1 Extend onDraw() and onMeasure()(onDraw,onMeasure详解)

  The onDraw() method delivers you a Canvas upon which you can implement anything you want: 2D graphics, other standard or custom components, styled text, or anything else you can think of.

 注意 onDraw 只支持2d绘制,如果3D绘制,要继承surfaceView,在一个独立的线程中绘制(见示例GLSurfaceViewActivity)。

  Note: This does not apply to 3D graphics. If you want to use 3D graphics, you must extend SurfaceView instead of View, and draw from a separate thread. See the GLSurfaceViewActivity sample for details.

  onMeasure() is a little more involved. onMeasure() is a critical piece of the rendering contract between your component and its container. onMeasure() should be overridden to efficiently and accurately report the measurements of its contained parts. This is made slightly more complex by the requirements of limits from the parent (which are passed in to the onMeasure() method) and by the requirement to call the setMeasuredDimension() method with the measured width and height once they have been calculated. If you fail to call this method from an overridden onMeasure() method, the result will be an exception at measurement time.

onMeasure需要有效地,准确地,向它的容器类报告它内部成员的尺寸。计算出宽,高后必需在onMeasure中调用setMeasuaredDimension方法来设置一下,否则抛异常。

  At a high level, implementing onMeasure() looks something like this:

  1. The overridden onMeasure() method is called with width and height measure specifications (widthMeasureSpec and heightMeasureSpec parameters, both are integer codes representing dimensions) which should be treated as requirements for the restrictions on the width and height measurements you should produce. A full reference to the kind of restrictions these specifications can require can be found in the reference documentation under View.onMeasure(int, int) (this reference documentation does a pretty good job of explaining the whole measurement operation as well).
    当onMeasure被调用时,它的两个参数中包含尺寸信息,可以从其中提取出来。详细见: View.onMeasure(int, int)
  2. Your component's onMeasure() method should calculate a measurement width and height which will be required to render the component. It should try to stay within the specifications passed in, although it can choose to exceed them (in this case, the parent can choose what to do, including clipping, scrolling, throwing an exception, or asking the onMeasure() to try again, perhaps with different measurement specifications).
    onMeasure内应该实现的功能:计算当前控件及其内控件的尺寸大小。
  3. Once the width and height are calculated, the setMeasuredDimension(int width, int height) method must be called with the calculated measurements. Failure to do this will result in an exception being thrown.
    计算好尺寸后,必需调用 setMeasuredDimension() 否则出异常

  Here's a summary of some of the other standard methods that the framework calls on views:

  下面是自定义View时可重载方法:
CategoryMethodsDescription
Creation Constructors

There is a form of the constructor that are called when the view is created from code

and a form that is called when the view is inflated from a layout file.

The second form should parse and apply any attributes defined in the layout file.

onFinishInflate() Called after a view and all of its children has been inflated from XML.
Layout onMeasure(int, int) Called to determine the size requirements for this view and all of its children.
onLayout(boolean, int, int, int, int) Called when this view should assign a size and position to all of its children.
onSizeChanged(int, int, int, int) Called when the size of this view has changed.
Drawing onDraw(Canvas) Called when the view should render its content.
Event processing onKeyDown(int, KeyEvent) Called when a new key event occurs.
onKeyUp(int, KeyEvent) Called when a key up event occurs.
onTrackballEvent(MotionEvent) Called when a trackball motion event occurs.
onTouchEvent(MotionEvent) Called when a touch screen motion event occurs.
Focus onFocusChanged(boolean, int, Rect) Called when the view gains or loses focus.
onWindowFocusChanged(boolean) Called when the window containing the view gains or loses focus.
Attaching onAttachedToWindow() Called when the view is attached to a window.
onDetachedFromWindow() Called when the view is detached from its window.
onWindowVisibilityChanged(int) Called when the visibility of the window containing the view has changed.

3.2 A Custom View Example(一个自定义View的示例)

  The CustomView sample in the API Demos provides an example of a customized View. The custom View is defined in the LabelView class.

  1 /*
  2  * Copyright (C) 2007 The Android Open Source Project
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 
 17 package com.example.android.apis.view;
 18 
 19 // Need the following import to get access to the app resources, since this
 20 // class is in a sub-package.
 21 import android.content.Context;
 22 import android.content.res.TypedArray;
 23 import android.graphics.Canvas;
 24 import android.graphics.Paint;
 25 import android.util.AttributeSet;
 26 import android.view.View;
 27 
 28 import com.example.android.apis.R;
 29 
 30 
 31 /**
 32  * Example of how to write a custom subclass of View. LabelView
 33  * is used to draw simple text views. Note that it does not handle
 34  * styled text or right-to-left writing systems.
 35  *
 36  */
 37 public class LabelView extends View {
 38     private Paint mTextPaint;
 39     private String mText;
 40     private int mAscent;
 41     
 42     /**
 43      * Constructor.  This version is only needed if you will be instantiating
 44      * the object manually (not from a layout XML file).
 45      * @param context
 46      */
 47     public LabelView(Context context) {
 48         super(context);
 49         initLabelView();
 50     }
 51 
 52     /**
 53      * Construct object, initializing with any attributes we understand from a
 54      * layout file. These attributes are defined in
 55      * SDK/assets/res/any/classes.xml.
 56      * 
 57      * @see android.view.View#View(android.content.Context, android.util.AttributeSet)
 58      */
 59     public LabelView(Context context, AttributeSet attrs) {
 60         super(context, attrs);
 61         initLabelView();
 62 
 63         TypedArray a = context.obtainStyledAttributes(attrs,
 64                 R.styleable.LabelView);
 65 
 66         CharSequence s = a.getString(R.styleable.LabelView_text);
 67         if (s != null) {
 68             setText(s.toString());
 69         }
 70 
 71         // Retrieve the color(s) to be used for this view and apply them.
 72         // Note, if you only care about supporting a single color, that you
 73         // can instead call a.getColor() and pass that to setTextColor().
 74         setTextColor(a.getColor(R.styleable.LabelView_textColor, 0xFF000000));
 75 
 76         int textSize = a.getDimensionPixelOffset(R.styleable.LabelView_textSize, 0);
 77         if (textSize > 0) {
 78             setTextSize(textSize);
 79         }
 80 
 81         a.recycle();
 82     }
 83 
 84     private final void initLabelView() {
 85         mTextPaint = new Paint();
 86         mTextPaint.setAntiAlias(true);
 87         // Must manually scale the desired text size to match screen density
 88         mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
 89         mTextPaint.setColor(0xFF000000);
 90         setPadding(3, 3, 3, 3);
 91     }
 92 
 93     /**
 94      * Sets the text to display in this label
 95      * @param text The text to display. This will be drawn as one line.
 96      */
 97     public void setText(String text) {
 98         mText = text;
 99         requestLayout();
100         invalidate();
101     }
102 
103     /**
104      * Sets the text size for this label
105      * @param size Font size
106      */
107     public void setTextSize(int size) {
108         // This text size has been pre-scaled by the getDimensionPixelOffset method
109         mTextPaint.setTextSize(size);
110         requestLayout();
111         invalidate();
112     }
113 
114     /**
115      * Sets the text color for this label.
116      * @param color ARGB value for the text
117      */
118     public void setTextColor(int color) {
119         mTextPaint.setColor(color);
120         invalidate();
121     }
122 
123     /**
124      * @see android.view.View#measure(int, int)
125      */
126     @Override
127     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
128         setMeasuredDimension(measureWidth(widthMeasureSpec),
129                 measureHeight(heightMeasureSpec));
130     }
131 
132     /**
133      * Determines the width of this view
134      * @param measureSpec A measureSpec packed into an int
135      * @return The width of the view, honoring constraints from measureSpec
136      */
137     private int measureWidth(int measureSpec) {
138         int result = 0;
139         int specMode = MeasureSpec.getMode(measureSpec);
140         int specSize = MeasureSpec.getSize(measureSpec);
141 
142         if (specMode == MeasureSpec.EXACTLY) {
143             // We were told how big to be
144             result = specSize;
145         } else {
146             // Measure the text
147             result = (int) mTextPaint.measureText(mText) + getPaddingLeft()
148                     + getPaddingRight();
149             if (specMode == MeasureSpec.AT_MOST) {
150                 // Respect AT_MOST value if that was what is called for by measureSpec
151                 result = Math.min(result, specSize);
152             }
153         }
154 
155         return result;
156     }
157 
158     /**
159      * Determines the height of this view
160      * @param measureSpec A measureSpec packed into an int
161      * @return The height of the view, honoring constraints from measureSpec
162      */
163     private int measureHeight(int measureSpec) {
164         int result = 0;
165         int specMode = MeasureSpec.getMode(measureSpec);
166         int specSize = MeasureSpec.getSize(measureSpec);
167 
168         mAscent = (int) mTextPaint.ascent();
169         if (specMode == MeasureSpec.EXACTLY) {
170             // We were told how big to be
171             result = specSize;
172         } else {
173             // Measure the text (beware: ascent is a negative number)
174             result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop()
175                     + getPaddingBottom();
176             if (specMode == MeasureSpec.AT_MOST) {
177                 // Respect AT_MOST value if that was what is called for by measureSpec
178                 result = Math.min(result, specSize);
179             }
180         }
181         return result;
182     }
183 
184     /**
185      * Render the text
186      * 
187      * @see android.view.View#onDraw(android.graphics.Canvas)
188      */
189     @Override
190     protected void onDraw(Canvas canvas) {
191         super.onDraw(canvas);
192         canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, mTextPaint);
193     }
194 }

  The LabelView sample demonstrates a number of different aspects of custom components:

  • Extending the View class for a completely custom component.
  • Parameterized constructor that takes the view inflation parameters (parameters defined in the XML). Some of these are passed through to the View superclass, but more importantly, there are some custom attributes defined and used for LabelView.
  • Standard public methods of the type you would expect to see for a label component, for example setText()setTextSize()setTextColor() and so on.
  • An overridden onMeasure method to determine and set the rendering size of the component. (Note that in LabelView, the real work is done by a private measureWidth() method.)
  • An overridden onDraw() method to draw the label onto the provided canvas.

  You can see some sample usages of the LabelView custom View in custom_view_1.xml from the samples. In particular, you can see a mix of both android: namespace parameters and custom app: namespace parameters. These app: parameters are the custom ones that the LabelView recognizes and works with, and are defined in a styleable inner class inside of the samples R resources definition class.

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <!-- Copyright (C) 2007 The Android Open Source Project
 3 
 4      Licensed under the Apache License, Version 2.0 (the "License");
 5      you may not use this file except in compliance with the License.
 6      You may obtain a copy of the License at
 7   
 8           http://www.apache.org/licenses/LICENSE-2.0
 9   
10      Unless required by applicable law or agreed to in writing, software
11      distributed under the License is distributed on an "AS IS" BASIS,
12      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13      See the License for the specific language governing permissions and
14      limitations under the License.
15 -->
16 
17 <!-- Demonstrates defining custom views in a layout file. -->
18 
19 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
20         xmlns:app="http://schemas.android.com/apk/res/com.example.android.apis"
21         android:orientation="vertical"
22         android:layout_width="match_parent"
23         android:layout_height="wrap_content">
24     
25     <com.example.android.apis.view.LabelView
26             android:background="@drawable/red"
27             android:layout_width="match_parent"
28             android:layout_height="wrap_content" 
29             app:text="Red"/>
30     
31     <com.example.android.apis.view.LabelView
32             android:background="@drawable/blue"
33             android:layout_width="match_parent"
34             android:layout_height="wrap_content" 
35             app:text="Blue" app:textSize="20dp"/>
36     
37     <com.example.android.apis.view.LabelView
38             android:background="@drawable/green"
39             android:layout_width="match_parent"
40             android:layout_height="wrap_content" 
41             app:text="Green" app:textColor="#ffffffff" />
42 
43 </LinearLayout>

4.Compound Controls(用已存在的系统组件自定义一个混合组件)

  If you don't want to create a completely customized component, but instead are looking to put together a reusable component that consists of a group of existing controls, then creating a Compound Component (or Compound Control) might fit the bill. In a nutshell, this brings together a number of more atomic controls (or views) into a logical group of items that can be treated as a single thing. For example, a Combo Box can be thought of as a combination of a single line EditText field and an adjacent button with an attached PopupList. If you press the button and select something from the list, it populates the EditText field, but the user can also type something directly into the EditText if they prefer.

 把系统中现成的组件混合在一起,可以定义一个混合组件,如可以把一个Button和一个EditBox组合在一起成一个,系统中已经用这种思路定义了一些组件,如:Spinner和 AutoCompleteTextView

  In Android, there are actually two other Views readily available to do this: Spinner and AutoCompleteTextView, but regardless, the concept of a Combo Box makes an easy-to-understand example.

  To create a compound component:

4.1 自定义混合组件的步骤

  1. The usual starting point is a Layout of some kind, so create a class that extends a Layout. Perhaps in the case of a Combo box we might use a LinearLayout with horizontal orientation. Remember that other layouts can be nested inside, so the compound component can be arbitrarily complex and structured. Note that just like with an Activity, you can use either the declarative (XML-based) approach to creating the contained components, or you can nest them programmatically from your code.
    第1步是选择一个Layout,如LinearLayout,注意它可以根据一个layout.xml构造,也可全用代码构造。
  2. In the constructor for the new class, take whatever parameters the superclass expects, and pass them through to the superclass constructor first. Then you can set up the other views to use within your new component; this is where you would create the EditText field and the PopupList. Note that you also might introduce your own attributes and parameters into the XML that can be pulled out and used by your constructor.
    构造混合组件中的每一个小组件。
  3. You can also create listeners for events that your contained views might generate, for example, a listener method for the List Item Click Listener to update the contents of the EditText if a list selection is made.
    可以根据业务定义自己的监听器
  4. You might also create your own properties with accessors and modifiers, for example, allow the EditText value to be set initially in the component and query for its contents when needed.
    定义业务成员
  5. In the case of extending a Layout, you don't need to override the onDraw() and onMeasure() methods since the layout will have default behavior that will likely work just fine. However, you can still override them if you need to.
    注意,通常自定义Layout时,无需重写onMeasure,onDraw,它们默认已经可以很好的工作。除非你需要。
  6. You might override other on... methods, like onKeyDown(), to perhaps choose certain default values from the popup list of a combo box when a certain key is pressed.
    重写其它需要的onXXX方法

  To summarize, the use of a Layout as the basis for a Custom Control has a number of advantages, including:

 自定义Layout的优点
  • You can specify the layout using the declarative XML files just like with an activity screen, or you can create views programmatically and nest them into the layout from your code.
    可以从一个layout.xml构造。
  • The onDraw() and onMeasure() methods (plus most of the other on... methods) will likely have suitable behavior so you don't have to override them.
    不用重写onDraw,onMeasure
  • In the end, you can very quickly construct arbitrarily complex compound views and re-use them as if they were a single component.
    可以把它当作一个简单的组件来看。

4.2 Examples of Compound Controls(自定义Layout的示例及它们的位置)

  In the API Demos project that comes with the SDK, there are two List examples — Example 4 and Example 6 under Views/Lists demonstrate a SpeechView which extends LinearLayout to make a component for displaying Speech quotes. The corresponding classes in the sample code are List4.java and List6.java.

 1   /**
 2      * We will use a SpeechView to display each speech. It's just a LinearLayout
 3      * with two text fields.
 4      *
 5      */
 6     private class SpeechView extends LinearLayout {
 7         public SpeechView(Context context, String title, String dialogue, boolean expanded) {
 8             super(context);
 9             
10             this.setOrientation(VERTICAL);
11             
12             // Here we build the child views in code. They could also have
13             // been specified in an XML file.
14             
15             mTitle = new TextView(context);
16             mTitle.setText(title);
17             addView(mTitle, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
18             
19             mDialogue = new TextView(context);
20             mDialogue.setText(dialogue);
21             addView(mDialogue, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
22             
23             mDialogue.setVisibility(expanded ? VISIBLE : GONE);
24         }
25         
26         /**
27          * Convenience method to set the title of a SpeechView
28          */
29         public void setTitle(String title) {
30             mTitle.setText(title);
31         }
32         
33         /**
34          * Convenience method to set the dialogue of a SpeechView
35          */
36         public void setDialogue(String words) {
37             mDialogue.setText(words);
38         }
39         
40         /**
41          * Convenience method to expand or hide the dialogue
42          */
43         public void setExpanded(boolean expanded) {
44             mDialogue.setVisibility(expanded ? VISIBLE : GONE);
45         }
46         
47         private TextView mTitle;
48         private TextView mDialogue;
49     }

5.Modifying an Existing View Type(重写一个现有组件)

  There is an even easier option for creating a custom View which is useful in certain circumstances. If there is a component that is already very similar to what you want, you can simply extend that component and just override the behavior that you want to change. You can do all of the things you would do with a fully customized component, but by starting with a more specialized class in the View hierarchy, you can also get a lot of behavior for free that probably does exactly what you want.

 重写一个现有组件,可以直接继承那些不变的工作,只改变那些特别的行为,这样可以减少大量工作和错误。NotePad就是一个例子。

  For example, the SDK includes a NotePad application in the samples. This demonstrates many aspects of using the Android platform, among them is extending an EditText View to make a lined notepad. This is not a perfect example, and the APIs for doing this might change from this early preview, but it does demonstrate the principles.

  If you haven't done so already, import the NotePad sample into Android Studio (or just look at the source using the link provided). In particular look at the definition of MyEditText in the NoteEditor.java file.

Some points to note here(一些关键点如下:)

  1. The Definition

    The class is defined with the following line:
    public static class MyEditText extends EditText

    • It is defined as an inner class within the NoteEditor activity, but it is public so that it could be accessed as NoteEditor.MyEditText from outside of the NoteEditor class if desired.
    • It is static, meaning it does not generate the so-called "synthetic methods" that allow it to access data from the parent class, which in turn means that it really behaves as a separate class rather than something strongly related to NoteEditor. This is a cleaner way to create inner classes if they do not need access to state from the outer class, keeps the generated class small, and allows it to be used easily from other classes.
    • It extends EditText, which is the View we have chosen to customize in this case. When we are finished, the new class will be able to substitute for a normal EditText view.
  2. Class Initialization

    As always, the super is called first. Furthermore, this is not a default constructor, but a parameterized one. The EditText is created with these parameters when it is inflated from an XML layout file, thus, our constructor needs to both take them and pass them to the superclass constructor as well.

  3. Overridden Methods

    In this example, there is only one method to be overridden: onDraw() — but there could easily be others needed when you create your own custom components.

    For the NotePad sample, overriding the onDraw() method allows us to paint the blue lines on the EditText view canvas (the canvas is passed into the overridden onDraw() method). The super.onDraw() method is called before the method ends. The superclass method should be invoked, but in this case, we do it at the end after we have painted the lines we want to include.

  4. Use the Custom Component

    We now have our custom component, but how can we use it? In the NotePad example, the custom component is used directly from the declarative layout, so take a look at note_editor.xml in the res/layout folder.

    1 <view
    2   class="com.android.notepad.NoteEditor$MyEditText" 
    3   id="@+id/note"
    4   android:layout_width="fill_parent"
    5   android:layout_height="fill_parent"
    6   android:background="@android:drawable/empty"
    7   android:padding="10dip"
    8   android:scrollbars="vertical"
    9   android:fadingEdge="vertical" />
    • The custom component is created as a generic view in the XML, and the class is specified using the full package. Note also that the inner class we defined is referenced using the NoteEditor$MyEditTextnotation which is a standard way to refer to inner classes in the Java programming language.

      If your custom View component is not defined as an inner class, then you can, alternatively, declare the View component with the XML element name, and exclude the class attribute. For example:

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

      Notice that the MyEditText class is now a separate class file. When the class is nested in the NoteEditor class, this technique will not work.

    • The other attributes and parameters in the definition are the ones passed into the custom component constructor, and then passed through to the EditText constructor, so they are the same parameters that you would use for an EditText view. Note that it is possible to add your own parameters as well, and we will touch on this again below.

  And that's all there is to it. Admittedly this is a simple case, but that's the point — creating custom components is only as complicated as you need it to be.

  A more sophisticated component may override even more on... methods and introduce some of its own helper methods, substantially customizing its properties and behavior. The only limit is your imagination and what you need the component to do.

 

 

posted @ 2016-02-16 17:09  f9q  阅读(529)  评论(0编辑  收藏  举报