안드로이드 Custom View를 이용하여 Custom Android Button 만들기 어플 개발 / 안드로이드

2010/04/22 12:33

복사 http://blog.naver.com/mygirl2/40105201905

출처 : http://androidcore.com/index.php?option=com_content&view=article&id=235&Itemid=106

 

Making a custom Android button using a custom view

 

Creating a custom view is as simple as inheriting from the View class and overriding the methods that need to be overridden. In this example, a custom button is implemented in this way. The button shall feature a labelled image (i.e. an image with text underneath).

 

사용자 정의 뷰(View)를 이용하여 사용자 정의 버튼(안드로이드용) 만들어 보기

 

사용자 정의 뷰(View)를 생성하는 것은 뷰 클래스를 상속하는 것만큼 쉽다. 그리고 오버라이드(Override) 해야 할 메소드를 오버라이드하는 것 만큼...

의역하면, 뷰 클래스를 상속하고 오버라이드 해줘야 할 부분만 오버라이드 해주면 되니까 사용자 정의 뷰를 만드는 것이 굉장히 쉽다는 얘기이다.

예를 들면, 사용자 정의 버튼은 이런 방식으로 구현이 되는데... 다음의 예제에서는 사용자 정의 버튼이 라벨이 표시되는 이미지와 밑에 텍스트가 추가되는 특징을 갖게 된다. 그럼 예제를 보자...



1   public class CustomImageButton extends View {
2       private final static int WIDTH_PADDING = 8;
3       private final static int HEIGHT_PADDING = 10;
4       private final String label;
5       private final int imageResId;
6       private final Bitmap image;
7       private final InternalListener listenerAdapter = new InternalListener();
8
 

The constructor can take in the parameters to set the button image and label.

 

생성자는 버튼 이미지와 라벨을 설정하기 위해 파라미터를 받을 수 있다.


9       /**
10       * Constructor.
11       *

// 생성자


12       * @param context
13       *        Activity context in which the button view is being placed for.

 

// 버튼 뷰가 배치되는 액티비티 문맥(context)

 

14       *
15       * @param resImage
16       *        Image to put on the button. This image should have been placed
17       *        in the drawable resources directory.

// 버튼에 이미지를 추가하기. 이 이미지는 drawable 리소스 디렉토리에 배치(보관, 저장?)되어야 한다.

 

18       *
19       * @param label
20       *        The text label to display for the custom button.
21       */

 

// 사용자 정의 버튼에서 표시될 텍스트 라벨


22      public CustomImageButton(Context context, int resImage, String label)
23       {
24           super(context);
25           this.label = label;
26           this.imageResId = resImage;
27           this.image = BitmapFactory.decodeResource(context.getResources(),
28                  imageResId);
29 
30           setFocusable(true);
31           setBackgroundColor(Color.WHITE);
32
33           setOnClickListener(listenerAdapter);
34           setClickable(true);
35       }
36
 

With the constructor defined, there are a number of methods in the View class that needs to be overridden to this view behave like a button. Firstly, the onFocusChanged gets triggered when the focus moves onto or off the view. In the case of our custom button, we want the button to be “highlighted” when ever the focus is on the button.

 

생성자가 정의 되고 나서 뷰 클래스는 몇가지 메소드들이 있다는 것도 고려해야 한다. 그것은 뷰 클래스에서 버튼과 같은 뷰가 가져야 할 것을 오버라이드해줘야 한다는 것이다. (위에 서두에 언급했던 내용...)

 

첫번째로 onFocusChanged 메소드는 발동을 언제하냐면, 포커스가 On되거나 Off될때이다. 뷰에서 대한 포커스 말이다.

여기에서 언급되는 사용자 정의 버튼의 경우, 버튼이 하이라이트(highlighted)되는 기능이 필요한데, 포커스가 버튼에 맞춰졌을때(Focus On 되었을때) 말이다.

 


49          {
50              this.setBackgroundColor(Color.WHITE);
51          }
52      }
53     
 

The method responsible for rendering the contents of the view to the screen is the draw method. In this case, it handles placing the image and text label on to the custom view.

 

setBackgroundColor() 메소드는 뷰의 내용들을 표현하는 메소드인데, 스크린에 표현하게 된다. 이 메소드는 draw 메소드 계열이다.

