如何初始化依赖于视图属性的东西

How to initialize stuff that depends on the view’s attributes

说我有这个 class MyView:

public class MyView extends GLSurfaceView {
    private MyRenderer mRenderer;

    public MyView(Context ctx, AttributeSet attrs) {
        super(ctx, attrs);
        init(ctx);
    }

    private void init(Context ctx) {
        mRenderer = new MyRenderer(ctx);
        setRenderer(mRenderer);
    }

    @Override
    public void setBackground(Drawable background) {
        mRenderer.setBackground(background);
    }
}

这是由 MyActivity 膨胀的,像这样:

public class MyActivity extends Activity {
    private MyView mView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        init();
    }

    protected void init() {
        setContentView(R.layout.my_layout);
        mView = (MyView) findViewById(R.id.my_view);
    }
}

据我所知,setBackgroundsetContentView 中被 inflater 调用,在 MyView 中调用 init 之前,因此 mRenderer 尚未初始化还。

好像是第 22 条军规,因为如果没有视图的初始化就无法设置视图的属性,这是在设置属性之后发生的。

这是布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/my_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@drawable/background" >

    <com.developer.app.MyView
        android:id="@+id/my_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/background"
        />

    <TextView
        android:id="@+id/left_arrow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:background="@drawable/left_arrow"
        />

    <TextView
        android:id="@+id/right_arrow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:background="@drawable/right_arrow"
        />

    <TextView
        android:id="@+id/home_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="10dp"
        android:layout_marginTop="10dp"
        android:background="@drawable/home"
        />
</RelativeLayout>

你已经初始化了它的三个函数,例如 xml 和 java 就是你正在做的。

public class MyEditText extends EditText {
    public MyEditText(Context context) {
        super(context);
        this.setTextColor(Color.parseColor("#4789da"));
        this.setBackgroundResource(R.drawable.edittext_back);
        this.setTextSize(18);
        this.setPadding(5,5,5,5);
    }

    public MyEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setTextColor(Color.parseColor("#4789da"));
        this.setBackgroundResource(R.drawable.edittext_back);
        this.setTextSize(18);
        this.setPadding(5,5,5,5);
    }

    public MyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.setTextColor(Color.parseColor("#4789da"));
        this.setBackgroundResource(R.drawable.edittext_back);
        this.setTextSize(18);
        this.setPadding(5,5,5,5);
    }
}

我从你的问题中了解到的。您需要 oncreate() 中的视图属性。但不能这样做。原因是 UI 还没有初始化。有解决办法。 这 link 可能会有所帮助。

getWidth() and getHeight() of View returns 0

你是对的。如果解析了 android:background 属性,则从 View 的构造函数调用 setBackground()。在你的情况下,它在这里调用:

super(ctx, attrs);

如果要将背景设置为mRenderer,可以在init:

中进行
private void init(Context ctx) {
    mRenderer = new MyRenderer(ctx);
    setRenderer(mRenderer);
    final Drawable background = getBackground();
    if (background != null) {
        mRenderer.setBackground(background);
    }
}

并在 setBackground 中添加一个 null-check,因为在将某些值设置为 mRenderer

之前,可以从超类的构造函数中调用此方法
@Override
public void setBackground(Drawable background) {
    if (mRenderer != null) {
        mRenderer.setBackground(background);
    }
}