I have a simple LinearLayout
containing only a custom view extending TextView
(which I shall start calling "IdiomView
") and a ListView
. The only difference in IdiomView
from a normal TextView
is that I have overridden the onDraw()
method to iteratively reduce the text size until the text is less than 3 lines long. My problem is that when the views are drawn, the user will see this:
______________
|__ACTION_BAR__|
| IdiomView |
|______________|
| |
| ListView |
| |
| |
|______________|
which quickly becomes:
______________
|__ACTION_BAR__|
|__IdiomView __|
| |
| ListView |
| |
| |
| |
|______________|
i.e. the ListView is drawn and then jumps up after IdiomView
has sorted out its size.
What I would like is a way to wait until my IdiomView
is fully drawn, before drawing the ListView. This post What event is fired after all views are fully drawn? explains how to line up a thread after the drawing is complete by calling View.post(Runnable)
. The problem is my overridden onDraw()
method calls onDraw()
multiple times in order to calculate the whether the smaller text covers less than 3 lines, so this element probably "finishes drawing" numerous times before I would want the ListView
to appear.
I appreciate all comments and answers. Here's my current code:
layout XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:background="@color/off_white"
android:orientation="vertical" >
<carter.cwords.idioms.IdiomView
android:id="@+id/idiom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="10dp"
android:textColor="@color/transparent"
android:textSize="28sp"
android:textStyle="italic"
android:visibility="invisible" />
<ListView
android:id="@+id/quote_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:choiceMode="none"
android:footerDividersEnabled="false"
android:headerDividersEnabled="false"
android:visibility="invisible" />
</LinearLayout>
Activity:
private IdiomView mIdiomTextView;
private ListView mQuoteList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.idiom_of_the_day);
mIdiomTextView = (IdiomView) findViewById(R.id.idiom);
mQuoteList = (ListView) findViewById(R.id.quote_list);
// Populate page data onResume()
}
@Override
protected void onResume() {
super.onResume();
sendRequest(R.string.url_idiom_of_the_day, new AfterRequest(){
@Override
public void useResults(Document resultXml) {
if(resultXml != null){
Log.i(getClass().getSimpleName(), "useResults()");
String idiomString = XmlUtilities.getTextValue(resultXml, NetworkHelper.XML_TAG_IDIOM_CONTENT);
logDebug("idiomString: " + idiomString);
mIdiomTextView.setText("\"" + idiomString + "\"");
mQuoteList.setAdapter(new ContentAdapter(mContext, resultXml));
mIdiomTextView.setVisibility(View.VISIBLE);
mIdiomTextView.post(new Runnable(){
@Override
public void run() {
mQuoteList.setVisibility(View.VISIBLE);
}
});
}
}
});
}
IdiomView
:
public class IdiomView extends TextView {
public IdiomView(Context context) {
super(context);
}
public IdiomView(Context context, AttributeSet attrs){
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.i(getClass().getSimpleName(), "onDraw(): " + this.getLineCount());
if(this.getLineCount() > 2){
this.setTextSize(TypedValue.COMPLEX_UNIT_PX, this.getTextSize()-1);
}
else{
this.setTextColor(getResources().getColor(R.color.text));
}
Log.i(getClass().getSimpleName(), "onDraw(): " + this.getLineCount());
}
}
Thank you very much.
Setting the text size repeatedly until you find the proper font size could be very inefficient because your TextView
will need to be remeasured and redrawn each time. Instead of doing this, you could measure and set the text only once by using its TextView.getPaint()
method. You could than measure the text with the Paint
in a loop providing it different font sizes until the value returned by Paint.measureText()
is below two times the current width of the widget.