2013-07-04 27 views

回答

12

所以答案,令人驚訝的,是 「是」。筆者近日瞭解到這一點,它實際上是東西,你可以做,使您的自定義視圖通脹更有效。的IntelliJ仍警告你,它的無效(儘管它會編譯併成功運行) - 我不知道是否Eclipse的警告你與否。

無論如何,所以你需要做的就是定義自己的LayoutInflater.Factory子類:

public class CustomViewFactory implements LayoutInflater.Factory { 
    private static CustomViewFactory mInstance; 

    public static CustomViewFactory getInstance() { 
     if (mInstance == null) { 
      mInstance = new CustomViewFactory(); 
     } 

     return mInstance; 
    } 

    private CustomViewFactory() {} 

    @Override 
    public View onCreateView (String name, Context context, AttributeSet attrs) { 
     //Check if it's one of our custom classes, if so, return one using 
     //the Context/AttributeSet constructor 
     if (MyCustomView.class.getSimpleName().equals(name)) { 
      return new MyCustomView(context, attrs); 
     } 

     //Not one of ours; let the system handle it 
     return null; 
    } 
} 

然後,在任何活動或情境中,你會膨脹包含這些自定義視圖的佈局,你需要你的工廠分配給LayoutInflater爲背景:

public class CustomViewActivity extends Activity { 
    public void onCreate (Bundle savedInstanceState) { 
     //Get the LayoutInflater for this Activity context 
     //and set the Factory to be our custom view factory 
     LayoutInflater.from(this).setFactory(CustomViewFactory.getInstance()); 

     super.onCreate(savedInstanceState); 
     setContentView(R.layout.layout_with_custom_view); 
    } 
} 

然後你可以在你的XML使用簡單的類名稱:

<?xml version="1.0" encoding="utf-8"?> 

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
      android:orientation="vertical" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent"> 

    <MyCustomView 
     android:id="@+id/my_view" 
     android:layout_width="match_parent" 
     android:layout_height="60dp" 
     android:layout_gravity="center_vertical" /> 

</FrameLayout> 
+0

Eclipse告訴我沒有LayoutInflater.Factory – Ragnar

+0

@Ragnar自從API 1(http://developer.android.com/reference/android/view/LayoutInflater.Factory.html)以來就一直存在。你爲它添加了適當的導入嗎? – kcoppock

+0

發現了它,我只是不得不進口android.view.LayoutInflater – Ragnar

-1

號你需要給「完整路徑」你的課,否則框架將無法膨脹你的佈局。

+0

我想在xml中定義一個資源可能會將此類作爲父項。不是嗎? – Ragnar

+1

@kcoppock答案顯示瞭如何幫助框架與搜索,但我很遠沒有看到任何真正的好處在這裏。而保持併發症。 –

+0

@MarcinOrlowski從內部來看,如果你不提供LayoutInflater,反射將被用來擴展一個自定義視圖,所以我會說這應該會提高性能(儘管我懷疑它會有明顯的改進),但我同意它的確如此增加一些開銷。 – kcoppock

1

定義自己的LayoutInflater.Factory的子類,似乎很多工作我的。 只需使用一些通用的代碼重寫活動的onCreateView():

@Override 
public View onCreateView(String name, Context context, AttributeSet attrs) { 

    View view; 

    // No need wasting microseconds getting the inflater every time. 
    // This method gets called a great many times. 
    // Better still define these instance variables in onCreate() 
    if (mInflator == null){ 

     mInflator = LayoutInflater.from(context); 

     mPrefix = ((Activity) context).getComponentName().getClassName(); 

     // Take off the package name including the last period 
     // and look for custom views in the same directory. 
     mPrefix = mPrefix.substring(0, mPrefix.lastIndexOf(".")+1); 
    } 

    // Don't bother if 'a path' is already specified. 
    if (name.indexOf('.') > -1) return null; 

    try{ 

     view = mInflator.createView(name, mPrefix, attrs); 

    } catch (ClassNotFoundException e) { 

     view = null; 

    } catch (InflateException e) { 

     view = null; 
    } 

    // Returning null is no big deal. The super class will continue the inflation. 
    return view; 
} 

注意自定義視圖必須駐留在同一個包(即在同一目錄)作爲本次活動,但當時它只是一個普通的一段代碼你可以在任何活動中打耳光(甚至更好,從自定義的父活動類繼承)。 你不擔心在由kcoppock提供的解決方案中指定尋找出某一類:

if (MyCustomView.class.getSimpleName().equals(name)) {....

你肯定不是創建一個全新的類。

真正神奇的是在覈心庫類,LayoutInflator.java。看到通話,mPrivateFactory.onCreateView(),下面?:

if (view == null && mPrivateFactory != null) { 
     view = mPrivateFactory.onCreateView(parent, name, mContext, attrs); 
    } 

    if (view == null) { 
     if (-1 == name.indexOf('.')) { 
      view = onCreateView(parent, name, attrs); 
     } else { 
      view = createView(name, null, attrs); 
     } 
    } 

你看,如果所謂的,mPrivateFactory,返回null(mPrivateFactory恰好是由這樣你的活動類),該LayoutInflator剛剛進行與它的其他替代方法,並繼續通貨膨脹:

if (view == null) { 
    if (-1 == name.indexOf('.')) { 
     view = onCreateView(parent, name, attrs); 
    } else { 
     view = createView(name, null, attrs); 
    } 
} 

這是圖書館類與IDE調試器「穿行」,真正看到Android的作品是一個好主意。:)

請注意,代碼if (-1 == name.indexOf('.')) {適用於仍然堅持使用自定義視圖的完整路徑<com.wehavelongdomainname.android.ui.MyButton>如果名稱中有一個「點」,則creatview()將與前綴(第二個參數)爲空:view = createView(name, null, attrs);

爲什麼我使用這種方法是因爲我發現在初始開發過程中,有些時候程序包名稱被移動(即更改)。但是,與java代碼本身內執行的程序包名稱更改不同,編譯器不會捕獲任何XML文件中現在存在的此類更改和差異。使用這種方法,現在不需要。

乾杯。

相關問題