여기서 소개된 이 메소드는 이미지와 텍스트 라벨을 사용자 정의 뷰에 배치하는 것을 조정(컨트롤)한다.

 


54      /**
55       * Method called on to render the view.
56       */
57      protected void onDraw(Canvas canvas)
58      {
59          Paint textPaint = new Paint();
60          textPaint.setColor(Color.BLACK);
61          canvas.drawBitmap(image, WIDTH_PADDING / 2, HEIGHT_PADDING / 2, null);
62          canvas.drawText(label, WIDTH_PADDING / 2, (HEIGHT_PADDING / 2) +
63                  image.getHeight() + 8, textPaint);
64      }
65     
 

For the elements to be displayed correctly on the screen, Android needs to know the how big the custom view is. This is done through overriding the onMeasure method. The measurement specification parameters represent dimension restrictions that are imposed by the parent view.

 

요소들(elements)들이 화면에 제대로 표현되기 위해서 안드로이드는 사용자 정의 뷰의 크기가 얼마나 되는지에 대한 정보를 필요로 한다.

아래의 경우 onMeasure 메소드를 오버라이딩한 것이다. measurement(측정) 상세 내용(스펙) 파라미터는 부모 뷰(View)로 부터 결정된(강요된? 강제로 결정된?) 치수 제한을 나타낸다.

 


 66        @Override
 67        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
 68        {
 69         setMeasuredDimension(measureWidth(widthMeasureSpec),
 70                 measureHeight(heightMeasureSpec));
 71        }
 72   
 

The call to setMeasuredDimension in the onMeasure method is important. The documentation states that the call is necessary to avoid a IllegalStateException.

 

onMeasure 메소드 내에서 setMeasuredDimension() 메소드를 호출하는 것은 중요하다. 그 이유는 illegalStateException이 발생하는 것을 피하기 위해서이다. 이 메소드의 호출이 말이다. (문서에 표시된 내용 - 어떤 문서?)

 


 73     private int measureWidth(int measureSpec)
 74     {
 75         int preferred = image.getWidth() * 2;
 76         return getMeasurement(measureSpec, preferred);
 77     }
 78   
 79     private int measureHeight(int measureSpec)
 80     {
 81         int preferred = image.getHeight() * 2;
 82         return getMeasurement(measureSpec, preferred);
 83     }
 84   
 

To calculate the width and height measurements, I’ve chosen to keep the logic simple by using a simple formula to calculate the dimensions. This simple formula computes the dimensions based on the dimensions of the image. The measureSpec parameter specifies what restrictions are imposed by the parent layout.

 

가로폭과 세로높이 측정값을 계산하기 위해서, 이 글을 쓴 사람은 치수를 계산 하기 위한(할 수 있는) 간단한 공식을 이용했고 그렇게 한 이유는 프로그램 로직을 간결하게 유지하기 위한 방법이라고 생각했기 때문이다.

이 간단한 공식은 이미지의 치수에 기초(기반)을 둔 치수를 산출한다.(compute 뜻 까먹었었는데, 긴가민가했는데 찍었는데 맞췄다. ㅇㅇ)

measureSpec 파라미터는 부모 레이아웃으로 강요된 제한들을 명시한다.

 


 85     private int getMeasurement(int measureSpec, int preferred)
 86     {
 87         int specSize = MeasureSpec.getSize(measureSpec);
 88         int measurement = 0;
 89       
 90         switch(MeasureSpec.getMode(measureSpec))
 91         {
 92             case MeasureSpec.EXACTLY:
 93                 // This means the width of this view has been given.
 

// 이것은 주어진 뷰(View)의 가로폭을 의미한다.

 

 94                 measurement = specSize;
 95                 break;
 96             case MeasureSpec.AT_MOST:
 97                 // Take the minimum of the preferred size and what
 98                 // we were told to be. 

 

// 원하는 크기(size)의 최소값을 얻어라

// 뭔가 되기 위해서? 되어햐 할 것들에 대해 듣는 것.. (코드를 봐야 이해할 것 같다. 일단 나중에..)

 

 99                 measurement = Math.min(preferred, specSize);
100                 break;
101             default:
102                 measurement = preferred;
103                 break;
104         }
105   
106         return measurement;
107     }
108
 

