XML을 사용하여 사용자 정의 Android UI 요소 선언


답변:


840

Android 개발자 안내서에는 사용자 정의 구성 요소 빌드 라는 섹션이 있습니다. 불행히도, XML 속성에 대한 설명은 레이아웃 파일 내부에서 컨트롤을 선언하고 실제로 클래스 초기화 내부의 값을 처리하지는 않습니다. 단계는 다음과 같습니다.

1. 속성 선언 values\attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyCustomView">
        <attr name="android:text"/>
        <attr name="android:textColor"/>            
        <attr name="extraInformation" format="string" />
    </declare-styleable>
</resources>

declare-styleable태그 에서 규정되지 않은 이름을 사용하는 것에 주목하십시오 . 비표준 안드로이드 속성 extraInformation은 타입을 선언해야합니다. 수퍼 클래스에 선언 된 태그는 다시 선언하지 않고도 서브 클래스에서 사용할 수 있습니다.

2. 생성자 생성

AttributeSet초기화에 사용하는 두 개의 생성자가 있으므로 생성자가 호출 할 별도의 초기화 메소드를 작성하는 것이 편리합니다.

private void init(AttributeSet attrs) { 
    TypedArray a=getContext().obtainStyledAttributes(
         attrs,
         R.styleable.MyCustomView);

    //Use a
    Log.i("test",a.getString(
         R.styleable.MyCustomView_android_text));
    Log.i("test",""+a.getColor(
         R.styleable.MyCustomView_android_textColor, Color.BLACK));
    Log.i("test",a.getString(
         R.styleable.MyCustomView_extraInformation));

    //Don't forget this
    a.recycle();
}

R.styleable.MyCustomViewint[]각 요소가 속성의 ID 인 자동 생성 된 자원입니다. 요소 이름에 속성 이름을 추가하여 XML의 각 속성에 대한 속성이 생성됩니다. 예를 들어에 R.styleable.MyCustomView_android_text대한 android_text속성을 포함합니다 MyCustomView. 그런 다음 TypedArray다양한 get기능을 사용하여 속성을 검색 할 수 있습니다 . XML에 정의 된 속성이 속성에 정의되어 있지 않으면 null반환됩니다. 물론, 리턴 유형이 기본 유형 인 경우를 제외하고 두 번째 인수가 리턴됩니다.

모든 속성을 검색하지 않으려면이 배열을 수동으로 생성 할 수 있습니다. 표준 Android 속성의 ID는에 포함되어 있고이 android.R.attr프로젝트의 속성은에 R.attr있습니다.

int attrsWanted[]=new int[]{android.R.attr.text, R.attr.textColor};

당신이해야주십시오 참고 하지 아무것도 사용 android.R.styleable에 따라, 이 스레드 는 향후 변경 될 수 있습니다. 한 곳에서 이러한 모든 상수를 보는 것이 유용한 것으로 여전히 문서에 있습니다.

3. 다음과 같은 레이아웃 파일에서 사용하십시오. layout\main.xml

xmlns:app="http://schemas.android.com/apk/res-auto"최상위 레벨 xml 요소에 네임 스페이스 선언 을 포함하십시오 . 네임 스페이스는 다른 스키마가 동일한 요소 이름을 사용할 때 가끔 발생하는 충돌을 피하는 방법을 제공합니다 (자세한 내용은 이 기사 참조 ). URL은 스키마를 고유하게 식별하는 방법 일 뿐이며 실제로 해당 URL에서 호스팅 할 필요는 없습니다 . 이것이 아무것도하지 않는 것 같으면 충돌을 해결하지 않으면 실제로 네임 스페이스 접두사를 추가 할 필요가 없기 때문입니다.

<com.mycompany.projectname.MyCustomView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@android:color/transparent"
    android:text="Test text"
    android:textColor="#FFFFFF"
    app:extraInformation="My extra information"
/> 

완전한 이름을 사용하여 사용자 정의보기를 참조하십시오.

안드로이드 LabelView 샘플

완전한 예제를 원하면 안드로이드 레이블보기 샘플을보십시오.

LabelView.java

 TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.LabelView);
 CharSequences=a.getString(R.styleable.LabelView_text);

attrs.xml

<declare-styleable name="LabelView">
    <attr name="text"format="string"/>
    <attr name="textColor"format="color"/>
    <attr name="textSize"format="dimension"/>
</declare-styleable>

custom_view_1.xml

<com.example.android.apis.view.LabelView
    android:background="@drawable/blue"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    app:text="Blue" app:textSize="20dp"/>

이것은 LinearLayout네임 스페이스 속성을 가진에 포함되어 있습니다 :xmlns:app="http://schemas.android.com/apk/res-auto"

연결


14
루트 요소에 사용자 정의 네임 스페이스가 필요한 경우 표준 안드로이드 네임 스페이스와 사용자 정의 네임 스페이스를 모두 추가해야하며 그렇지 않으면 빌드 오류가 발생할 수 있습니다.
체이스

11
이 답변은 내가 찾은 사용자 정의 XML 매개 변수에 대한 인터넷의 가장 명확한 리소스입니다. Casebash 감사합니다.
Artem Russakovskii

