Pants
Pants

Reputation: 2772

TextView not appearing when programatically adding it to a LinearLayout

Basically as the title says. I have a class that extends LinearLayout and I want that LinearLayout to have a child TextView inside. The problem is, the TextView does not seem to appear.

Here is what I have so far, what exactly am I doing wrong?

Update: I Changed my code as following as you guys have suggested, and my TextView still does not appear....

public class CalendarCourseView extends LinearLayout {

    private int height;
    private int topMargin;
    private Course course;

    public CalendarCourseView(Context context, Course course, int topMargin,
                              int height) {
        super(context);
        final DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
        this.topMargin = (int) TypedValue
                .applyDimension(TypedValue.COMPLEX_UNIT_DIP, topMargin, displayMetrics);
        this.height = (int) TypedValue
                .applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, displayMetrics);
        this.course = course;
        this.setBackgroundColor(course.getColor());
        setTextView();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), this.height);
        ((MarginLayoutParams) getLayoutParams()).topMargin = topMargin;
    }

    private void setTextView() {
        TextView textView = new TextView(this.getContext());
        LayoutParams params = new LayoutParams(new LinearLayout.LayoutParams(ViewGroup
                .LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        textView.setLayoutParams(params);
        textView.setText(course.getName());
        this.addView(textView);
    }

}

Update: I pinned-point the problem. It is with onMeasure. I believe the TextView is not placed in the same position as the LinearLayout after height and topMargin change.

Update: Fixed it simply by changing calling super.onMeasure on onMeasure.

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, this.height);
        ((MarginLayoutParams) getLayoutParams()).topMargin = topMargin;
    }

I believe it is because setMeasuredDimension(int, int) only changes the dimension of the View and not the children. I would also have had to override onLayout. Calling the super.onMeasure also changes the children and simplified things.

Upvotes: 0

Views: 120

Answers (2)

Florent
Florent

Reputation: 1765

Check your code to see if

course.getName()

has a value. Just for testing purposes, you can say

textView.setText("MyCourseName");

for example.

This example below is working correctly for me.

public class CustomView extends LinearLayout {

    public CustomView(Context context) {
        super(context);
        Log.d("CusotmView", "on constructor after super(context)");

        TextView textView = new TextView(this.getContext());
        LayoutParams params = new LayoutParams(new LinearLayout.LayoutParams(ViewGroup
                .LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        textView.setLayoutParams(params);
        textView.setText("MyText");
        this.addView(textView);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.d("CustomView", "onMeasure");
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

Upvotes: 2

BlackHatSamurai
BlackHatSamurai

Reputation: 23483

As it's been mentioned, calling setTextView from the onMeasure method is a bad idea. onMeasure is not always called consistentyly, like onCreate or onStart. On top of that, I don't think that you are properly adding the textView to the main view. I would put the setTextView inside the constructor like so:

public MyView(Context context, Course course, int topMargin,
                              int height) {
        super(context);
        final DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
        this.topMargin = (int) TypedValue
                .applyDimension(TypedValue.COMPLEX_UNIT_DIP, topMargin, displayMetrics);
        this.height = (int) TypedValue
                .applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, displayMetrics);
        this.course = course;
        super.setBackgroundColor(course.getColor());
        this.setTextView();
    }

I will also add that you aren't adding the TextView to the correct view. You are adding it to the super class, rather than the view that has been created. You are going to need to get a reference to the view you are trying to add the layout to. Maybe it would look something like this:

private void setTextView() {
        TextView textView = new ResponsiveTextView(super.getContext());
        LayoutParams params = new LayoutParams(new LinearLayout.LayoutParams(ViewGroup
                .LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        textView.setLayoutParams(params);
        textView.setText(course.getName());
        //You should reference the object being created rather than the super class
        this.addView(textView);

    }

Upvotes: 0

Related Questions