开发者

Why setting text from onMeasure does not affect TextView?

There is a TextView of a certain size and whenever text set to it is too long I'd like to re-set it to some preset value.

To accomplish this I am overriding onMeasure and calling setText. However this does not affect the TextView content开发者_运维问答s.

What am I missing?

EDIT: if you think that it should be done in a completely different way - please feel free to suggest


onMeasure() is usually called during layout phase. Besides as far as I know onMeasure() is where YOU have to measure your view. It receives 2 values which are the size of the parent of your view which may be constant.

Why don't you just check the length of the text you're setting and if it's too long just replace it with your default one?


From the View documentation page.

Measure the view and its content to determine the measured width and the measured height. This method is invoked by measure(int, int) and should be overriden by subclasses to provide accurate and efficient measurement of their contents.

If you want the textview to have limited width or height call setMaxWidth() setMaxHeight() setMaxLines() or check it manualy and change is the way you like from a custom method


In your onMeasure(int,int)

  1. CALL super(int,int)
  2. Use getMeasuredWidth() and getMeasuredHeight

something like this:

void onMeasure(int a, int b){
    super(a,b);
    if(getMeasuredWidth()>bla)
        setText("default");
}


This is what I do to reduce the text font in case the text content is large enough to goto the next line. The problem is pretty much the same the only difference in your case is that you want to replace it with some other default text.

ViewTreeObserver vto = ((TextView)findViewById(R.id.myTextView)).getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

            @Override
            public void onGlobalLayout() {

                if (null != ((TextView)findViewById(R.id.myTextView))) {
                    if (1 < ((TextView)findViewById(R.id.myTextView)).getLineCount()) {
                    ((TextView)findViewById(R.id.myTextView)).setTextSize(TypedValue.COMPLEX_UNIT_PX,
                              ((TextView)findViewById(R.id.myTextView)).getTextSize() - 2);
                    }
                }

           }
});

This would take care of your length dynamically. Now the text size or length cannot be fixed as based on different form factors it would change. For instance a 20 character text in 3.2 inch screen would be decidedly large however it would be too small for 4.1 inch screen. So I would suggest you to use line count as the reference and if the text wraps then you can either reduce the font like I do or replace it by something else.


You could register a custom TextWatcher with addTextChangedListener (TextWatcher watcher).

Inside the TextWatcher you would override the afterTextChanged(Editable s) function, mesure the lenght of the text, and if too long, set it back to your default text.

EDIT: I'm not too sure about this, but this is why I think your solution with onMeasure is not working: onMeasure is called on the initial layout phase, or when the UI needs to be resized, so once your UI is set, if you change the text of the UI afterwards, and the text becomes too long, this doesn't affect the size of the TextView, and onMeasure is not called again...

AnyWay better to just look out for text changes, and do what you want when it's over a limit, and let Android do the dirty TextView measurement work


You will want to implement Textwatcher and in the onTextChanged(...) method, call TextView's setEms(...) method, which will set the width of the TextView to the width of (n m's), where n is the input for setEms(...).

...
TextView tv = (TextView) findViewById(R.id.my_text_view);
tv.addTextChangedListener(this);
...
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
    tv.setEms(count);
}


This is my idea:

You can measure the text trivially with .length() if its length is bigger than your desired limit, than cut put only the substring. But if you want to display entire text you can implement onClickListener() on that TextView which envoking will show entire text as Dialog or whatever.

Another approach which I think can be suitable is to create different layouts for different density screens and then add in your xml android:maxLines="your limit" android:textSize="some value" and android:maxLength="@integer/mylimit" (different limit and size for different density). So what remains is to measure the length and only show the substring (or default text)


Something like:

String myText = "bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla";
String clickForMore="...Click for more";
int limit =  myActivity.this.getResources().getInteger(R.integer.limit); //dont forget to declare it in your string.xml

Imagine we have 3 lines of text and we permitted only 2 (with total length value of int limit). Slice of our text fits inside the TextView, but it is not entirely shown. We need to inform the user that there is more to read...

    myTextView.setVisibility(View.INVISIBLE);// <--- takes the space in the container
    if(clickForMore.length() < myText.length() && myText.length() > limit)// <--- avoiding negative place and checking if the entire text is inside the box or there are characters leftover.
    {
    String temp = myText.substring(0, limit-clickForMore.length());// <-- we cutting space from currently displayed (not original string)  to append the `clickForMore` string information.
    myTextView.setText(temp+clickForMore);
     myTextView.setVisibility(View.VISIBLE);
     myTextView.setOnTouchListener(new OnTouchListener() {

        @Override
    public boolean onTouch(View v, MotionEvent event) {
    // display the dialog with full text....
    return false;
                }

}); //<--- instantiate the click listener 
    }
    else
    {
       //the text fits the box and no need to slice it, just display it straight forward
    }

myText.length() > limit - Test whether the string overlaps the limit. Implement .addTextChangeListener() (TextWatcher) and in afterTextChange() override method implement all these I mentioned above.

Then you create onClickListener() for the TextView where you make dialog and then show your text as it is.


I hope you find this idea, reasonable. If you need more explanation what I had in mind feel free to write me.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