[android] Android에서 스타일 지정 가능한 속성 선언

declare-styleable컴포넌트에 대한 사용자 정의 스타일을 선언 할 수 있는 태그에 대한 귀중한 문서가 거의 없습니다 . 태그 의 속성에 대해 유효한 값 목록 을 찾았습니다 . 그것이 진행되는 한 좋지만 이러한 값 중 일부를 사용하는 방법을 설명하지 않습니다. attr.xml (표준 속성에 대한 Android 소스)을 찾아 보면서 다음과 같은 작업을 수행 할 수 있음을 발견했습니다.formatattr

<!-- The most prominent text color.  -->
<attr name="textColorPrimary" format="reference|color" />

format속성 분명히 값의 조합으로 설정할 수있다. 아마도 format속성은 파서가 실제 스타일 값을 해석하는 데 도움이 될 것입니다. 그런 다음 attr.xml에서 이것을 발견했습니다.

<!-- Default text typeface. -->
<attr name="typeface">
    <enum name="normal" value="0" />
    <enum name="sans" value="1" />
    <enum name="serif" value="2" />
    <enum name="monospace" value="3" />
</attr>

<!-- Default text typeface style. -->
<attr name="textStyle">
    <flag name="normal" value="0" />
    <flag name="bold" value="1" />
    <flag name="italic" value="2" />
</attr>

이 두 가지 모두 표시된 스타일에 허용되는 값 집합을 선언하는 것 같습니다.

그래서 두 가지 질문이 있습니다.

  1. enum값 세트 중 하나를 취할 수있는 스타일 속성과 값 세트를 취할 수있는 스타일 속성의 차이점은 무엇입니까 flag?
  2. 누구든지 declare-styleable작동 방식 에 대한 더 나은 문서를 알고 있습니까 (Android 소스 코드를 리버스 엔지니어링하는 것 제외)?



답변

여기에이 질문이 있습니다. 약간의 정보로 사용자 지정 속성정의 하지만 많지는 않습니다.

그리고이 포스트 . 플래그 및 열거 형에 대한 좋은 정보가 있습니다.

사용자 지정 XML 속성 플래그

플래그는 아주 작은 값의 하위 집합, 즉 속성 태그 아래에 정의 된 값만 허용된다는 점에서 특수 속성 유형입니다. 플래그는 “이름”속성과 “값”속성으로 지정됩니다. 이름은 해당 속성 유형 내에서 고유해야하지만 값은 그럴 필요가 없습니다. 이것이 Android 플랫폼이 진화하는 동안 “fill_parent”와 “match_parent”가 모두 동일한 동작에 매핑되는 이유입니다. 그들의 가치는 동일했습니다.

name 속성은 레이아웃 XML 내의 값 위치에 사용되는 이름에 매핑되며 네임 스페이스 접두사가 필요하지 않습니다. 따라서 위의 “tilingMode”에 대해 속성 값으로 “center”를 선택했습니다. 나는 “늘어난”또는 “반복”을 쉽게 선택할 수 있지만 다른 것은 없습니다. 실제 값으로 대체하는 것도 허용되지 않았습니다.

값 속성은 정수 여야합니다. 16 진수 또는 표준 숫자 표현의 선택은 귀하에게 달려 있습니다. 둘 다 사용되는 Android 코드 내 몇 군데가 있으며 Android 컴파일러는 둘 중 하나를 기꺼이 받아들입니다.

사용자 지정 XML 속성 열거 형

열거 형은 하나의 프로 비전이있는 플래그와 거의 동일한 방식으로 사용되며 정수와 교환하여 사용할 수 있습니다. 내부적으로 Enum과 Integer는 동일한 데이터 유형, 즉 Integer에 매핑됩니다. 정수와 함께 속성 정의에 나타날 때 Enum은 항상 나쁜 “매직 넘버”를 방지하는 역할을합니다. 이것이 차원, 정수 또는 명명 된 문자열 ‘fill_parent’가있는 ‘android : layout_width’를 가질 수있는 이유입니다.

이를 컨텍스트에 적용하기 위해 정수 또는 “scroll_to_top”문자열을 허용하는 “layout_scroll_height”라는 사용자 지정 속성을 생성한다고 가정 해 보겠습니다. 이렇게하려면 “integer”형식 속성을 추가하고 enum을 따릅니다.

<attr name="layout_scroll_height" format="integer">
    <enum name="scroll_to_top" value="-1"/>
