标签:
Here is a high level overview of what you need to know to get started in creating your own View components:
这里高度概括了一些步骤, 教你如何创建你的自定义组件.
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).
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.
完全自定义的组件可以用来创建任何你想要的图形组件. 也许是一个像电压表的图形计量器, 或者想卡拉OK里面显示歌词的小球随着音乐滚动. 无论怎样, 内置的组件或者他们的组合是无法满足你的需求的.
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).
幸运的是, 你可以以你自己的要求轻松地创建完全属于自己的组件,你会发现不够用的只是你的想象力、屏幕的尺寸和处理器的性能(记住你的应用程序最后只会在那些性能低于桌面电脑的平台上面运行)。
To create a fully customized component:
要创建完全自定义组件:
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() 方法会传递进来一个 Canvas(画布) 对象, 在这个画布上, 你可以绘制任何2D图形, 包括其他的标准或者自定义组件, 有样式的文字, 或者任何你可以想到的东西.
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.
这里不适用3D图形.如果你想使用3D图形, 你必须继承 SurfaceView, 而不是View, 并且要在新线程里绘制.
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() 时要有效地精确地计算出它包含的内容的尺寸.这有点小麻烦,因为我们不但要考虑父类的限制(通过onMeasure()传过来的),同时我们应该知道一旦测量宽度和高度出来后,就要立即调用setMeasuredDimension(int measuredWidth, int measuredHeight) 方法, 把测量好的宽和高设置进去. 如果重写的onMeasure方法里没有调用这个方法, 在测量时会抛异常.
At a high level, implementing onMeasure() looks something like this:
概括说来, 实现 onMeasure 会做以下这些事情:
Measure the view and its content to determine the measured width and the measured height. This method is invoked by measure(int, int) and should be overriden by subclasses to provide accurate and efficient measurement of their contents.
测量view和它里面的内容, 从而确定测量之后的宽度和高度. 这个方法由 measure() 方法调用, 子类应该重写他, 提供精确有效的尺寸.
CONTRACT: When overriding this method, you must call setMeasuredDimension(int, int) to store the measured width and height of this view. Failure to do so will trigger an IllegalStateException, thrown by measure(int, int). Calling the superclass‘ onMeasure(int, int) is a valid use.
约定: 重写这个方法时, 你一定要调用 setMeasuredDimension(int, int) 方法, 用来保存测量之后的宽和高. 否则会抛异常
The base class implementation of measure defaults to the background size, unless a larger size is allowed by the MeasureSpec. Subclasses should override onMeasure(int, int) to provide better measurements of their content.
父类中的实现只是设置了默认的背景大小, 子类要提供更好的测量尺寸.
If this method is overridden, it is the subclass‘s responsibility to make sure the measured height and width are at least the view‘s minimum height and width (getSuggestedMinimumHeight() and getSuggestedMinimumWidth()).
如果子类重写了这个方法, 子类就要负责保证测量后的宽和高要至少要为view对象最小的宽和高.
widthMeasureSpec | horizontal space requirements as imposed(强加的) by the parent. The requirements are encoded with View.MeasureSpec. |
---|---|
heightMeasureSpec | vertical space requirements as imposed by the parent. The requirements are encoded with View.MeasureSpec. |
Here‘s a summary of some of the other standard methods that the framework calls on views:
这里总结了框架会在view上调用的一些其他标准的方法
Category | Methods | Description |
---|---|---|
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. |
The CustomView sample in the API Demos provides an example of a customized View. The custom View is defined in the LabelView class.
API Demos 里的CustomView sample 提供了自定义视图的例子. LabelView类定义了自定义视图.
The LabelView sample demonstrates a number of different aspects of custom components:
LabelView的例子展示了自定义组件的方方面面:
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.
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.
如果你不想完全自定义组件, 而是想把几个已有控件组合成一个可重用的组件, 那么就可以创建一个组合控件. 概括的说, 这就是把一些原子性的控件做合成了一个控件. 比如说, 选择框可以认为是一个单行的et和一个相邻的带弹出列表的按钮的组合.
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.
事实上, 在android中, 还有另外两个视图也是这样: , 但是cb更容易理解.
To create a compound component: 要创建组合控件:
To create a compound component:
To summarize, the use of a Layout as the basis for a Custom Control has a number of advantages, including:
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.
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.
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 Eclipse (or just look at the source using the link provided). In particular look at the definition of MyEditText in the NoteEditor.javafile.
Some points to note here
The class is defined with the following line:
public static class
MyEditText extends EditText
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.
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.
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.
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:
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.
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.
标签:
原文地址:http://www.cnblogs.com/ywq-come/p/5927297.html