回答:
Androidデベロッパーガイドには、カスタムコンポーネントの構築というセクションがあります。残念ながら、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
タグで非修飾名を使用していることに注意してください。のような非標準のandroid属性extraInformation
は、型を宣言する必要があります。スーパークラスで宣言されたタグは、再宣言しなくてもサブクラスで使用できます。
AttributeSet
for初期化に使用する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
、のandroid_text
属性が含まれていますMyCustomView
。次に、TypedArray
さまざまなget
関数を使用して属性を取得できます。XMLで定義されている属性が定義されていない場合は、null
が返されます。もちろん、戻り値の型がプリミティブの場合を除いて、その場合、2番目の引数が返されます。
すべての属性を取得したくない場合は、この配列を手動で作成できます。標準のAndroid属性のIDはに含まれてandroid.R.attr
いますが、このプロジェクトの属性はに含まれていますR.attr
。
int attrsWanted[]=new int[]{android.R.attr.text, R.attr.textColor};
このスレッドでは将来的に変更される可能性があるため、では何も使用しないでください。これらすべての定数を1か所に表示することは有用であるため、ドキュメントにはまだ記載されています。android.R.styleable
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"
/>
完全修飾名を使用してカスタムビューを参照します。
完全な例が必要な場合は、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
、namespace属性を持つにいます。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" />
xmlns:app="http://schemas.android.com/apk/res-auto"
コメント57を参照してください
Suspicious namespace: Did you mean http://schemas.android.com/apk/res-auto
res-auto
Android StudioとGradleを使用しているため、カスタム名前空間は終了します。それ以外の場合(たとえば、一部のEclipseバージョン)、通常はで終わりlib/[your package name]
ます。iehttp://schemas.android.com/apk/lib/[your package name]
最も投票された回答への追加。
android:xxx prdefined属性を使用してカスタムビューを作成するときに、obtainStyledAttributes()の使用方法について説明します。特に、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>
たぶん、私は何らかの間違いをしているのですが、obtainStyledAttributes()に関するAndroidのドキュメントは非常に貧弱です。
同時に、宣言されたすべての属性を使用して、標準のUIコンポーネントを拡張できます。たとえばTextViewは多くのプロパティを宣言するため、このアプローチはあまり良くありません。そして、オーバーライドされたonMeasure()とonDraw()に完全な機能を実装することは不可能です。
しかし、カスタムコンポーネントの理論的な広い再利用を犠牲にすることができます。「使用する機能を正確に知っている」と言い、コードを誰とも共有しないでください。
次に、コンストラクタを実装できますCustomComponent(Context, AttributeSet, defStyle)
。呼び出し後、super(...)
すべての属性が解析され、ゲッターメソッドを通じて利用できるようになります。
最初の答えをありがとう。
私に関しては、問題が1つだけありました。ビューを拡張すると、バグが発生しました: 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レイアウトファイルです。