2013-02-20 16 views
3

我有一個簡單的LinearLayout只包含一個自定義視圖,延伸TextView(我將開始調用「IdiomView」)和一個ListView。與正常的TextView相比,IdiomView唯一的區別在於,我已經重寫了onDraw()方法來迭代地減小文本大小,直到文本長度小於3行。我的問題是,當意見得出,用戶將看到:如何在別人之後繪製某些視圖?

______________ 
|__ACTION_BAR__| 
| IdiomView | 
|______________| 
|    | 
| ListView | 
|    | 
|    | 
|______________| 

它很快就變成了:

______________ 
|__ACTION_BAR__| 
|__IdiomView __| 
|    | 
| ListView | 
|    | 
|    | 
|    | 
|______________| 

即ListView控件的繪製,然後跳起來後IdiomView已經整理出它的大小。

我想要的是在繪製ListView之前等待我的IdiomView完全繪製的方法。這篇文章What event is fired after all views are fully drawn?解釋瞭如何通過調用View.post(Runnable)來完成繪圖完成後的線程。問題是我重寫了onDraw()方法調用onDraw()多次,以便計算較小的文本是否覆蓋少於3行,因此在我希望ListView出現之前,此元素可能會「完成繪製」多次。

我欣賞所有意見和答案。這裏是我當前的代碼:

佈局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> 

活動:

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()); 

    } 


} 

非常感謝你。

+1

通過使用getPaint()方法,可以避免重複設置文本大小(同時重新繪製小部件)。使用該「Paint」來測量文本在循環中的寬度(使用不同的文本大小),直到您看到兩次將適合可用的最大寬度(對於TextView)的值,並將該直接值用於文本大小 – Luksprog 2013-02-20 21:35:20

+0

感謝Luksprog。這就是我應該如何處理這個問題。 [This thread](http://stackoverflow.com/questions/14276853/how-to-measure-textview-height-based-on-device-width-and-font-size)提供了有關測量TextView的詳細信息。 – 2013-02-21 23:42:21

回答

2

反覆設置文字大小,直到找到合適的字體大小C應該效率很低,因爲您的TextView需要每次重新測量和重新繪製。而不是這樣做,您可以通過使用其TextView.getPaint()方法來測量和設置文本一次。您可以在一個循環中使用Paint來測量文本,以提供不同的字體大小,直到Paint.measureText()返回的值低於窗口小部件當前寬度的兩倍。

+0

如果長度超過最大寬度的兩倍,則循環播放時間仍可以跨越三行,如果長度較長的文字覆蓋到三分之一,則只需使用最大高度進行測量。 – 2013-02-22 10:48:26

+0

@WilliamCarter我忘記了這一點,你仍然可以測量寬度,但它需要額外的檢查,看看文本的一半站在哪裏(在一個字或空的空間),並從那裏進行一些調整。 – Luksprog 2013-02-22 11:54:09

3

我從來沒有在View之前試過這個,但我認爲它可以幫助您的應用程序只在IdiomView繪製後與ListView一起使用。您可能能夠使用偵聽器來實現此目的。但是,它會要求您使用方法後面的代碼。

IdiomView

public static interface OnDrawComplete { 
    public abstract void onDrawComplete(); 
} 

private OnDrawComplete mListener; 

public IdiomView(Context context) {  
    super(context); 
    // this forces it to make sure it's actually an activity 
    // context so you can get a listener 
    if (context instanceof Activity) 
     this.mListener = context; 
} 

現在,在您的繪圖結束,稱之爲

if (this.mListener != null) 
    this.mListener.onDrawComplete(); 

這將調用創建對象的活動和它的繪圖通知創建的接口。所以,你的活動範圍內,就實現接口

public void onDrawComplete() { 
    // After the draw completes, it calls this callback. 
    // setup the rest of your layout now 
    mQuoteList = (ListView) findViewById(R.id.quote_list); 
    this.populateQuoteList(); 
} 

您可能還可以調用this.mListener.onDrawComplete();在某種其他View事件,但我無法找到一個比較合適。你提到View.post(runnable),這可能會工作,但我從來沒有使用過這樣的事情。

最大的潛在問題是,我不知道IdiomView將如何接收上下文或哪一個。在這種情況下,您需要實現接口的環境的Activity環境。

如果它沒有得到正確的上下文,可能需要手動實例化並將其添加到佈局以使用此方法。

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    mIdiomTextView = new mIdiomTextView(this); 
    // add to the Layout manually. 
} 

這裏更多的是它充實

IdiomView

public class IdiomView extends TextView { 
    public static interface OnDrawComplete { 
     public abstract void onDrawComplete(); 
    } 

    private OnDrawComplete mListener; 

    public IdiomView(Context context) {  
     this(context, 0); 
    } 

    public IdiomView(Context context, AttributeSet attrs){ 
     super(context, attrs); 
     if (context instanceof Activity) 
      this.mListener = context; 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     super.onDraw(canvas); 
     // do your drawing code here 
     // ... 
     // after drawing, call the listener, which tells your 
     // Activity to deal with the ListView. 
     if (this.mListener != null) 
      this.mListener.onDrawComplete(); 
    } 
} 

活動

public class MyActivity extends Activity implements IdiomView.OnDrawComplete { 
    //... 

    private IdiomView mIdiomTextView; 
    private ListView mQuoteList; 

    public void onDrawComplete() { 
     // After the draw completes, it calls this callback. 
     // setup the rest of your layout now 
     mQuoteList = (ListView) findViewById(R.id.quote_list); 
     this.populateQuoteList(); 
     // now show the ListView 
     mQuoteList.setVisibility(View.Visible); 
    } 

    private void populateQuoteList() { 
     // populate your ListView here 
    } 
} 
+0

這是一個很棒的答案,它回答了我完美問的問題。然而,在實現這個答案之後,我計算了我的'IdiomView'完成繪圖需要多長時間,差不多有半秒。我問的問題很糟糕,其他問題相同的人應該看Luksprog的評論(上面),他的方法需要大約50毫秒。 – 2013-02-21 23:44:04

+0

很高興你解決它。看看Luksprog是否會將它添加爲答案,以便您可以接受它。 – Kirk 2013-02-22 00:01:04

相關問題