25

我有一個簡單的自定義的TextView,設置自定義字體在其構造像下面錯誤「requestLayout()不正確的...所謂的」在Android 4.3

public class MyTextView extends TextView { 

    @Inject CustomTypeface customTypeface; 

    public MyTextView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     RoboGuice.injectMembers(context, this); 
     setTypeface(customTypeface.getTypeface(context, attrs)); 
     setPaintFlags(getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); 
    } 
} 

它通過JB 4.2正常工作從薑餅代碼。但是當我在Android 4.3手機上顯示自定義文本視圖時,adb logcat充斥着以下消息。

10-05 16:09:15.225: WARN/View(9864): requestLayout() improperly called by com.cmp.views.MyTextView{42441b00 V.ED.... ......ID 18,218-456,270 #7f060085 app:id/summary} during layout: running second layout pass 
10-05 16:09:15.225: WARN/View(9864): requestLayout() improperly called by com.cmp.views.MyTextView{423753d0 V.ED.... ......ID 26,176-742,278 #7f060085 app:id/summary} during layout: running second layout pass 

我注意到,它確實減慢了UI。任何想法爲什麼它發生在4.3?

感謝您的幫助。

+0

您是否曾嘗試在視圖的生命週期中稍後移動'setTypeface()'和/或'setPaintFlags()',比如'onFinishInflate()'或其他東西?我的猜測是'setTypeface()'正在觸發一個'requestLayout()',因爲它們可能不希望它在視圖構造函數中被調用。 – CommonsWare

+0

我試圖將它移動到onFinishInflate(),這也沒有幫助。我在日誌中看到這些requestLayout()消息 – Sanjay

+0

MyTextView的唯一目的是設置自定義字體嗎?創建自定義視圖來設置cutom字體不是一個好的解決方案。 – GareginSargsyan

回答

2

Looking into the Android source,這個問題是在一個小更詳細地描述:

requestLayout()佈局期間被調用。如果在請求的視圖中沒有設置佈局請求標誌,則沒有問題。如果某些請求仍處於待處理狀態,那麼我們需要清除這些標記並執行完整的請求/測量/佈局傳遞來處理這種情況。

看來問題可能與Roboguice有關;見issue #88。建議的解決方案是使用@InjectView:

您現在可以在視圖類中使用@InjectView。只需撥打Injector.injectMembers()您填寫好圖,翼後:

public class InjectedView extends FrameLayout { 

    @InjectView(R.id.view1) View v; 

    public InjectedView(Context context) { 
     super(context); 
     final View child = new View(context); 
     child.setId(R.id.view1); 
     addView(child); 

     RoboGuice.getInjector(context).injectMembers(this); 
    } 
} 

也許你應該考慮遷移RoboGuice.injectMembers(context, this)使用@InjectView註解視圖對象的聲明。

+2

我沒有使用Roboguice,只是在我的onCreate中設置了一個字體。任何想法,爲什麼會發生在我的情況,或任何解決方法? –

+0

[檢查AOSP源代碼](http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r1/android/widget/TextView.java#TextView.setTypeface %28android.graphics.Typeface%29),'setTypeface()'確實調用'requestLayout()',這很有意義,因爲維度可能需要改變。我不確定爲什麼這可能會導致佈局傳遞衝突。也許你可以嘗試簡化你的佈局?我難住這個。 –

6

我發現這個錯誤發生在我的應用程序中。雖然在您提供的代碼中找不到這種情況(如果您在代碼中的其他位置執行此操作可能會有幫助),但希望可以幫助其他人修復這種不可能的問題。

我有一個線(不是由我添加的,當然):

myView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { 
    @Override 
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 
     //this would then make a call to update another view's layout. 
    } 
}); 

在我的應用程序,我並不需要任何監聽器,所以刪除這整個塊固定的這個問題。對於那些需要這樣的事情,請記住在佈局發生變化後(在此回調中)刪除偵聽器。

0

請檢查天氣任何視圖的Id在同一個活動上下文中重複。我也得到相同的警告,我使用一個TextView重複一個具有相同ID的循環。我通過每次使用不同的ID來解決問題。

+0

我與文本視圖有相同的問題,但無法更改每個人的ID!你可以發佈一些代碼嗎? – Smile2Life

1

我將這些警告修復在我自定義的ListView項目(LinearLayout子類)中。這個類實現Checkable,並具有setChecked(boolean checked)方法被調用,以表明該項目是否被選中:

@Override 
public void setChecked(boolean checked) { 
    mChecked = checked; 
    TextView textView = (TextView)this.findViewById(R.id.drawer_list_item_title_text_view); 
    if(mChecked) { 
     textView.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "font/Andada-Bold.ttf")); 
    } 
    else { 
     textView.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "font/Andada-Regular.ttf")); 
    } 
} 

我目測通過在我看來,一個TextView調用setTypeFace()表示選中狀態,定期和大膽的字體之間切換。這些setTypeFace()調用導致警告。

要解決這個問題,我創建了Typeface S IN類的構造函數實例變量和以後使用它們,當改變字體,而不是調用Typeface.createFromAsset(...)每次:

private Typeface mBoldTypeface; 
private Typeface mRegularTypeface; 

public DrawerView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     initTypefaces(); 
} 

private void initTypefaces() { 
     this.mBoldTypeface = Typeface.createFromAsset(getContext().getAssets(), "font/Andada-Bold.ttf"); 
     this.mRegularTypeface = Typeface.createFromAsset(getContext().getAssets(), "font/Andada-Regular.ttf"); 
} 

@Override 
public void setChecked(boolean checked) { 
    mChecked = checked; 
    TextView textView = (TextView)this.findViewById(R.id.drawer_list_item_title_text_view); 
    if(mChecked) { 
     textView.setTypeface(mBoldTypeface); 
    } 
    else { 
     textView.setTypeface(mRegularTypeface); 
    } 
} 

這是一個非常具體的情景,但我驚喜地發現修復,也許其他人處於相同的情況。

0

我遇到了同樣的問題。這是因爲我試圖用iOS方式設置視圖的位置。你知道在iOS中通過設置視圖的左上角值和寬度,高度來設置視圖的位置。但在Android中,它應該是(左,上,右,下)。我確實對此非常重視。當我進入layout()定義時,我閱讀了方法的評論,然後我找出了警告發生的原因。

相關問題