LayoutInflater を使用してリソースからビューを取得し、それをプログラムで構築されたカスタム ViewGroup に挿入しています。リソースに TextView のみが含まれている場合は正常に機能します。ただし、リソースに LinearLayout が含まれている場合、静かに失敗します。例外はスローされず、カスタム ViewGroup コンポーネントは表示されますが、リソースからのビューは表示されません。
カスタム ViewGroup は、内側のビューの周りに色付きの境界線を配置します。クラスは次のとおりです。
package ask.question;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class BorderViewGroup extends ViewGroup {
private View leftBorder ;
private View topBorder ;
private View rightBorder ;
private View bottomBorder ;
private View innerView = null ;
public BorderViewGroup(Context context) {
super(context);
initBorderViewGroup(context);
}
public BorderViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
initBorderViewGroup(context);
}
public BorderViewGroup(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initBorderViewGroup(context);
}
private void initBorderViewGroup(Context context) {
leftBorder = new View(context);
topBorder = new View(context);
rightBorder = new View(context);
bottomBorder = new View(context);
addView(leftBorder);
addView(topBorder);
addView(rightBorder);
addView(bottomBorder);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// Should probably use argument 'changed'.
int width = r - l;
int height = this.getHeight();
leftBorder.layout(0, 0, 2, height);
topBorder.layout(0, 0, width, 2);
rightBorder.layout(width-2, 0, width, height);
bottomBorder.layout(0, height-2, width, height);
if (innerView != null) {
innerView.layout(2, 2, width-2, height-2);
}
}
/*
* Sets the view to be displayed within the borders.
* Subsequent calls will replace the view.
* @param view View to be displayed. May be null.
*/
public void setInnerView(View view) {
if (innerView!=null) {
this.removeView(innerView);
}
this.innerView = view ;
if (innerView!=null) {
addView(innerView);
}
}
/*
* Sets the colors for each of the four borders.
* A color value of zero will be ignored, leaving that border unchanged.
* Note: colors can be specified in hexadecimal. Red is 0xFFFF0000. In general, the first two hex digits control transparency, the next red, green and blue.
*/
public void setBorderColors(int leftColor, int topColor, int rightColor, int bottomColor) {
if (leftColor!=0) leftBorder.setBackgroundColor(leftColor);
if (topColor!=0) topBorder.setBackgroundColor(topColor);
if (rightColor!=0) rightBorder.setBackgroundColor(rightColor);
if (bottomColor!=0) bottomBorder.setBackgroundColor(bottomColor);
}
/*
* Sets the color of the border around the innerView.
* A color value of zero will be ignored, leaving the border unchanged.
* Note: colors can be specified in hexadecimal. Red is 0xFFFF0000. In general, the first two hex digits control transparency, the next red, green and blue.
*/
public void setBorderColor(int color) {
setBorderColors(color, color, color, color);
}
}
リソースが TextView の場合は正常に機能します。アクティビティの onCreate() メソッドと、リソース ファイル flat.xml を次に示します。
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BorderViewGroup bvg = new BorderViewGroup(this);
LayoutInflater inflater = LayoutInflater.from(this);
//View mainView = inflater.inflate(R.layout.flat, null);
View mainView = inflater.inflate(R.layout.nested, null);
View objectView = mainView.findViewById(R.id.object_view);
if (mainView==null) throw new RuntimeException("mainView is null");
if (objectView==null) throw new RuntimeException("objectView is null");
bvg.setBorderColors(0xFFFF0000, 0xFF00F0F0, 0xFF00FF00, 0xFF0000FF);
setContentView(bvg);
bvg.setInnerView(objectView);
}
と
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/object_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="View from resource xml." />
上記は正常に動作します。色付きの境界線と「View from resource xml.」というテキストが表示されます。
ただし、リソース ファイルに LinearLayout が含まれていると、静かに失敗します。アクティビティの onCreate() メソッドと、リソース ファイルの nested.xml を次に示します。
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BorderViewGroup bvg = new BorderViewGroup(this);
LayoutInflater inflater = LayoutInflater.from(this);
View mainView = inflater.inflate(R.layout.flat, null);
//View mainView = inflater.inflate(R.layout.nested, null);
View objectView = mainView.findViewById(R.id.object_view);
if (mainView==null) throw new RuntimeException("mainView is null");
if (objectView==null) throw new RuntimeException("objectView is null");
bvg.setBorderColors(0xFFFF0000, 0xFF00F0F0, 0xFF00FF00, 0xFF0000FF);
setContentView(bvg);
bvg.setInnerView(objectView);
}
と
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/object_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tv"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="A TextView from resource XML." />
<TextView
android:id="@+id/here"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="A second TextView." />
</LinearLayout>
これは動作しません。色付きの境界線は表示されますが、テキストは表示されません。
一方が機能し、もう一方が機能しないのはなぜですか? さらに良いことに、LinearLayout を機能させるにはどうすればよいでしょうか?
ビューが表示されない XML インフレータのインフレータ コードをたどりましたか? . すでに親がいるというエラーが発生するため、インフレからいくつかの引数を削除しました。TextView はそれらがなくても機能します。