XMLを使用してAndroid UI要素を宣言するにはどうすればよいですか?
Android開発者ガイドには Building Custom Components というセクションがあります。残念ながら、 XML属性の説明 はレイアウトファイル内のコントロールの宣言のみを扱い、実際にはクラスの初期化内の値を処理しません。手順は次のとおりです。
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
などの非標準のAndroid属性では、型を宣言する必要があります。スーパークラスで宣言されたタグは、再宣言することなくサブクラスで使用できます。
初期化にAttributeSet
を使用するコンストラクターが2つあるため、コンストラクターが呼び出す別の初期化メソッドを作成すると便利です。
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.MyCustomView
は自動生成されたint[]
リソースで、各要素は属性のIDです。属性名を要素名に追加することにより、XMLの各プロパティに対して属性が生成されます。たとえば、R.styleable.MyCustomView_Android_text
には、MyCustomView
のAndroid_text
属性が含まれます。その後、さまざまなTypedArray
関数を使用して、get
から属性を取得できます。 XMLで定義されている属性が定義されていない場合、null
が返されます。もちろん、戻り値の型がプリミティブの場合を除き、その場合は2番目の引数が返されます。
すべての属性を取得したくない場合は、この配列を手動で作成できます。標準のAndroid属性のIDはAndroid.R.attr
に含まれていますが、このプロジェクトの属性はR.attr
。
int attrsWanted[]=new int[]{Android.R.attr.text, R.attr.textColor};
あなたはnotAndroid.R.styleable
で何も使用してはならないことに注意してください このスレッド 。これらの定数をすべて1か所で表示するのが便利であるため、まだドキュメントに記載されています。
layout\main.xml
などのレイアウトファイルで使用します最上位のxml要素に名前空間宣言xmlns:app="http://schemas.Android.com/apk/res-auto"
を含めます。名前空間は、異なるスキーマが同じ要素名を使用しているときに発生する競合を回避する方法を提供します(詳細については、 この記事 を参照してください)。 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"
/>
完全修飾名を使用してカスタムビューを参照します。
完全な例が必要な場合は、Androidラベルビューのサンプルをご覧ください。
TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.LabelView);
CharSequences=a.getString(R.styleable.LabelView_text);
<declare-styleable name="LabelView">
<attr name="text"format="string"/>
<attr name="textColor"format="color"/>
<attr name="textSize"format="dimension"/>
</declare-styleable>
<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'にリソースIDが見つかりません」が表示されます)。
<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" />
最も投票された回答への追加。
私たちがAndroid:xxxの定義済み属性を使ってカスタムビューを作成するときに、performStyledAttributes()の使用法についていくつかの単語を追加します。特に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>
たぶん、私はいくつかの方法で間違っていますが、performStyledAttributes()に関するAndroidのドキュメントは非常に貧弱です。
同時に、宣言されたすべての属性を使用して、標準のUIコンポーネントを拡張することもできます。たとえばTextViewは多くのプロパティを宣言しているため、この方法はそれほど良くありません。そして、オーバーライドされたonMeasure()とonDraw()に完全な機能を実装することは不可能でしょう。
しかし、カスタムコンポーネントの理論的な再利用を犠牲にすることはできます。 「私が使用する機能を正確に知っている」と言って、誰ともコードを共有しないでください。
それからコンストラクタCustomComponent(Context, AttributeSet, defStyle)
を実装することができます。 super(...)
を呼び出した後、すべての属性を解析してgetterメソッドで利用できるようにします。
Googleが開発者ページを更新し、そこにさまざまなトレーニングを追加したようです。
そのうちの一つはカスタムビューの作成を扱い、ここで見つけることができます
最初の回答をどうもありがとう。
私に関しては、私はそれに関してただ一つの問題を抱えていました。私の見解を膨らませるとき、私はバグがありました: Java.lang.NoSuchMethodException:MyView(コンテキスト、属性)
私は新しいコンストラクタを作成することでそれを解決しました:
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レイアウトファイルです。