뷰 클래스 만들기

잘 설계된 맞춤 뷰는 잘 설계된 다른 클래스와 매우 유사합니다. 즉, 사용하기 쉬운 인터페이스로 특정 기능 집합을 캡슐화하고 CPU와 메모리를 효율적으로 사용하는 등의 특징이 있습니다. 그러나 맞춤 뷰는 잘 설계된 클래스이어야 할 뿐 아니라 다음 사항을 충족해야 합니다.

  • Android 표준 준수
  • Android XML 레이아웃에서 작동하는 맞춤 스타일 속성 제공
  • 접근성 이벤트 전송
  • 여러 Android 플랫폼과 호환

Android 프레임워크에서는 이 모든 요구사항을 충족하는 뷰를 만드는 데 도움이 되는 일련의 기본 클래스 및 XML 태그를 제공합니다. 이 과정에서는 Android 프레임워크를 사용하여 뷰 클래스의 핵심 기능을 만드는 방법에 관해 설명합니다.

이 과정 외에도 맞춤 구성요소에서 이와 관련된 추가 정보를 얻으실 수 있습니다.

뷰의 서브클래스 만들기

Android 프레임워크에 정의된 모든 뷰 클래스는 View를 확장합니다. 맞춤 뷰는 View를 직접 확장할 수도 있으며, 또는 기존의 뷰 서브클래스(예: Button) 중 하나를 확장하여 시간을 절약할 수 있습니다.

Android 스튜디오가 뷰와 상호작용할 수 있도록 하려면 최소한 ContextAttributeSet 객체를 매개변수로 취하는 생성자를 제공해야 합니다. 이 생성자를 사용하면 Layout Editor에서 뷰의 인스턴스를 만들고 수정할 수 있습니다.

Kotlin

    class PieChart(context: Context, attrs: AttributeSet) : View(context, attrs)
    

