84

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>

これらは両方とも、示されたスタイルに許可された値のセットを宣言しているようです。

だから私は2つの質問があります:

  1. enum値のセットの1つをとることができるスタイル属性と値のセットをとることができるスタイル属性の違いは何flagですか?
  2. declare-styleable(Androidソースコードをリバースエンジニアリングする以外に)どのように機能するかについてのより良いドキュメントを知っている人はいますか?
4

2 に答える 2

76

ここにこの質問があります:カスタム属性いくつかの情報で定義しますが、それほど多くはありません。

そしてこの投稿。フラグと列挙型に関する優れた情報があります。

カスタム XML 属性フラグ

フラグは、属性タグの下で定義された値の非常に小さなサブセットのみが許可されるという点で、特別な属性タイプです。フラグは、「name」属性と「value」属性によって指定されます。名前はその属性タイプ内で一意である必要がありますが、値は一意である必要はありません。これが、Android プラットフォームの進化中に、「fill_parent」と「match_parent」の両方が同じ動作にマッピングされた理由です。それらの値は同一でした。

name 属性は、レイアウト XML 内の値の場所で使用される名前にマップされ、名前空間プレフィックスは必要ありません。したがって、上記の「tilingMode」では、属性値として「center」を選択しました。「ストレッチ」または「繰り返し」を簡単に選択できましたが、他には何もありませんでした。実際の値を代入することさえ許されませんでした。

value 属性は整数でなければなりません。16 進数または標準の数値表現の選択はユーザー次第です。Android コード内で両方が使用されている場所がいくつかありますが、Android コンパイラはどちらも喜んで受け入れます。

カスタム XML 属性列挙

列挙型は、フラグとほぼ同じ方法で使用されますが、1 つの規定があり、整数と同じ意味で使用できます。内部では、列挙型と整数は同じデータ型、つまり整数にマップされます。属性定義で整数を使用する場合、Enum は常に悪い「マジック ナンバー」を防ぐのに役立ちます。これが、ディメンション、整数、または名前付き文字列「fill_parent」のいずれかを含む「android:layout_width」を持つことができる理由です。</p>

これを理解するために、整数または文字列「scroll_to_top」を受け入れる「layout_scroll_height」というカスタム属性を作成するとします。そのためには、「整数」形式の属性を追加し、その後に列挙型を続けます。

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

この方法で Enum を使用する場合の 1 つの条件は、カスタム ビューを使用する開発者が意図的に値「-1」をレイアウト パラメーターに配置できることです。これにより、「scroll_to_top」の特別なケース ロジックがトリガーされます。Enum 値が適切に選択されていない場合、このような予期しない (または予想される) 動作は、ライブラリをすぐに「レガシー コード」の山に追いやる可能性があります。


私が見ているように、実際に属性に追加できる実際の値は、属性から取得できるものによって制限されます。その他のヒントについては、こちらAttributeSetのクラス リファレンスを確認してください。

以下を取得できます。

  • ブール値 ( getAttributeBooleanValue),
  • フロート ( getAttributeFloatValue),
  • 整数 ( getAttributeIntValue)、
  • 整数(としてgetAttributeUnsignedIntValue)、
  • と文字列 ( getAttributeValue)
于 2011-05-16T17:31:00.090 に答える
74

@Aleadam の回答は非常に役に立ちますが、enumとの大きな違いが 1 つ省略されていますflag。前者は、ビューに対応する属性を割り当てるときに、値を 1 つだけ選択することを目的としています。ただし、後者の値は、ビットごとの 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"
    ... />

したがって、列挙型は可能な値の 1 つを選択しますが、フラグは組み合わせることができます。数値はこの違いを反映する必要があります。通常は、ビットごとの ORを使用してフラグを組み合わせて、個別に追加または削除できるように、シーケンスを0,1,2,3,...列挙型 (たとえば、配列インデックスとして使用) およびフラグに移動する必要があります。1,2,4,8,...|

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 -->

最後に、ライブラリ プロジェクトで属性を宣言しているが、別のプロジェクト (ライブラリに依存する) のレイアウトにそれらを適用したい場合は、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>
于 2014-03-12T19:38:33.050 に答える