Building 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.

안드로이드는 기초적인 레이아웃 클래스인 뷰View와 뷰그룹ViewGroup에 기반해서 여러분의 UI 제작을 위한 정교하고 강력한 컴포넌트화된 모델을 제공한다. 우선 안드로이드 플랫폼은 여러분의 UI를 만드는 데 사용할 수 있는 다양한 미리 만들어진 뷰와 뷰그룹 서브클래스 - 각각은 위젯과 레이아웃이라 불린다 ? 를 포함하고 있다.

A partial list of available widgets includes Button, TextView, EditText, ListView, CheckBox, RadioButton, Gallery, Spinner, and the more special-purpose AutoCompleteTextView, ImageSwitcher, and TextSwitcher.

사용가능한 위젯의 일부 리스트에는 Button, TextView, EditText, ListView, CheckBox, RadioButton, Gallery, Spinner, 그리고 더 특수한 목적의 AutoCompleteTextView,ImageSwitcher, 그리고 TextSwitcher가 포함된다.

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

사용가능한 레이아웃에 속하는 것에는 LinearLayout, FrameLayout, RelativeLayout, 그리고 그 밖의 것들이 있다. 더 많은 예제들에 대해서는 “일반적인 레이아웃 오브젝트”를 보라..

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).
  • 여러분은 완전하게 직접 렌더링 된custom-rendered 뷰 타입, 예를 들어 아날로그 전자 장치와 비슷한 2D 그래픽을 사용해 만들어진 “볼륨 제어volume control” 손잡이를 만들 수 있다.
  • 여러분은 아마 콤보박스ComboBox(팝업 리스트와 프리 텍스트 입력 필드의 조합), 듀얼-페인 실렉터 컨트롤dual-pane selector control(왼쪽과 우른쪽 판 각각에 리스트를 가지고, 그 리스트의 아이템을 다른 곳에 재지정할 수 있는 것) 등과 같은 어떤 것을 만들기 위해, 새로운 하나의 컴포넌트 안으로 뷰 컴포넌트의 그룹을 조합할 수 있다.
  • 여러분은 EditText 컴포넌트의 스크린 렌더링 방식을 오버라이드 할 수 있다 (노트패드(Notepad) 튜토리얼은 페이지에 멋진 효과와 밑줄을 주기 위해 이것을 사용한다).
  • 여러분은 키 입력과 같은 다른 이벤트를 캡쳐할 수 있으며, 그것을 약간의 커스텀 방식으로 제어할 수 있다(게임에서 처럼).

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

아래의 섹션은 커스텀 뷰를 만드는 방법과 여러분의 애플리케이션에서 그것을 사용하는 방법을 설명한다. 더 자세한 레퍼런스 정보에 대해서는, 뷰View 클래스를 보라.

The Basic Approach

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

여기에 있는 것은 여러분 자신의 뷰 컴포넌트를 생성하기 위해 알아야 할 필요가 있는 것에 대한 상위 레벨에서의 개요이다.

  1. Extend an existing View class or subclass with your own class.
  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 in Activity or ListActivity that you override for lifecycle and other functionality hooks.
  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.
  1. 여러분 자신의 클래스를 사용해서 기존의 뷰View 클래스 또는 서브클래스를 확장extend하라.
  2. 슈퍼클래스의 몇몇 메쏘드를 오버라이드 하라. 오버라이드 할 슈퍼클래스 메쏘드들은 ‘on’으로 시작한다. 예를 들어 onDraw(), onMeasure(), 그리고 onKeyDown()이 그것이다. 이것은 여러분이 액티비티Activity 또는 리스트액티비티ListActivity에서 생명주기를 오버라이드해서 다른 기능들을 추가하는 on...events와 유사하다.
  3. 러분의 새로운 확장 클래스를 사용하라. 일단 완성되면, 여러분의 새로운 확장 클래스는 그것의 기반이 되었던 뷰를 대신해서 사용될 수 있다.

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).

Tip: 확장 클래스는 액티비티 내에 내부inner 클래스로 정의될 수 있다. 이것은 그것에 대한 접근을 통제하기 때문에 유용하다. 하지만 필수사항은 아니다(여러분은 아마 여러분 애플리케이션 내에서 더 넓게 사용할 새로운 public 뷰를 만들고자 할 것이다).

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.

