findViewById() returns 自定义视图中的 null

findViewById() returns null from a custom view

我是 Android 编程新手。我有一个 Main Activity 实现了一些 TextViewcustom-view 的布局。布局是这样的:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">


<TextView
    android:id="@+id/turnTextView"
    //and other tags
    />

    <com.example.crosstheboxprova.GameMap
    android:id="@+id/gameMapView"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:layout_marginStart="0dp"
    android:layout_marginLeft="0dp"
    android:layout_marginTop="0dp"
    android:layout_marginEnd="0dp"
    android:layout_marginRight="0dp"
    android:layout_marginBottom="0dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/turnTextView" />

</android.support.constraint.ConstraintLayout>

custom-view 是这样的:

public class GameMap extends View {

private TextView tv;


public GameMap(Context context) {
    super(context);
    init(context);
}

public GameMap(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public GameMap(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context);
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public GameMap(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    init(context);
}

private void init(Context context){
    //do I have to use the context in some way? 
    //here or on other part of the class I need something like:
    tv = findViewById(R.id.turnTextView); //returns null
    tv.setText("hello");
}



@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    /***/
}



@Override
public boolean onTouchEvent(MotionEvent event) {

}

}

主要Activity是这样的:

public class MainActivity extends AppCompatActivity {
private GameMap gameMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(R.layout.activity_main);
    gameMap = new GameMap(this);

}
}

问题是,当我调用 FindViewById() 访问 TextView 并从 custom-view 内部设置文本时,它 returns null 并抛出 NullPonterException.如何从 custom-view 中访问 TextView

首先你必须创建一个 custom_layout.xml 并把你的 TextView 和任何你想使用的小部件像这样:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/txt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

然后在 class GameMap 的 init() 方法中初始化你的 custom_layout :

public class GameMap extends LinearLayout {
.
.
.

     private void init(Context context) {

            View rootView = inflate(context, R.layout.sampel, this);
            tv = rootView.findViewById(R.id.txt);
            tv.setText("hello");
        }

然后在您的 MainActivity layout.xml

中添加您的 custom_layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">


    <com.example.crosstheboxprova.GameMap
    android:id="@+id/gameMapView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    />

</android.support.constraint.ConstraintLayout>

并在您的 MainActivity class 中:

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_main);

        GameMap gameMap = (GameMap) findViewById(R.id.gameMapView);

//        And continue the code ...
    }
}