私は次のようにしました
1)スタイラブルを作成する
_<declare-styleable name="Viewee">
<attr name="linkedView" format="reference"/>
</declare-styleable>
_
2)カスタムビューレイアウトの定義
_<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"
Android:background="#ffc0">
<TextView
Android:id="@+id/custom_text"
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"
Android:text="[text]"
/>
</LinearLayout>
_
3)必要なクラスを作成する
_public class Viewee extends LinearLayout
{
public Viewee(Context context, AttributeSet attributeSet)
{
super(context, attributeSet);
View.inflate(context, R.layout.viewee, this);
TextView textView = (TextView) findViewById(R.id.custom_text);
TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.Viewee);
int id = typedArray.getResourceId(R.styleable.Viewee_linkedView, 0);
if (id != 0)
{
View view = findViewById(id);
textView.setText(((TextView) view).getText().toString());
}
typedArray.recycle();
}
}
_
そして最後に以下のような活動で
_<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res/com.ns"
Android:layout_width="fill_parent"
Android:layout_height="fill_parent"
Android:orientation="vertical">
<TextView
Android:id="@+id/tvTest"
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"
Android:text="Android"/>
<com.ns.Viewee
Android:layout_width="fill_parent"
Android:layout_height="fill_parent"
app:linkedView="@+id/tvTest"
/>
</LinearLayout>
_
vieweeコンストラクターでゼロ以外のid
を受信しましたが、findViewById(id)
がnullに戻り、NullPointerException
が発生します。
私は何が欠けていますか?
答えが見つかりました!
問題はfindViewById(id)
と私がそれを呼んだ場所にありました。 findViewById
は子ビューのみを検索し、 documentation が言うように、上位階層レベルにビューは存在しません。したがって、getRootView().findViewById(id)
のようなものを呼び出す必要がありますが、これはnull
も返します。これは、それが正しいとは言えなかったためです。
Viewee
コンストラクターではViewee
自体がまだルートに接続されていないため、呼び出しによってNullPointerException
が発生します。
したがって、構築後にどこか別の場所でgetRootView().findViewById(id)
を呼び出すと、正常に機能し、両方とも"@+id/tvTest"
および"@id/tvTest"
正しいです。私はそれをテストしました!
答えは次のとおりです
public class Viewee extends LinearLayout
{
public Viewee(Context context, AttributeSet a)
{
super(context, attributeSet);
View.inflate(context, R.layout.main6, this);
TextView textView = (TextView) findViewById(R.id.custom_text);
TypedArray t = context.obtainStyledAttributes(a, R.styleable.Viewee);
int id = t.getResourceId(R.styleable.Viewee_linkedView, 0);
if (id != 0)
{
_id = id;
}
t.recycle();
}
private int _id;
public void Foo()
{
TextView textView = (TextView) findViewById(R.id.custom_text);
View view = getRootView().findViewById(_id);
textView.setText(((TextView) view).getText().toString());
}
}
Foo
は、アクティビティなどの別の場所で参照IDを介して添付ビューを処理する必要がある場合に呼び出されます。
クレジットは完全に この投稿 で貢献した人たちに行きます。質問を送信する前に、その投稿を見たことがありませんでした。
これは古い質問ですが、すべてをカスタムビューにカプセル化したかったので、これを行う別の方法を追加すると思いました。
階層の上位にあるビューを取得する別の方法である外部から呼び出す代わりに、代わりにonAttachedToWindow()
にフックしました。
public class MyCustomView extends LinearLayout {
private int siblingResourceId;
private View siblingView;
public MyCustomView(Context context, AttributeSet a) {
super(context, attributeSet);
inflate(context, R.layout.main6, this);
TextView textView = (TextView) findViewById(R.id.custom_text);
TypedArray t = context.obtainStyledAttributes(a, R.styleable.Viewee);
siblingResourceId = t.getResourceId(R.styleable.MyCustomView_siblingResourceId, NO_ID);
t.recycle();
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
if (siblingResourceId != NO_ID) {
siblingView = ((View) getParent()).findViewById(siblingResourceId);
}
}
}
onAttachedToWindow
はかなり早い段階で呼び出されますが、ビュー階層全体が落ち着くのに十分遅いようです。それは少なくとも私のニーズには完璧に機能し、もう少し制御されており、機能するために外部からの対話を必要としません;-)
編集: Kotlinコードが追加されました
class MyCustomView(context: Context, attributeSet: AttributeSet) : LinearLayout(context, attributeSet) {
private val siblingResourceId: Int
private lateinit var siblingView: View
// All other constructors left out for brevity.
init {
inflate(context, R.layout.main6, this)
val textView = findViewById<TextView>(R.id.custom_text)
val t = context.obtainStyledAttributes(a, R.styleable.Viewee)
siblingResourceId = t.getResourceId(R.styleable.MyCustomView_siblingResourceId, NO_ID)
t.recycle()
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
if (siblingResourceId != NO_ID) {
siblingView = (parent as View).findViewById(siblingResourceId)
}
}
}
注:このカスタムparent
のView
はView
自体であると想定しています。
説明したAndroid:id
はapp:linkedView="@+id/tvTest
に設定されます。ただし、@+id/tvTest
は、「tvTest」という名前の新しいIDを作成するために使用されます。あなたがしたいのはapp:linkedView="@id/tvTest
を使うことです。