Search code examples
androidandroid-custom-viewfindviewbyid

findViewById() returns null from a custom view


I'm new at Android programming. I have a Main Activity that implements a layout with some TextView and a custom-view. The layout is this:

<?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>

the custom-view is something like this:

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) {

}

}

and the MainActivity is this:

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);

}
}

the problem is that when I call FindViewById() to access a TextView and set the text from inside the custom-view it returns null and throws a NullPonterException. How can I access the TextView from inside the custom-view?


Solution

  • First you must create a custom_layout.xml and put your TextView and any widget you want to use like this :

    <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>
    

    then initialize your custom_layout in init() methode of class GameMap :

    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");
            }
    

    then add your custom_layout in your MainActivity layout.xml

    <?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>
    

    and in your 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 ...
        }
    }