4

I made a custom component that extends View and overrides its onMeasure(), the content of this component is some text, then I add it to a RelativeLayout, but this text can't display, if I comment onMeasure() that been overridden the text shows. What's the reason?

Here is the code:

public class CustomView extends View {
    private String text;
    private int viewWidth;
    private int viewHeight;
    private Paint paint;
    private FontMetrics fontMetrics;
    public CustomView(Context context) {
        this(context, null);
    }
    public CustomView(Context context, String text) {
        this(context, text, 0);
        this.text = text;
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);

        updateViewBounds();
    }
public CustomView(Context context, String text, int defStyle) {
    super(context);

}
private void updateViewBounds(){
    viewWidth = (int) paint.measureText(this.text);
    fontMetrics = paint.getFontMetrics();
    viewHeight =  (int)(fontMetrics.descent - fontMetrics.ascent);      
}
private String getText() {
    return this.text;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    setMeasuredDimension(viewWidth, viewHeight);
    //setMeasuredDimension(560, 100);even though give a ensured size, it can't //anyway.
}
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    paint.setColor(Color.WHITE);
    paint.setTextSize(30);
    canvas.drawText(text, 0, 200, paint);
    Log.e("content", ""+this.getText());
}
public boolean onTouchEvent (MotionEvent event){
    Log.e("Touch", ""+this.getText());
    return false;

}

}

Here is the Activity:

public class CustomViewActivity extends Activity {
    /** Called when the activity is first created. */
    private RelativeLayout contentLayout;
    private CustomView view1;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        contentLayout = (RelativeLayout)findViewById(R.id.contentLayout);
        view1 = new CustomView(this, "You drive me crazy!!!");
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        view1.setLayoutParams(layoutParams);
        contentLayout.addView(view1);
    }
}

this is the XML file:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/contentLayout"
    android:layout_width="1024px"
    android:layout_height="560px"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="126dp"
        android:text="Button" />

</RelativeLayout>
Flexo
  • 87,323
  • 22
  • 191
  • 272
acoustic
  • 4,557
  • 3
  • 19
  • 18

1 Answers1

6

You can absolutely set the MeasureSpec to a different size, however, the arguments for onMeasure are misleading. A MeasureSpec is a specially translated int that has to be specifically created by using both a pixel measure and a flag. The correct way to set a specific size it indicated below...

final int desiredHSpec = MeasureSpec.makeMeasureSpec(pixelHeight, MeasureSpec.MODE_CONSTANT);
final int desiredWSpec = MeasureSpec.makeMeasureSpec(pixelWidth, MeasureSpec.MODE_CONSTANT);
setMeasuredDimension(desiredWSpec, desiredHSpec);

The MODE_CONSTANTS must have a value of one of the following: * AT_MOST - meaning that it is dynamic, but will be clipped if the contents are too large * EXACTLY - meaning it will be that size no matter how large or small the contents are * UNSPECIFIED - meaning that it will make whatever decision it makes according to the parameters of the parents, children, device size, etc...

If you do not specify one of these constants, then the Android Layout rendering engine has no idea what to do, and simply hides the object. It must be understood, that as an open platform for so many devices, Google decided to make the layout engine "dynamic and intelligent" to support as many apps as possible on as many platforms as possible. This simply requires the developer to let the device know exactly what it needs.

Note: It sounds like you want EXACTLY, but think carefully about your choice and how many devices you will be supporting. :)

Fuzzical Logic
  • 12,947
  • 2
  • 30
  • 58
  • Fuzzical Logic, thanks for your answer!By doing what you proposal,the Text can show out now! But the new problem is:when touch the other parts of screen,it also respone for onTouchEvent() that was been override.To fire up onTouchEvent() by just touch the text,what to do?? – acoustic Jan 01 '12 at 10:54
  • The onTouchEvent will fire as long as the View is being touched. And because you are painting the text manually, it does not have a "window" to receive input. If you need this to change, then you need to manually detect (in your onTouch) whether or not your finger is over the text OR Another alternative is to make a child TextView inside your CustomView, and simply set the Child's OnTouchListener. – Fuzzical Logic Jan 02 '12 at 07:36
  • the purpose of this custom View is:it contains a text and some graphic effects that not add in yet(like color, scale, circle ...). I want the view's size is as large as text, so I can just touch the text to make some effects and Activity happen. – acoustic Jan 04 '12 at 03:28
  • Well, then you have to setMeasuredDimensions according to the size of the Text, rather than a constant size like in your code. Then you should have no problems. :) It looks like you already have the code to get the size of the Text, so that's not too bad it all. Just use those numbers in your onMeasure(). – Fuzzical Logic Jan 04 '12 at 12:12
  • 2
    in `setMeasuredDimension()` method first argument will be width and second will be height. You interchanged both arguments. – Dharmendra Jul 10 '12 at 05:39
  • ROFL. +10! So I did. Thank you for pointing that out. This post has been up for months and no one caught it. Fixed! – Fuzzical Logic Jul 10 '12 at 09:31