To make the customised button useful, it needs to trigger some kind of action when it is clicked (i.e. a listener). The view class already defines methods for setting the listener, but a more specialised listener could be better suited to the custom button. For example, the specialised listener could pass back information on the instance of the custom button.

 

사용자 정의 버튼을 유용하게 만들기 위해서는 사용자 버튼에 몇가지 종류의 액션(Action)을 발동 시키는 것이 필요한데, 예를들어 리스너(listener)등으로 클릭했을 때 말이다.

뷰(View) 클래스의 경우 이미 리스너 설정에 필요한 메소드들을 정의되어 있다.

하지만 좀 더 특별하고 뛰어나다고 할까? 이러한 리스너는 사용자 정의 버튼에 좀 더 최적화 될 수 있다.

예를 들면, 이 특별한 리스너는 정보를 돌려줄 수 있는데, 사용자 정의 버튼의 객체(instance)에 말이다.


109     /**
110      * Sets the listener object that is triggered when the view is clicked.

 

// 리스너 객체를 설정하라. 뷰가 클릭되었을때 발동되는 리스너 객체 말이다.

 

111      *
112      * @param newListener
113      *        The instance of the listener to trigger.

 

// 발동되는 리스너 객체..

 

114      */
115     public void setOnClickListener(ClickListener newListener)
116     {
117         listenerAdapter.setListener(newListener);
118     }
119   
 

If the custom listener passes information about this instance of the custom button, it may as well have accessors so listener implementation can get useful information about this custom button.

 

사용자 정의 리스너가 사용자 정의 버튼 객체에 대한 정보를 제공한다면, 사용자 정의 리스너는 접근자를 가질지도 모른다. 리스너 구현하는 것이 사용자 정의 버튼에 대한 유용한 정보를 제공 할 수 있도록 말이다.

(의역하면, 사용자 정의 리스너가 사용자 정의 버튼 객체에 대해 뭔가를 제공한다면 전달하거나... 그러면 구현하는 리스너가 사용자 정의 버튼에 대해 유용한 정보를 가질 수 있도록 접근자를 가질지도 모른다는 의미가 될 것 같다. 코드를 안 보고 번역하니 헤깔린다.)


120     /**
121      * Returns the label of the button.

 

// 라벨 버튼을 반환하기


122      */
123     public String getLabel()
124     {
125         return label;
126     }
127   
128     /**
129      * Returns the resource id of the image.
130      */

 

// 이미지의 리소스 아이디(id)를 반환하기


131     public int getImageResId()
132     {
133         return imageResId;
134     }
135   
 

Finally, for our custom button class that is using a custom listener, the custom listener class needs to be defined.

 

마지막으로 사용자 정의 리스너를 사용하고 있는 여기에 소개된 사용자 정의 버튼에 대해 사용자 정의 리스너 클래스가 정의되어야 한다는 것을 말해두고 싶다.

 


136     /**
137      * Internal click listener class. Translates a view’s click listener to
138      * one that is more appropriate for the custom image button class.

 

/* 내부의 클릭 리스너 클래스(이것이 익명 클래스라고 불리기도 하는건가? 안 찾아봐서 잘 모르겠다.)

뷰(View)의 클래스를 전환(변환)해야 하는데, 사용자 정의 버튼 클래스에 좀 더 적합한 것으로 말이다.

(위에 설명된 translate라는 단어는 번역이라기 보다는 전환(변환)이 맞을 것 같다.) */

 

 

139      *
140      * @author Kah
141      */
142     private class InternalListener implements View.OnClickListener
143     {
144         private ClickListener listener = null;
145   
146         /**
147          * Changes the listener to the given listener.

 

리스너를 주어진 리스너로 변경해라


148          *
149          * @param newListener
150          *        The listener to change to.

 

바꿀 리스너

 

151          */
152         public void setListener(ClickListener newListener)
153         {
154             listener = newListener;
155         }
156       
157         @Override
158         public void onClick(View v)
159         {
160             if (listener != null)
161             {
162                 listener.onClick(CustomImageButton.this);
163             }
164         }
165     }
166    }
167  

+ Recent posts