완전하게 커스터마이즈된 컴포넌트는, 여러분이 원하는 것이 어떤 것이든 보여줄 수 있는 그래픽컬한 컴포넌트를 제작하기 위해 사용될 수 있다. 여러분이 오래된 아날로그 게이지gauge처럼 보이는 그래픽한 VU 미터를 원하거나, 또는 여러분이 가라오케 머신을 가지고 노래할 수 있도록 단어를 따라 움직이는 바운싱bouncing 볼이 있는 sing-a-long 텍스트 뷰를 원한다고 가정하자. 어떤 쪽이든, 여러분이 원하는 것은 내장된built-in 컴포넌트를 어떻게 결합combine하더라도 할 수 없는 것이다.

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:

완전하게 커스터마이즈된 컴포넌트를 생성하기 위해서:

  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.
  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.)
  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.
  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.
  5. Other on... methods may also be overridden as required.
  1. 여러분이 확장할 수 있는 가장 일반적인 뷰는 놀랍지 않게도 뷰View이다. 그러므로 여러분의 새로운 슈퍼 컴포넌트를 만들기 위해, 여러분은 보통 이것을 확장하는 것에서 시작할 것이다.
  2. 여러분은 XML 내에 애트리뷰트와 파라미터를 가질 수 있는 생성자를 제공할 수 있다. 그리고 여러분 자신의 그러한 애트리뷰트와 파라미터를 또한 사용할 수 있다(아마도 VU 미터의 컬러과 범위, 또는 바늘의 너비와 민감함 등이 이에 속할 것이다).
  3. 여러분은 아마도 여러분 자신의 이벤트 리스너listener, 속성 접근자accessor 및 수정자modifier, 그리고 추가적으로 가능하다면 여러분의 컴포넌트 클래스 안에 보다 더 정교한 동작을 생성하고자 할 것이다.
  4. nbsp;만약 여러분이 어떤 것을 보여주기 위한 컴포넌트를 원한다면, 여러분은 거의 확실히 onMeasure()를 오버라이드하길 원할 것이며, 또한 onDraw()를 오버라이드할 것이다. 둘 다 모두 디폴트 작동구조를 가지고 있지만, 디폴트 onDraw()는 아무 것도 하지 않을 것이며, 디폴트 onMeasure()는 항상 100x100 크기 - 아마 여러분이 원하는 것이 아닌 것 ? 를 설정할 것이다.
  5. 다른 on...메쏘드들 또한 필요에 따라 오버라이드 될 수 있다.

Extend onDraw() and 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() 메쏘드는 여러분에게 캔버스Convas를 파라미터로 전달하며, 그 캔버스 위에 여러분이 원하는 어떤 것, 즉 2D 그래픽, 다른 표준 또는 커스텀 컴포넌트, 스타일드styled 텍스트, 또는 그 밖의 여러분이 생각할 수 있는 어떤 것이든 구현할 수 있다.

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 seperate thread. See the GLSurfaceViewActivity sample for details.

Note: 이것은 3D 그래픽에는 적용되지 않는다. 만약 여러분이 3D 그래픽을 이용하고 싶다면, 여러분은 뷰 대신에 서피스뷰(SurfaceView)를 확장해야만 하고, 별도의 쓰레드에서 그리기를 해야 한다. 보다 자세한 것에 대해서는 GLSurfaceViewActivity 예제를 보라.

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()는 그것이 포함하고 있는 영역을 효과적이고 정확하게 측정해서 레포트하도록 오버라이드 되어야 한다. 이것은 (onMeasure() 메쏘드에 전달된 파라미터 안에 있는) 부모parent의 요구조건과 일단 계산되어졌던 측정된 너비measured width와 높이measured height를 가지고 setMeasuredDimension() 메쏘드를 호출하는 요구조건에 의해, 약간 더 복잡하게 만들어진다. 만약 여러분이 오버라이드한 onMeasure() 메쏘드에서 이 메쏘드를 호출하지 않는다면, 그 결과는 측정 시점에 예외exception가 될 것이다.

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

