2013-07-04 20 views

Trả lời

12

Vì vậy, câu trả lời, đáng ngạc nhiên là "có". Tôi đã học về điều này gần đây, và nó thực sự là một cái gì đó bạn có thể làm để làm cho lạm phát xem tùy chỉnh của bạn hiệu quả hơn. IntelliJ vẫn cảnh báo bạn rằng nó không hợp lệ (mặc dù nó sẽ biên dịch và chạy thành công) - Tôi không chắc liệu Eclipse có cảnh báo bạn hay không.

Dù sao, vì vậy những gì bạn cần làm là xác định lớp con của riêng bạn 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; 
    } 
} 

Sau đó, trong bất cứ hoạt động hay bối cảnh mà bạn đang thổi phồng một cách bố trí có chứa những quan điểm tùy chỉnh, bạn sẽ cần phải gán nhà máy của mình vào LayoutInflater với bối cảnh đó:

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

sau đó, bạn có thể sử dụng tên lớp đơn giản trong XML của bạn:

<?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 cho tôi biết rằng không có LayoutInflater.Factory – Ragnar

+0

@Ragnar Đã có từ API 1 (http://developer.android.com/reference/android/view/LayoutInflater.Factory.html). Bạn đã thêm nhập phù hợp cho nó chưa? – kcoppock

+0

tìm thấy nó, tôi chỉ cần nhập android.view.LayoutInflater – Ragnar

-1

số Bạn cần phải đưa ra "đường dẫn đầy đủ" để lớp học của bạn, nếu không khuôn khổ sẽ không thể để tăng cường bố cục của bạn.

+0

Tôi đã nghĩ rằng có thể xác định một tài nguyên trong xml sẽ có lớp này làm cha mẹ. Không phải nó? – Ragnar

+1

Câu trả lời @kcoppock cho thấy cách giúp khuôn khổ với tìm kiếm, nhưng tôi không thấy bất kỳ lợi ích thực sự nào ở đây. Thay vì mainteance biến chứng. –

+0

@MarcinOrlowski Bên trong, phản chiếu sẽ được sử dụng để tăng lượt xem tùy chỉnh nếu bạn không cung cấp LayoutInflater, vì vậy tôi sẽ nói rằng điều này sẽ cải thiện hiệu suất (mặc dù tôi nghi ngờ đó là một cải tiến đáng chú ý), nhưng tôi đồng ý rằng thêm một số chi phí. – kcoppock

0

Bạn cũng có thể làm điều này:

<view 
    class="com.wehavelongdomainname.android.ui.MyButton" 
    ... /> 

cf. http://developer.android.com/guide/topics/ui/custom-components.html#modifying

+0

Thật sao? Điều này hoạt động trên Lollipop quá? Đó là một cái mới :) – milosmns

+0

@milosmns Tôi không nghĩ nó mới nói chung. (Có lẽ bạn có ý nghĩa mới đối với bạn.) – dcow

+0

Vâng, đã không sử dụng nó trước đây. Tốt nhất! – milosmns

1

Xác định lớp con của riêng bạn về LayoutInflater.Factory có vẻ như rất nhiều công việc của tôi. Đơn giản chỉ cần ghi đè onCreateView của hoạt động() với một số mã chung:

@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; 
} 

Lưu ý quan điểm tùy chỉnh phải nằm trong cùng một gói (tức là trong cùng thư mục) như hoạt động này, nhưng sau đó nó chỉ là một mảnh generic mã bạn có thể tát vào bất kỳ hoạt động nào (hoặc thậm chí tốt hơn, kế thừa từ lớp hoạt động gốc tùy chỉnh). Bạn không phải lo lắng về việc tìm ra cho một lớp học đặc biệt theo quy định tại các giải pháp được cung cấp bởi kcoppock:

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

Bạn đang chắc chắn không tạo ra một lớp học hoàn toàn mới.

Ma thuật thực sự nằm trong lớp thư viện cốt lõi, LayoutInflator.java. Xem cuộc gọi, mPrivateFactory.onCreateView(), dưới đây ?:

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

Bạn thấy đấy, nếu cái gọi là, mPrivateFactory, trả về null (mPrivateFactory sẽ xảy ra là lớp hoạt động của bạn bằng cách này), các LayoutInflator chỉ mang về với phương pháp thay thế khác và tiếp tục lạm phát:

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

Bạn nên xem qua các lớp thư viện bằng trình gỡ lỗi IDE và thực sự xem cách hoạt động của Android.:)

Lưu ý mã, if (-1 == name.indexOf('.')) {, dành cho bạn, những người vẫn khăng khăng đưa vào đường dẫn đầy đủ với chế độ xem tùy chỉnh của bạn, <com.wehavelongdomainname.android.ui.MyButton> Nếu có 'dấu chấm' trong tên, thì creatview() được gọi với tiền tố (tham số thứ hai) là null: view = createView(name, null, attrs);

Tại sao tôi sử dụng phương pháp này là vì tôi đã tìm thấy có lần khi tên gói được di chuyển (tức là thay đổi) trong quá trình phát triển ban đầu. Tuy nhiên, không giống như các thay đổi tên gói được thực hiện trong chính mã java, trình biên dịch không nắm bắt những thay đổi đó và sự khác biệt hiện có trong bất kỳ tệp XML nào. Sử dụng cách tiếp cận này, bây giờ nó không phải.

Chúc mừng.

Các vấn đề liên quan