0

I am just learning Java and XML and am trying to set a TextView to be in the center of its parent RelativeLayout. My App only loads when I comment out the last 3 lines before the setContentView(homeScreen)

Here is my XML:

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

</RelativeLayout>

Here is my Java:

package com.example.android.testerapp1;

import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);


    TextView homeScreen = new TextView(this);
    homeScreen.setText("Welcome to Test App 001" + "\nThis TextView was created dynamically in Java!");
    homeScreen.setTextSize(24);
    homeScreen.setTextColor(Color.CYAN);
    homeScreen.setCursorVisible(true);
    homeScreen.setPadding(16,56,16,56);
    homeScreen.setBackgroundColor(Color.BLACK);
    homeScreen.setGravity(Gravity.CENTER);

    //dynamically set width to dp (converted to pixels ~600) and height to 'wrap content'
    // convert dp amount to pixels for size
    final float scale = getResources().getDisplayMetrics().density;
    int pixelWidth = (int) (2000 / scale + 0.5f);

    homeScreen.setLayoutParams(new ViewGroup.LayoutParams(pixelWidth , ViewGroup.LayoutParams.WRAP_CONTENT));

    RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)homeScreen.getLayoutParams();
    params.addRule(RelativeLayout.CENTER_IN_PARENT);
    homeScreen.setLayoutParams(params);


    setContentView(homeScreen);
    }
}

I have seen this sort of post about 10 times now and they all have the same solution which I can't seem to implement correctly, it may be another part of my code? Possibly where I set the width and height usingsetLayoutParamsalso?

Cœur
  • 37,241
  • 25
  • 195
  • 267

2 Answers2

1

The setContentView() call is supposed to be used to set the layout of the full screen. What you're doing currently in your Activity code is setting just a TextView as the full view of the screen, so the Activity has no reference to the XML layout that you created. This is why your 3 lines of code at the end fail, because the TextView is trying to setup its LayoutParams for how its parent should place and measure it, however it has no parent in this context. What I would recommend doing is giving an id attribute to the RelativeLayout in the XML to get a reference to it in Activity code like so:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="home_screen_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"/>

Then in your Activity code, adjust it so that you call with the resource id of your XML file. If we assume it's called act_main.xml in the layout folder of your resources directory (i.e. in src/main/resources/layout/act_main.xml), you would call setContentView(R.layout.act_main) as the first line in onCreate() after the super() call so that the framework has an opportunity to parse your XML and inflate it (i.e. instantiate, make calculations on the size and determine placement of its components among other things). After that, use findViewById(R.id.home_screen_layout) to get a reference to that RelativeLayout so that you may create a new TextView and add it to your already inflated layout.

package com.example.android.testerapp1;

import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // make your view components private members as findViewById calls are expensive for the framework
    private RelativeLayout homeScreenLayout;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Have the activity inflate the XML file with your RelativeLayout
        setContentView(R.layout.act_main);

        // Now that it is inflated, get a reference to that parent
        homeScreenLayout = (RelativeLayout) findViewById(R.id.home_screen_layout);

        // Dynamically create a TextView associated with this Activity's context
        TextView homeScreen = new TextView(this);
        homeScreen.setText("Welcome to Test App 001" + "\nThis TextView was created dynamically in Java!");
        homeScreen.setTextSize(24);
        homeScreen.setTextColor(Color.CYAN);
        homeScreen.setCursorVisible(true);
        homeScreen.setPadding(16,56,16,56);
        homeScreen.setBackgroundColor(Color.BLACK);
        homeScreen.setGravity(Gravity.CENTER);

        //dynamically set width to dp (converted to pixels ~600) and height to 'wrap content'
        // convert dp amount to pixels for size
        final float scale = getResources().getDisplayMetrics().density;
        int pixelWidth = (int) (2000 / scale + 0.5f);

        // Adjust the placement in the parent
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(pixelWidth , RelativeLayout.LayoutParams.WRAP_CONTENT)    
        params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); // make sure to use the function which takes a boolean value for rules like CENTER_IN_PARENT
        homeScreen.setLayoutParams(params); // Add these parameters to the textview

        // Let the layout know about your newly created textview so that it can re-draw its canvas
        homeScreenLayout.addView(homeScreen);

    }
}

As a note, I will add that a of what you're doing can be done in the XML with relative ease, but since you asked about setting it programmatically specifically, I won't go into detail on that aspect. But if you're interested in some structured resources, I would recommend checking out the Android Developer Guide, specifically the section on XML layouts and how they interact with Activities

EDIT: Note the changes I made to the code for the Activity. The major pieces are first inflating the empty RelativeLayout xml with setContentView(int id), and then adding the other TextView to the given layout. There was a minor error in the code I presented concerning the CENTER_IN_PARENT line. According to the [docs](https://developer.android.com/reference/android/widget/RelativeLayout.LayoutParams.html#addRule(int, int)), you must use the addRule(int, int) version of the function when adding rules that use a boolean value.

shiv
  • 206
  • 1
  • 7
  • This makes complete sense, since it has no parent to go to the center of. However I'm trying to create the TextView dynamically in Java as an exercise, so your answer is only partly helpful. I think I need to add the TextView to the RelativeLayout first and `setContentView` to the RelativeLayout? I have tried `RelativeLayout homeLayout = (RelativeLayout)findViewById(R.id.homeLayout);` and then `homeLayout.addView(homeScreen);` but it doesnt run even after changing to `setContentView(homeLayout);`.... – MechatronicsStudent Aug 25 '17 at 15:45
  • Even when I dont use `homeLayout.addView(homeScreen);` and ignore my `homeScreen` completely it still crashes. I believe the problem is in `RelativeLayout homeLayout = (RelativeLayout)findViewById(R.id.homeLayout);` then `setContentView(homeLayout);` app doesnt even show the 'Hello World' from my preview window, it just goes black and closes. Is there a way of adding the homeScreen to the RelativeLayout in java and still call `setContentView(R.layout.activity_main)`? – MechatronicsStudent Aug 25 '17 at 16:37
  • Well, I'll say that if you want to create all the layout components programmatically, including your `RelativeLayout`, then you would instantiate all of your views and pass in the `RelativeLayout` to the correct `setContentView(View view, ViewGroup.LayoutParams param)` call (note the function parameters as documented [here](https://developer.android.com/reference/android/app/Activity.html#setContentView(android.view.View))). Since you just want to add the TextView dynamically, you call `setContentView(int id)` and then use `findViewById()` to to the `RelativeLayout` – shiv Aug 28 '17 at 23:04
0

You can set width and height on the constructor and then use it

Relative.LayoutParams(int width, int height)

so you need to do like:

homeScreen.setLayoutParams(width , height);
Rodriquez
  • 981
  • 1
  • 7
  • 21
  • Unfortunately I get an error that i'm not passing two 'int' to 'setLayoutParams' method - I initially tried your method but after researching like https://stackoverflow.com/questions/9678785/android-setting-layoutparams-programmatically & https://stackoverflow.com/questions/4854492/setting-width-to-wrap-content-for-textview-through-code – MechatronicsStudent Aug 24 '17 at 22:16