Wowzer
Wowzer

Reputation: 1161

Textview not displaying in custom viewgroup even when onMeasure() is called

So I am just playing around in android and found something really strange. Before I states what is wrong let me give the code.

Here is my Custom Viewgroup code:

    package com.ayto.android.cleverpad;

import android.content.Context;
import android.graphics.Color;
import android.graphics.RectF;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
    public class noteLayout extends ViewGroup {
    float leftOrientationSize = 0;
    float rightOrientationSize=0;
    public noteLayout(Context activityContext)
    {
        super(activityContext);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
        RelativeLayout mainParent = (RelativeLayout) getParent();
        for (int i = 0; i < getChildCount(); i++) {
            final View child = getChildAt(i);
            child.measure(MeasureSpec.makeMeasureSpec((mainParent.getWidth()/2)-30,MeasureSpec.EXACTLY),MeasureSpec.makeMeasureSpec(200,MeasureSpec.AT_MOST));
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int numberOfChild = getChildCount();
        for (int i = 0;i<numberOfChild;i++){
            View childView = getChildAt(i);
            float childHeight = (float) childView.getMeasuredHeight();
            float childWidth = (float) childView.getMeasuredWidth();
            RectF rect = new RectF();
            rect.bottom = childHeight+20;
            rect.top = 20;
            rect.left = 20;
            rect.right = childWidth+20;
            childView.layout((int) rect.left, (int) rect.top, (int) rect.right, (int) rect.bottom);
        }
    }
}

and here is the xml file that I add (addView()) to CustomView:

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" android:background="@android:color/holo_blue_bright">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Title"
        android:id="@+id/displayNoteTitle"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Test"
        android:id="@+id/displayNote"
        android:padding="5dp"
        android:paddingBottom="10dp"
        android:paddingLeft="5dp"
        android:ellipsize="end"
        android:layout_above="@+id/displayNoteTitle"
        android:layout_alignRight="@+id/displayNoteTitle"
        android:layout_alignEnd="@+id/displayNoteTitle" />

</RelativeLayout>

So basically what I did was create an instance of my noteLayout note = new noteLayout(getApplicationContext()) and use the layout inflater to inflate the views from my xml. Then I use noteLayout.addView() to add the inflated view into my custom viewgroup. My problem is that only the textview with the android:Text = "Title" is displayed and the other seem to not render. I am not so sure why this is the case.

enter image description here

ActivityMain

import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.view.Menu; 
import android.view.MenuItem; 
import android.widget.RelativeLayout; 

public class MainActivity extends AppCompatActivity { 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_main); 
noteLayout test = new noteLayout(getApplicationContext()); 
test.addView(getLayoutInflater().inflate(R.layout.Layout,null)); 
((RelativeLayout) findViewById(R.id.mainActivity)).addView(test); 
} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
// Inflate the menu; this adds items to the action bar if it is present. 
getMenuInflater().inflate(R.menu.menu_main, menu); 
return true; 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
// Handle action bar item clicks here. The action bar will 
// automatically handle clicks on the Home/Up button, so long 
// as you specify a parent activity in AndroidManifest.xml. 
int id = item.getItemId(); 

//noinspection SimplifiableIfStatement 
if (id == R.id.action_settings) { 
return true; 
} 

return super.onOptionsItemSelected(item); 
} 

}

Upvotes: 1

Views: 272

Answers (1)

AL.
AL.

Reputation: 37798

Okay. So after our discussion, managed to see what was happening.. I'll explain it thoroughly as it might be confusing.. First of.. In the MainActivity the noteLayout was initialized like so:

noteLayout test = new noteLayout(getApplicationContext());

and is then passed with another RelativeLayout that contains the 2 TextViews :

((RelativeLayout) findViewById(R.id.mainActivity)).addView(test);

So now, the hierarchy would look like this: RelativeLayout(activity_main)
-- RelativeLayout(one from xml)
---- TextView(title)
---- TextView(body)

And in the code of noteLayout in onMeasured() this line appears:

RelativeLayout mainParent = (RelativeLayout) getParent();

-- which means that the mainParent it gets is the RelativeLayout of the MainActivity (R.layout.activity_main), after that, the loop was made:

for (int i = 0; i < getChildCount(); i++) {
            final View child = getChildAt(i);
            child.measure(MeasureSpec.makeMeasureSpec((mainParent.getWidth()/2)-30,MeasureSpec.EXACTLY),MeasureSpec.makeMeasureSpec(200,MeasureSpec.AT_MOST));
        }

To verify this, I put a log inside the loop and it returns only 1 child. So what I did is modify the loop like so:

RelativeLayout mainParent = (RelativeLayout) getParent();
        final RelativeLayout child = (RelativeLayout) getChildAt(0);
        child.measure(MeasureSpec.makeMeasureSpec((mainParent.getWidth() / 2) - 30, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((mainParent.getHeight() / 2) - 30, MeasureSpec.EXACTLY));
        Log.d("SAMPLE", "RelativeLayout Child childcount: " + child.getChildCount());
        for (int i = 0; i < child.getChildCount(); i++) {
            Log.d("SAMPLE", "In loop: " + i);
            final View childOfChild = child.getChildAt(i);
            childOfChild.measure(MeasureSpec.makeMeasureSpec((mainParent.getWidth() / 2) - 30, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(200, MeasureSpec.AT_MOST));
        }

You can see here that I treated the child of the first RelativeLayout as another RelativeLayout then made the loop using the child.getChildCount(). Also (I just added default measure for the second RelativeLayout, you can edit it to whichever you prefer). This calls the TextViews properly now as to what you would expect from your code.

Here is a screenshot after running the code.

enter image description here

So overall. I just edited out the onMeasure() part of your code.. The main problem was just with which layout you were referring and looping. :D

Upvotes: 1

Related Questions