2
어떤 이유로 시각적 편집기는 android : text에 대해 작성된 텍스트 값의 사용을 거부하지만 장치는 잘 사용합니다. 어떻게 오세요?
안드로이드 개발자

2
@androiddeveloper Eclipse 편집기는 모든 android : 속성에 대한 값 사용을 거부하는 것 같습니다. 그것이 기능 또는 버그인지 알고 싶습니다
deej

4
xmlns : app 네임 스페이스와 res-auto의 목적은 무엇입니까?
IgorGanapolsky

91

훌륭한 참조. 감사! 그것에 추가 :

사용자 정의 뷰에 대한 사용자 정의 속성을 선언 한 라이브러리 프로젝트가 포함 된 경우 라이브러리 네임 스페이스가 아닌 프로젝트 네임 스페이스를 선언해야합니다. 예 :

라이브러리에 "com.example.library.customview"패키지가 있고 작업 프로젝트에 "com.example.customview"패키지가 있으면 다음을 수행하십시오.

작동하지 않습니다 ( "오류 : 'com.example.library.customview'패키지의 'newAttr'속성에 대한 자원 식별자를 찾을 수 없음"오류가 표시됨) :

<com.library.CustomView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res/com.example.library.customview"
        android:id="@+id/myView"
        app:newAttr="value" />

작동합니다 :

<com.library.CustomView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res/com.example.customview"
        android:id="@+id/myView"
        app:newAttr="value" />

47
이것은 ADT 17 미리보기에서 수정되었습니다. 라이브러리 선언에서 응용 프로그램의 네임 스페이스를 사용하는 방법 xmlns:app="http://schemas.android.com/apk/res-auto"을 참조하십시오 주석 57 code.google.com/p/android/issues/detail?id=9656
NMR

2
포함 사용자 정의 네임 스페이스는 이제 오류를 반환Suspicious namespace: Did you mean http://schemas.android.com/apk/res-auto
벤 윌킨슨

우리는 Android Studio와 Gradle을 사용하고 있기 때문에 커스텀 네임 스페이스는 res-auto로 끝납니다. 그렇지 않으면 (예를 들어 일부 이클립스 버전) 보통 lib / [패키지 이름]으로 끝납니다
Universe

사용자 정의 네임 스페이스는 res-autoAndroid Studio 및 Gradle을 사용하기 때문에 끝납니다 . 그렇지 않으면 (예를 들어 일부 이클립스 버전) 일반적으로로 끝납니다 lib/[your package name]. 즉http://schemas.android.com/apk/lib/[your package name]
우주

27

대부분의 투표 답변에 추가.

acquireStyledAttributes ()

android : xxx prdefined 속성을 사용하여 사용자 정의보기를 만들 때 acquireStyledAttributes () 사용법에 대한 단어를 추가하고 싶습니다. 특히 TextAppearance를 사용할 때.
"2. 생성자 생성"에서 언급했듯이, 커스텀 뷰는 생성시 AttributeSet을 얻습니다. TextView 소스 코드 (API 16)에서 볼 수있는 주요 사용법입니다.

final Resources.Theme theme = context.getTheme();

// TextAppearance is inspected first, but let observe it later

TypedArray a = theme.obtainStyledAttributes(
            attrs, com.android.internal.R.styleable.TextView, defStyle, 0);

int n = a.getIndexCount();
for (int i = 0; i < n; i++) 
{
    int attr = a.getIndex(i);
    // huge switch with pattern value=a.getXXX(attr) <=> a.getXXX(a.getIndex(i))
}
a.recycle();

여기서 볼 수있는 것은 무엇입니까?
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)
속성 세트는 문서에 따라 테마별로 처리됩니다. 속성 값은 단계별로 컴파일됩니다. 첫 번째 속성은 테마로 채워진 다음 값이 스타일의 값으로 대체되고 마지막으로 특수 뷰 인스턴스에 대한 XML의 정확한 값이 다른 속성을 대체합니다.
요청 된 속성의 배열- com.android.internal.R.styleable.TextView
일반적인 상수 배열입니다. 표준 속성을 요청하는 경우이 배열을 수동으로 구축 할 수 있습니다.

문서에서 언급되지 않은 것-결과 TypedArray 요소의 순서.
attrs.xml에 사용자 정의보기가 선언되면 속성 색인에 대한 특수 상수가 생성됩니다. 그리고 우리는 이런 식으로 값을 추출 할 수 있습니다 : a.getString(R.styleable.MyCustomView_android_text). 그러나 수동int[] 경우 상수가 없습니다. getXXXValue (arrayIndex)가 제대로 작동한다고 가정합니다.

다른 질문은 "내부 상수를 어떻게 바꾸고 표준 속성을 요청할 수 있는가?"입니다. android.R.attr. * 값을 사용할 수 있습니다.

따라서 사용자 정의보기에서 표준 TextAppearance 속성을 사용하고 생성자에서 값을 읽으려면 TextView에서 다음과 같이 코드를 수정할 수 있습니다.