자바

    class PieChart extends View {
        public PieChart(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    }
    

맞춤 속성 정의

사용자 인터페이스에 내장 View를 추가하려면 XML 요소에 지정하고 요소 속성으로 모양과 동작을 제어합니다. 잘 작성된 맞춤 뷰는 XML을 통해 추가하고 스타일을 지정할 수도 있습니다. 맞춤 뷰에서 이 동작을 사용 설정하려면 다음을 실행해야 합니다.

  • <declare-styleable> 리소스 요소에서 뷰의 맞춤 속성 정의
  • XML 레이아웃에서 속성 값 지정
  • 런타임에 속성 값 검색
  • 뷰 검색된 속성 값 적용

이 섹션에서는 맞춤 속성을 정의하고 이 속성의 값을 지정하는 방법에 관해 설명합니다. 다음 섹션에서는 런타임에 값을 검색하고 적용하는 방법에 관해 다룹니다.

맞춤 속성을 정의하려면 프로젝트에 <declare-styleable> 리소스를 추가합니다. 통상적으로 이러한 리소스는 res/values/attrs.xml 파일에 저장합니다. 다음은 attrs.xml 파일의 예입니다.

    <resources>
       <declare-styleable name="PieChart">
           <attr name="showText" format="boolean" />
           <attr name="labelPosition" format="enum">
               <enum name="left" value="0"/>
               <enum name="right" value="1"/>
           </attr>
       </declare-styleable>
    </resources>
    

이 코드는 PieChart라는 스타일 지정이 가능한 항목에 속하는 두 개의 맞춤 속성, showTextlabelPosition을 선언합니다. 스타일을 지정할 수 있는 항목의 이름은 관례상 맞춤 뷰를 정의하는 클래스 이름과 같습니다. 이 규칙을 엄격히 따를 필요는 없지만 인기 있는 많은 코드 편집기에서는 이 이름 지정 관례에 따라 명령문을 완성합니다.

맞춤 속성을 정의하면 내장 속성과 마찬가지로 레이아웃 XML 파일에서 이 속성을 사용할 수 있습니다. 유일한 차이점은 맞춤 속성이 다른 네임스페이스에 속한다는 것입니다. 맞춤 속성은 http://schemas.android.com/apk/res/android 네임스페이스에 속하지 않고 http://schemas.android.com/apk/res/[your package name]에 속합니다. 예를 들어, PieChart에 정의된 속성을 사용하는 방법은 다음과 같습니다.

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:custom="http://schemas.android.com/apk/res/com.example.customviews">
     <com.example.customviews.charting.PieChart
         custom:showText="true"
         custom:labelPosition="left" />
    </LinearLayout>
    

샘플에서는 길이가 긴 네임스페이스 URI를 반복하지 않도록 xmlns 지시어를 사용합니다. 이 지시어는 custom이라는 별칭을 http://schemas.android.com/apk/res/com.example.customviews 네임스페이스에 할당합니다. 네임스페이스에 사용할 별칭을 선택할 수 있습니다.

레이아웃에 맞춤 뷰를 추가하는 XML 태그의 이름을 확인하세요. 이 이름은 맞춤 뷰 클래스의 정규화된 이름입니다. 뷰 클래스가 내부 클래스인 경우 뷰 클래스를 뷰의 외부 클래스 이름을 사용하여 추가로 정규화해야 합니다. 예를 들어, PieChart 클래스에는 PieView라는 내부 클래스가 있습니다. 이 클래스의 맞춤 속성을 사용하려면 com.example.customviews.charting.PieChart$PieView 태그를 사용합니다.

맞춤 속성 적용

XML 레이아웃에서 뷰를 만들면 리소스 번들에서 XML 태그의 모든 속성을 읽어 뷰 생성자에 AttributeSet으로 전달합니다. AttributeSet에서 직접 값을 읽을 수 있지만, 그렇게 하면 몇 가지 단점이 있습니다.

  • 속성 값 내의 리소스 참조가 결정되지 않습니다.
  • 스타일이 적용되지 않습니다.

대신, AttributeSetobtainStyledAttributes()에 전달하면 됩니다. 이 메서드는 이미 역참조되었으며 스타일이 지정된 값의 TypedArray 배열을 다시 전달합니다.

Android 리소스 컴파일러는 obtainStyledAttributes()를 더 쉽게 호출할 수 있도록 많은 작업을 실행합니다. 생성된 R.java에서는 res 디렉터리의 <declare-styleable> 리소스마다 배열의 각 속성에 색인을 정의하는 속성 ID 배열과 상수 집합을 모두 정의합니다. 미리 정의된 상수를 사용하여 TypedArray에서 속성을 읽습니다. PieChart 클래스에서 속성을 읽는 방법은 다음과 같습니다.

Kotlin

    init {
        context.theme.obtainStyledAttributes(
                attrs,
                R.styleable.PieChart,
                0, 0).apply {

            try {
                mShowText = getBoolean(R.styleable.PieChart_showText, false)
                textPos = getInteger(R.styleable.PieChart_labelPosition, 0)
            } finally {
                recycle()
            }
        }
    }
    

자바

    public PieChart(Context context, AttributeSet attrs) {
       super(context, attrs);
       TypedArray a = context.getTheme().obtainStyledAttributes(
            attrs,
            R.styleable.PieChart,
            0, 0);

       try {
           mShowText = a.getBoolean(R.styleable.PieChart_showText, false);
           textPos = a.getInteger(R.styleable.PieChart_labelPosition, 0);
       } finally {
           a.recycle();
       }
    }
    

TypedArray 객체는 공유 리소스이며 사용 후 재활용해야 합니다.

속성 및 이벤트 추가

속성은 뷰의 동작 및 모양을 제어하는 강력한 방법이지만 뷰가 초기화될 때만 읽을 수 있습니다. 동적 동작을 제공하려면 각 맞춤 속성의 속성 getter 및 setter 쌍을 노출하세요. 다음 스니펫은 PieChart에서 showText라는 속성을 노출하는 방법을 보여줍니다.

Kotlin

    fun isShowText(): Boolean {
        return mShowText
    }

    fun setShowText(showText: Boolean) {
        mShowText = showText
        invalidate()
        requestLayout()
    }
    

자바

    public boolean isShowText() {
       return mShowText;
    }

    public void setShowText(boolean showText) {
       mShowText = showText;
       invalidate();
       requestLayout();
    }
    

setShowTextinvalidate()requestLayout()을 호출합니다. 이 호출은 뷰가 안정적으로 작동하게 하는 데 중요합니다. 다시 그려야 한다는 것을 시스템에서 인식하도록 모양을 변경할 수 있는 속성으로 변경한 후 보기를 무효화해야 합니다. 마찬가지로 뷰의 크기나 모양에 영향을 줄 수 있는 속성이 변경되면 새 레이아웃을 요청해야 합니다. 이러한 메서드 호출을 잊어버리면 찾기 어려운 버그가 발생할 수 있습니다.

또한, 맞춤 뷰에서는 이벤트 리스너를 지원하여 중요한 이벤트를 전달해야 합니다. 예를 들어, PieChartOnCurrentItemChanged라고 하는 맞춤 이벤트를 노출하여 사용자가 새 파이 조각에 포커스를 두기 위해 원형 차트를 회전했다고 리스너에게 알려줍니다.

특히, 개발자가 맞춤 뷰의 유일한 사용자인 경우 속성 및 이벤트 노출을 잊어버리기 쉽습니다. 뷰의 인터페이스를 면밀히 정의하는 데 충분한 시간을 들이면 향후 유지관리 비용이 줄어듭니다. 따라야 할 규칙은 맞춤 뷰의 시각적 모양이나 동작에 영향을 주는 속성을 항상 노출하는 것입니다.

누구나 액세스할 수 있는 뷰 디자인

맞춤 뷰에서는 최대한 넓은 범위의 사용자를 지원해야 합니다. 여기에는 터치스크린을 보거나 사용하지 못하는 장애가 있는 사용자도 포함됩니다. 장애가 있는 사용자를 지원하려면 다음과 같이 해야 합니다.

  • android:contentDescription 속성을 사용하여 입력란의 라벨 지정
  • 필요한 경우 sendAccessibilityEvent()를 호출하여 접근성 이벤트 전송
  • D패드 및 트랙볼과 같은 대체 컨트롤러 지원

액세스 가능한 뷰 만들기에 관한 자세한 내용은 Android 개발자 가이드의 접근성 높은 애플리케이션 만들기를 참조하세요.