상위 레벨에서 볼 때At a high level, onMeasure()를 구현하는 것은 아래와 같이 보인다.

  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).
  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).
  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.
  1. 오버라이드된 onMeasure() 메쏘드는 너비width와 높이height에 대한 측정명세Measure Specification를 파라미터로 가지고 호출된다(측정 명세는 widthMeasureSpec와 heightMeasureSpec 으로 구성되며, 두가지 모두 크키를 나타내는 정수(integer) 코드이다). 측정명세는 여러분이 산출해야 하는 너비와 높이 치수measurement에 대한 제약 요건으로 취급되어야 한다. 이러한 명세가 요구할 수 있는 제약의 종류에 대한 전체 레퍼런스는 View.onMeasure(int, int) 아래의 레퍼런스 문서에서 찾을 수 있다(이 레퍼런스 문서는 또한 전체적인 치수 오퍼레이션을 설명하는 매우 좋은 일을 한다).
  2. 여러분 컴포넌트의 onMeasure() 메쏘드는 컴포넌트를 렌더링하기 위해 요구되는 너비와 높이 치수measurement를 계산해야 한다. 그것은 비록 onMeasure()에 전달된 그 명세의 범위를 초과exceed할 수 있음에도 불구하고, 그 명세 범위 내에 머무르도록 노력해야 한다(명세를 넘어서는 경우, 그 부모(parent)는 잘라내기, 스크롤링, 예외(exception) 발생, 또는 아마 다른 측정 명세를 사용해서 다시 시도하기 위한 onMeasure() 호출을 포함하는 어떤 것을 선택할 수 있다).
  3. 일단 너비와 높이가 계산되면 setMeasuredDimension(int width, int height) 메쏘드가 계산된 치수를 가지고 호출되어야 한다. 이것을 하지 않으면, 예외가 발생할 것이다.

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

여기에, 뷰에서 프레임워크가 호출하는 일부 다른 표준 메쏘드들의 개요가 있다.

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.

A Custom View Example

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 샘플은 커스터마이징된 뷰의 예제를 제공한다. 커스텀 뷰는 LabelView 클래스에서 정의된다.

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

LabelView 샘플은 커스텀 컴포넌트의 다양한 다른 측면을 보여준다.

  • 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.
  • 완전한 커스텀 컴포넌트를 위한 뷰 클래스를 확장하기.
  • 파라미터화된 생성자는 뷰 인플레이션inflation 파라미터(XML에서 정의된 파라미터)를 가진다. 이것들 중 일부는 뷰 슈퍼클래스에게 전달된다. 그러나 더 중요하게도, LabelView를 위해 정의된 몇 가지 커스텀 애트리뷰트가 있다.
  • 라벨label 컴포넌트에 대해 여러분이 보고자 할 타입에 대한 표준 퍼블릭public 메쏘드. 예를 들어 setText(), setTextSize(), setTextColor() 등이 있다.
  • 컴포넌트의 렌더링 크기를 결정 및 설정하기 위해 오버라이드된 onMeasure() 메쏘드(LabelView에서 private measureWidth() 메쏘드에 의해 실제 작업이 이루어진다는 것에 주의하라).
  • 제공된 캔버스Canvas위에 라벨label을 그리기 위해 오버라이드된 onDraw() 메쏘드.

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.

여러분은 그 샘플의 custom_view_1.xml 안에서 LabelView 커스텀 뷰의 몇가지 샘플 사용법을 볼 수 있다. 특히, 여러분은 android: 네임스페이스 파라미터와 커스텀 app: 네임스페이스 파라미터 두 가지의 혼합을 볼 수 있다. 이러한 app: 파라미터는 LabelView가 인식하고 그것을 가지고 작업하는 커스텀 파라미터이며, 샘플에 대한 R 리소스 정의 클래스의 styleable 내부inner 클래스에서 정의된다.

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.

