XML을 사용하여 사용자 정의 Android UI 요소 선언 Android UI 요소를 어떻게 선언합니까?

XML을 사용하여 Android UI 요소를 어떻게 선언합니까?



답변

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"

연결


답변

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

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

라이브러리에 “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" />


답변

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

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 메소드를 통해 모든 속성을 구문 분석하고 사용할 수 있습니다.


답변

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

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


답변

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

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

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

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

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


답변

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

             <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 레이아웃 파일입니다.


답변