2016-02-26 19 views
6

Anko docs cho chúng tôi biết cách thêm chế độ xem tùy chỉnh vào DSL. Nhưng nếu chế độ xem tùy chỉnh của tôi là một nhóm chế độ xem thì vấn đề phát sinh.Làm cách nào để thêm các nhóm chế độ xem tùy chỉnh vào Anko DSL?

class MyFrameLayout(context: Context) : FrameLayout(context) 

fun ViewManager.myFrameLayout(init: MyFrameLayout.() -> Unit = {}) = ankoView({ MyFrameLayout(it) }, init) 

class MyUI : AnkoComponent<Fragment> { 
    override fun createView(ui: AnkoContext<Fragment>) = with(ui) { 

     myFrameLayout { 
      textView("hello").lparams { // error: Unresolved reference: lparams 
       bottomMargin = dip(40) 
      } 
     } 
    } 
} 

nhưng nếu tôi thay đổi myFrameLayout gọi đến frameLayout thì hoạt động OK. Vì vậy, cách thích hợp để làm cho các nhóm xem được sử dụng với Anko DSL là gì?

Trả lời

0

Nếu chúng ta xem xét các nguồn Anko, chúng ta có thể thấy rằng frameLayout thực tế trả về một thể hiện của lớp _FrameLayout, trong đó các hàm lparams này được xác định. Theo hiểu biết của tôi, điều này là cần thiết, vì vậy, các chức năng lparams này chỉ có sẵn trong mã xây dựng bố cục.

Trong Anko's Layouts.kt tệp có các lớp _<ViewGroup> cho mọi hỗ trợ ViewGroup.

Vì vậy, cách đơn giản để hỗ trợ nhóm chế độ xem tùy chỉnh là tạo một lớp _<ViewGroup> với việc thực hiện phương pháp lparams. Vấn đề là lớp học _<ViewGroup> này thường chứa nhiều mã hơn chính số <ViewGroup> của tôi!

Và nếu tôi muốn tạo nhiều nhóm chế độ xem tùy chỉnh, việc thêm hỗ trợ Anko cho họ sẽ trở thành nỗi đau lớn với cách tiếp cận này. Giả sử tôi có các lớp học MyFrameLayout1, MyFrameLayout2, MyFrameLayout3. Về cơ bản chúng là FrameLayout vì vậy tôi muốn các thông số bố cục giống nhau được sử dụng với chúng. Nhưng tôi phải tạo các lớp học _FrameLayout1, _FrameLayout2, _FrameLaoyt3 chỉ cần sao chép/dán Anko's _FrameLayout.

Vì vậy, tôi đã cải thiện một chút cách tiếp cận này.Tôi tạo ra một interface _FrameLayout:

interface _FrameLayout { 
    // copy/paste from Anko's _FrameLayout 
} 

và bây giờ để hỗ trợ bất kỳ lớp con tùy chỉnh FrameLayout tôi chỉ có trách nhiệm:

class _MyFrameLayout(ctx: Context) : MyFrameLayout(ctx), _FrameLayout 

fun ViewManager.myFrameLayout(init: _MyFrameLayout.() -> Unit = {})= ankoView({ _MyFrameLayout(it) }, init) 

Điều này làm giảm sao chép/dán rất nhiều, khi tạo nhiều nhóm giao diện tùy chỉnh.

+0

Tôi đã gửi một vấn đề về https://github.com/Kotlin/anko/issues/152 đó – netimen

0

Nếu bạn đi đến bất kỳ lparams tờ khai Anko từ mã của bạn, bạn có thể thấy bên trong Anko tạo ra mã DSL, lparams là một chức năng mở rộng cho T: View mà trông như thế này:

fun <T: View> T.lparams(
     width: Int = android.view.ViewGroup.LayoutParams.WRAP_CONTENT, 
     height: Int = android.view.ViewGroup.LayoutParams.WRAP_CONTENT, 
     init: android.widget.FrameLayout.LayoutParams.() -> Unit = defaultInit 
): T { 
    val layoutParams = android.widget.FrameLayout.LayoutParams(width, height) 
    layoutParams.init() 
    [email protected] = layoutParams 
    return this 
} 

(và quá tải hơn đối với các nhà thầu khác nhau LayoutParams)

Nó được khai báo bên trong một lớp, vì vậy nó chỉ hiển thị trong các chức năng với bộ thu của lớp đó, xem another question về phương pháp lập trình DSL này.


Để có thể sử dụng lparams cho tùy chỉnh của bạn ViewGroup trong Anko DSL, bạn phải khai báo một chức năng tương tự hoặc các chức năng bên trong mã giao diện tùy chỉnh của bạn, điều đó sẽ tạo ra một thích hợp LayoutParams cho lớp học của bạn.

Nếu bạn muốn ẩn chức năng lparams từ bên ngoài DSL, bạn có thể tạo một lớp con của MyFrameLayout và chỉ sử dụng nó trong mã DSL, tự làm việc với MyFrameLayout ở nơi khác.

Sau đó, bạn có thể gọi lparams trên bất kỳ số View bên trong một lambda mà bạn vượt qua dưới dạng init: MyFrameLayout.() -> Unit đến fun ViewManager.myFrameLayout.

3

Trên thực tế bạn chỉ cần phải mở rộng anko và tuyên bố customview của bạn sau đó sử dụng nó trong các DSL thường:

public inline fun ViewManager.customView() = customView {} 
public inline fun ViewManager.customView(init: CustomView.() -> Unit) = ankoView({ CustomView(it) }, init) 

Sau đó, sử dụng nó trong các DSL thường

frameLayout { 
    customView() 
} 
2

nếu bạn kế thừa từ ví dụ _RelativeLayout thay vì RelativeLayout, bạn có thể sử dụng bố cục tùy chỉnh của mình như bạn mong đợi.

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