만약 여러분이 완벽하게 커스터마이즈된 컴포넌트를 생성하는 것을 원하지 않고, 대신 기존에 있는 컨트롤 그룹을 구성하는 재사용가능한 컴포넌트를 함께 배치하고자 한다면, 합성 컴포넌트(혹은 합성 컨트롤)를 만드는 것이 여러분의 기대를 충족시킬 수 있다. 간단하게 말해서, 이것은 하나로 취급될 수 있는 아이템들의 논리적 그룹안에 다수의 더 원자적인atomic 컨트롤(또는 뷰)를 합쳐 놓는다. 예를 들어 콤보 박스는 단일 라인 EditText 필드에 PopupList가 붙은 인접한 버튼의 조합으로 생각될 수 있다. 만약 여러분이 버튼을 누르거나 리스트로부터 무언가를 선택한다면, 그것은 EditText 필드에 존재할 것이다. 하지만 사용자들은 또한 원하다면 EditText 안에 직접적으로 어떤 것을 입력할 수 있다.

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.

안드로이드에는, 이것을 하기 위해 이미 사용가능한 두 개의 다른 뷰가 실제로 존재한다. Spinner와 AutoCompleteTextView가 그것이다. 하지만 이와 상관없이 콤보박스 개념은 이해하기 쉬운 예제를 제공한다.

To create a compound component:

합성 컴포넌트를 생성하기 위해서:

  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.
  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.
  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.
  1. 일반적인 시작점은 어떤 종류의 레이아웃이다. 그러므로 하나의 레이아웃을 확장하는 클래스를 생성하라. 아마도 콤보박스의 경우에, 우리는 수평horizontal 오리엔테이션을 가진 LinearLayout를 사용할 수 있을 것이다. 그 합성 컴포넌트가 임의로 복잡하게 구조화될 수 있도록, 다른 레이아웃이 그 안에 포함될nested 수 있다는 것에 유념하라. 마치 액티비티에서와 같이, 여러분은 포함된 컴포넌트를 생성하기 위해 (XML 기반의)선언 방식을 사용하거나, 또는 여러분의 코드에서 그것을 프로그램적으로 포함할nest 수 있다는 것에 주목하라.
  2. 새로운 클래스에 대한 생성자에서, 슈퍼클래스가 기대하는 파라미터가 무엇이든 그것을 얻은 후, 먼저 슈퍼클래스 생성자에게 그것을 전달하라. 그런 다음, 여러분의 새로운 컴포넌트 안에서 사용할 다른 뷰를 구성할 수 있다; 이곳이 여러분의 EditText 필드와 PopupList를 생성할 장소이다. 여러분은 또한 XML안에 여러분 자신의 애트리뷰트와 파라미터를 도입할 수 있으며, 그것을 가져와서 여러분의 생성자가 사용할 수 있다는 것에 주목하라.
  3. 여러분은 또한 여러분이 보유한 뷰가 발생시킬 지도 모르는 이벤트에 대한 리스너listener를 생성할 수 있다. 예를 들어 만약 리스트가 선택되면, EditText의 내용을 업데이트하기 위한 리스트 아이템 클릭 리스너에 대한 리스너 메쏘드를 생성할 수 있다.
  4. 여러분은 또한 접근자accessor와 수정자modifier를 사용해서 여러분 자신의 속성들을 생성할 수 있다. 예를 들어 EditText 값이 컴포넌트 초기에 설정되도록 하고 필요할 때 그것의 내용물content을 요청query하도록 할 수 있다.
  5. 이아웃을 확장하는 경우에, 여러분은 onDraw()와 onMeasure() 메쏘드를 오버라이드 할 필요는 없다. 왜냐하면 그 레이아웃은 훌륭하게 작업할 수 있는 디폴트 작동구조을 가지고 있기 때문이다. 하지만 필요하다면 여러분은 여전히 그것을 오버라이드 할 수 있다.
  6. 여러분은 특정 키가 눌려졌을 때, 콤보박스의 팝업 리스트에서 특정 디폴트 값을 선택하기 위해 onKeyDown()과 같은 다른 on...메쏘드를 오버라이드 할 수도 있다.

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

