web-dev-qa-db-ja.com

Androidでスタイル可能な属性を宣言する

コンポーネントのカスタムスタイルを宣言できる_declare-styleable_タグに関する貴重なドキュメントはほとんどありません。 formatタグのattr属性の有効な値の this list を見つけました。それはいいところですが、これらの値のいくつかを使用する方法を説明していません。 attr.xml (Android標準属性のソース))を参照すると、次のようなことができることがわかりました。

_<!-- 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ソースコード)のリバースエンジニアリング以外)。
77
Ted Hopp

ここにこの質問があります: Defining custom attrs withsomeinfo、but not much。

そして、これは post です。フラグと列挙型に関する良い情報があります:

カスタムXML属性フラグ

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

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

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

カスタムXML属性列挙

列挙型は、1つの規定でフラグとほぼ同じ方法で使用され、整数と交換可能に使用できます。内部では、EnumとIntegerは同じデータ型、つまりIntegerにマップされます。整数を使用して属性定義に表示される場合、Enumは、常に悪い「マジックナンバー」を防ぐのに役立ちます。これが、ディメンション、整数、または名前付き文字列「fill_parent」で「Android:layout_width」を持つことができる理由です。

これをコンテキストに入れるために、整数または文字列「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クラスリファレンス here を確認してください。

以下を入手できます。

  • ブール値(getAttributeBooleanValue)、
  • フロート(getAttributeFloatValue)、
  • ints(getAttributeIntValue)、
  • ints(getAttributeUnsignedIntValueとして)、
  • および文字列(getAttributeValue
69
Aleadam

@Aleadamの答えは非常に役立ちますが、enumflagの大きな違いを1つ省略しています。前者は、いくつかのビューに対応する属性を割り当てるときに、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つを選択しますが、フラグは組み合わせることができます。数値はこの違いを反映する必要があります。通常、シーケンスは列挙型に対して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>
63
Rad Haring