ColorStateList textColorApp = null;
int textSize = 15;
int typefaceIndex = -1;
int styleIndex = -1;

Resources.Theme theme = context.getTheme();

TypedArray a = theme.obtainStyledAttributes(attrs, R.styleable.CustomLabel, defStyle, 0);
TypedArray appearance = null;
int apResourceId = a.getResourceId(R.styleable.CustomLabel_android_textAppearance, -1);
a.recycle();
if (apResourceId != -1)
{
    appearance = 
        theme.obtainStyledAttributes(apResourceId, new int[] { android.R.attr.textColor, android.R.attr.textSize, 
            android.R.attr.typeface, android.R.attr.textStyle });
}
if (appearance != null)
{
    textColorApp = appearance.getColorStateList(0);
    textSize = appearance.getDimensionPixelSize(1, textSize);
    typefaceIndex = appearance.getInt(2, -1);
    styleIndex = appearance.getInt(3, -1);

    appearance.recycle();
}

CustomLabel이 정의 된 위치 :

<declare-styleable name="CustomLabel">
    <!-- Label text. -->
    <attr name="android:text" />
    <!-- Label text color. -->
    <attr name="android:textColor" />
    <!-- Combined text appearance properties. -->
    <attr name="android:textAppearance" />
</declare-styleable>

어쩌면 내가 어떤 식으로 잘못 생각했을 수도 있지만 acquireStyledAttributes ()에 대한 Android 설명서는 매우 열악합니다.

표준 UI 구성 요소 확장

동시에 선언 된 모든 속성을 사용하여 표준 UI 구성 요소를 확장 할 수 있습니다. 예를 들어 TextView가 많은 속성을 선언하기 때문에이 방법은 좋지 않습니다. 재정의 된 onMeasure () 및 onDraw ()에서 전체 기능을 구현하는 것은 불가능합니다.

그러나 우리는 사용자 정의 구성 요소를 이론적으로 광범위하게 재사용 할 수 있습니다. "사용할 기능을 정확히 알고 있습니다"라고 말하고 다른 사람과 코드를 공유하지 마십시오.

그런 다음 constructor을 구현할 수 있습니다 CustomComponent(Context, AttributeSet, defStyle). 호출 한 후 super(...)getter 메소드를 통해 모든 속성을 구문 분석하고 사용할 수 있습니다.


Eclipse GUI 디자이너에서 android : xxx 사전 정의 된 속성이 작동합니까?
deej

이러한 속성은 특성 편집기의 Eclipse ADT 플러그인에 의해 인식됩니다. 일부 값이 정의되지 않은 경우 내 스타일에서 기본값을 볼 수 있습니다. 그리고 클래스에 @RemoteView 주석을 추가하는 것을 잊지 마십시오.
yuriy.weiss 11

작동시킬 수 없습니다. Eclipse는 getText에 null을 계속로드하고 getResourceId에 대해 android.content.res.Resources $ NotFoundException을 발생시킵니다 (앱은 장치에서 제대로 실행 됨).
deej

죄송합니다. 도와 드릴 수 없습니다. 나는 가능성을 테스트하기 위해 데모 프로젝트 만 만들었으며 그러한 오류를 충족시키지 못했습니다.
yuriy.weiss

이것은 커스텀 뷰의 커스텀 속성을 내장 된 뷰의 내장 속성에 매핑하는 것보다 훨씬 낫습니다.
samis

13

Google이 개발자 페이지를 업데이트하고 다양한 교육을 추가 한 것으로 보입니다.

그들 중 하나는 커스텀 뷰 생성을 다루며 여기 에서 찾을 수 있습니다.


5

첫 번째 답변에 감사드립니다.

나에 관해서는, 나는 그것에 한 가지 문제가 있었다. 내보기를 팽창시킬 때 버그가 발생했습니다 : java.lang.NoSuchMethodException : MyView (Context, Attributes)

새 생성자를 만들어서 해결했습니다.

public MyView(Context context, AttributeSet attrs) {
     super(context, attrs);
     // some code
}

이것이 도움이되기를 바랍니다!


0

다른 레이아웃 파일에 레이아웃 파일을 포함시킬 수 있습니다.

             <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="30dp" >

                <include
                    android:id="@+id/frnd_img_file"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    layout="@layout/include_imagefile"/>

                <include
                    android:id="@+id/frnd_video_file"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    layout="@layout/include_video_lay" />

                <ImageView
                    android:id="@+id/downloadbtn"
                    android:layout_width="30dp"
                    android:layout_height="30dp"
                    android:layout_centerInParent="true"
                    android:src="@drawable/plus"/>
            </RelativeLayout>

여기에서 include 태그의 레이아웃 파일은 동일한 res 폴더의 다른 .xml 레이아웃 파일입니다.


나는 이것을 시도했는데, 내가 가진 문제는 포함 된 레이아웃을 '적응'할 수 없으며 제네릭을 만들 수 없다는 것입니다. 예를 들어 비슷한 방식으로 버튼을 포함 할 때 XML에 텍스트를 설정하려고하면 작동합니다.
cfl
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.