요약하면, 커스텀 컨트롤에 대한 기초로 레이아웃을 사용하는 것은 다음과 같은 다양한 장점을 가진다.

  • 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.
  • 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.
  • In the end, you can very quickly construct arbitrarily complex compound views and re-use them as if they were a single component.
  • 여러분은 액티비티 스크린에서와 같이 XML 선언 파일을 사용하여 레이아웃을 지정할 수 있으며, 또한 뷰를 프로그램적으로 생성해서 여러분 코드의 레이아웃에 그것을 포함할 수 있다.
  • onDraw()와 onMeasure() 메쏘드(더불어 다른 모든 on...메쏘드)는 여러분이 그것을 오버라이드 할 필요가 없도록 적절하게 동작할 것이다.
  • 끝으로, 여러분은 아주 빠르고 임의로 복잡한 합성 뷰를 생성할 수 있고, 마치 그것들이 단일 컴포넌트인 것처럼 그것을 재사용할 수 있다.

Examples of Compound Controls

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.

SDK에 포함되어 있는 API Demos 프로젝트에서는 두 개의 리스트 예제가 있다 ? Views/Lists 아래에 있는 Example4와 Example6은 SpeechView를 보여준다. 그것은 연설문을 보여주는 컴포넌트를 만들기 위해 LinearLayout를 확장하고 있다. 샘플 코드 안의 각각에 대응되는 클래스는 List4.java와 List6.java이다.

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 heirarchy, you can also get a lot of behavior for free that probably does exactly what you want.

어떤 상황에 유용한 커스텀 뷰를 생성하기 위한 더 쉬운 방법도 있다. 만약 여러분이 원하는 것과 매우 비슷한 컴포넌트가 이미 존재한다면, 여러분은 그 컴포넌트를 간단하게 확장extend해서 여러분이 바꾸고 싶어하는 것을 오버라이드 할 수 있다. 여러분은 완전하게 커스터마이즈된 컴포넌트를 사용해서 여러분이 원하는 모든 것을 할 수 있다. 그러나 뷰 계층구조에 더 전문화된 클래스를 사용함으로써, 여러분이 원하는 것을 아마도 정확하게 수행하는 더 많은 동작을 무상으로 또한 얻을 수 있다.

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.

예를 들어 SDK 샘플 안에는 노트패드NotePad 애플리케이션이 포함되어 있다. 이것은 안드로이드 플랫폼을 사용하는 것의 다양한 측면을 보여준다. 그것들 중에는 밑줄이 있는 노트패드를 만들기 위해 EditText 뷰를 확장한 것이 있다. 이것은 완벽한 예제는 아니다. 그리고 이것에 대한 그 API는 이전 버전의 형태와 다르게 변경될 수도 있다. 하지만 그것은 그 원리를 설명한다.

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.java file.