</attr>

이러한 방식으로 Enum을 사용할 때 한 가지 규정은 사용자 정의보기를 사용하는 개발자가 의도적으로 “-1″값을 레이아웃 매개 변수에 배치 할 수 있다는 것입니다. 이렇게하면 “scroll_to_top”이라는 특수한 경우 논리가 트리거됩니다. 이러한 예상치 못한 (또는 예상되는) 동작은 Enum 값을 잘못 선택하면 라이브러리를 “레거시 코드”더미로 빠르게 이동할 수 있습니다.


내가보기에 속성에 실제로 추가 할 수있는 실제 값은 속성에서 얻을 수있는 것에 의해 제한됩니다. 더 많은 힌트는 여기 에서 AttributeSet클래스 참조를 확인하십시오 .

다음을 얻을 수 있습니다.

  • 부울 ( getAttributeBooleanValue),
  • 수레 ( getAttributeFloatValue),
  • 정수 ( getAttributeIntValue),
  • int ( getAttributeUnsignedIntValue),
  • 및 문자열 ( getAttributeValue)


답변

@Aleadam의 답변은 매우 도움이되지만 imho는 enum과 사이의 주요 차이점을 생략 flag합니다. 전자는 하나를 선택하도록 의도되었으며 일부 뷰에 해당 속성을 할당 할 때 하나의 값만 선택합니다. 그러나 후자의 값은 비트 OR 연산자를 사용하여 결합 할 수 있습니다.

예, res/values/attr.xml

<!-- declare myenum attribute -->
<attr name="myenum">
    <enum name="zero" value="0" />
    <enum name="one" value="1" />
    <enum name="two" value="2" />
    <enum name="three" value="3" />
</attr>

<!-- declare myflags attribute -->
<attr name="myflags">
    <flag name="one" value="1" />
    <flag name="two" value="2" />
    <flag name="four" value="4" />
    <flag name="eight" value="8" />
</attr>

<!-- declare our custom widget to be styleable by these attributes -->
<declare-styleable name="com.example.MyWidget">
    <attr name="myenum" />
    <attr name="myflags" />
</declare-styleable>

에서에게 res/layout/mylayout.xml우리가 지금 할 수있는

<com.example.MyWidget
    myenum="two"
    myflags="one|two"
    ... />

따라서 열거 형은 가능한 값 중 하나를 선택하고 플래그는 결합 할 수 있습니다. 숫자 값은 이러한 차이를 반영해야합니다. 일반적으로 시퀀스를 0,1,2,3,...열거 형 (예 : 배열 인덱스로 사용) 및 플래그로 이동 1,2,4,8,...하여 비트 OR |을 사용하여 플래그를 결합 하여 독립적으로 추가하거나 제거 할 수 있도록해야 합니다.

2의 거듭 제곱이 아닌 값으로 “메타 플래그”를 명시 적으로 정의 할 수 있으므로 일반적인 조합에 대한 일종의 속기를 도입 할 수 있습니다. 예를 들어 myflags선언문에 이것을 포함했다면

<flag name="three" value="3" />

우리는 쓴 수 myflags="three"의 대신 myflags="one|two"으로 완전히 동일한 결과를, 3 == 1|2.

개인적으로 저는 항상 포함하고 싶습니다

<flag name="none" value="0" /> <!-- or "normal, "regular", and so on -->
<flag name="all" value="15" /> <!-- 15 == 1|2|4|8 -->

한 번에 모든 플래그를 설정 해제하거나 설정할 수 있습니다.

더 미묘하게는 하나의 플래그가 다른 플래그에 의해 암시되는 경우 일 수 있습니다. 따라서이 예에서 eight설정중인 플래그가 플래그를 설정해야 한다고 가정합니다 four(아직 설정되지 않은 경우). 그런 다음 플래그 eight를 미리 포함하도록 다시 정의 할 수 있습니다 four.

<flag name="eight" value="12" /> <!-- 12 == 8|4 -->

마지막으로 라이브러리 프로젝트에서 속성을 선언하지만 다른 프로젝트의 레이아웃 (lib에 따라 다름)에 적용하려는 경우 XML 루트 요소에 바인딩해야하는 네임 스페이스 접두사를 사용해야합니다. 예 :

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:auto="http://schemas.android.com/apk/res-auto"
    ... >

    <com.example.MyWidget
        auto:myenum="two"
        auto:myflags="one|two"
        ... />

</RelativeLayout>


답변