여러분이 아직 사용해 보지 않았다면, 노트패드 샘플을 이클립스 안으로 가져와라(또는 제공된 링크를 사용해 소스를 보라). 특별히 NoteEditor.java 파일에 있는 MyEditText(역주: 현재는 LineEditText로 변경되어 있음)의 정의를 살펴보라.

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.

    <view
      class="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" />
    
    • 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$MyEditText notation 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.
  1. 정의The Definition

    그 클래스는 아래의 줄로 정의된다.public static class MyEditText extends EditText

    • 이것은 NoteEditor 액티비티 내의 내부inner 클래스로 정의된다. 그러나 만약 필요하다면 NoteEditor 클래스의 외부에서 NoteEditor.MyEditText를 사용해서 접근될 수 있도록 퍼블릭public 으로 선언되어 있다.
    • 이것이 정적static으로 선언되었다는 것은, 그것이 부모parent 클래스로부터의 데이터에 대한 접근을 가능하게 하는 “통합적synthetic 메쏘드”라 불리는 것을 만들어내지 않음을 의미한다. 이것은 NoteEditor와 강하게 연결된 클래스라기 보다는 오히려 분리된 클래스로써 실제로 동작한다는 것을 의미한다. 이것은 메쏘드들이 외부 클래스로부터의 접근을 필요로 하지 않는다면 내부inner 클래스들을 생성하기 위한 더 깨끗한 방법이고, 생성된 클래스를 작게 유지하며 그 클래스를 다른 클래스로부터 쉽게 사용되도록 허용한다.
    • 이것은 EditText를 확장한다. 이 경우에, 이것은 우리가 커스터마이즈하기 위해 선택한 뷰가 된다. 우리가 끝냈을 때, 새로운 클래스는 보통의 EditText 뷰를 대체하는 것이 가능하게 될 것이다.
  2. 클래스 초기화Class Initialization

    항상 그렇듯이 super가 먼저 호출된다. 더 나아가, 이것은 디폴트 생성자가 아니라 파라미터화된 생성자이다. EditText는 그것이 XML 레이아웃 파일로부터 인플레이트inflate 될 때 이러한 파라미터들을 가지고 생성된다. 따라서, 우리의 생성자는 파라미터들을 얻는 것과 더불어 그것들을 슈퍼클래스 생성자에게 전달하는 것, 둘 다를 필요로 한다.

  3. 오버라이드된 메쏘드Overridden Methods

    이 예제에는, 오버라이드된 하나의 메쏘드, 즉 onDraw()만이 있을 뿐이다 - 하지만 여러분 자신의 커스텀 컴포넌트를 만들 때 필요한 다른 것들이 쉽게 있을 수도 있다.

    노트패드 샘플에 대해, onDraw() 메쏘드를 오버라이드하는 것은 우리가 EditText 뷰 캔버스Canvas 위에 파란색 라인을 그리는 것을 가능하게 한다(캔버스는 오버라이드된 onDraw() 메쏘드에 전달된다). super.onDraw() 메쏘드는 그 메쏘드가 끝나기 전에 불려져야 한다. 그 슈퍼클래스 메쏘드는 불려져야 한다. 하지만 이런 경우에 우리는 우리가 포함하고 싶은 선을 그린 후 끝에서 그것을 한다.

  4. 커스텀 컴포넌트 사용하기Use the Custom Component

    우리는 이제 우리의 커스텀 컴포넌트를 가지고 있다. 그러나 우리가 그것을 어떻게 사용할 수 있을까? 노트패드Nodepad 예제 안에서 커스텀 컴포넌트는 레이아웃 선언에서 직접 사용된다. res/layout 폴더에 있는 note_editor.xml를 살펴보라.

    <view
      class="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에 있는 일반적인 뷰로써 생성된다. 그리고 해당 클래스는 전체 패키지를 사용해서 지정된다. 또한 우리가 정의한 내부inner 클래스는 자바 프로그램 언어에서 내부inner 클래스를 레퍼런스하는 표준 방법인 NoteEditor$MyEditText 표기법을 사용하여 레퍼런스된다는 것에 유의하라.

      만약 여러분의 커스텀 뷰 컴포넌트가 내부inner 클래스로 정의되지 않는다면, 여러분은 대신에 XML 엘리먼트 이름을 가진 뷰 컴포넌트를 선언할 수 있으며, class 애트리뷰트를 제외시킬 수 있다. 예를 들어 다음과 같다.

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

      MyEditText 클래스는 이제 분리된 클래스 파일이라는 것을 주의하라. 클래스가 NoteEditor 클래스에서 포함될 경우, 이 기법technique은 동작하지 않을 것이다.

    • 그 정의 안에 있는 다른 애트리뷰트와 파라미터는 커스텀 컴포넌트 생성자에게 전달되는 것이며, 그리고 난 다음 EditText 생성자에게 전달된다. 그러므로 그것들은 여러분이 EditText 뷰에서 사용하는 것과 동일한 파라미터들이다. 마찬가지로 여러분 자신의 파라미터를 추가하는 것이 가능하다. 그리고, 우리는 다음에 이것을 다시 다룰 것이다.

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.

더 정교한 컴포넌트는 심지어 더 많은 on... 메쏘드들을 오버라이드 할 지도 모르며, 실제로 그것의 속성과 동작을 커스터마이징하여 그것 자신의 보조 메쏘드들 일부를 도입할 수 있다. 유일한 한계는 여러분의 상상력과 여러분이 그 컴포넌트로 하여금 무엇을 하도록 하느냐이다.

↑ Go to top

← Back to User Interface