通用式菜單式控件----LineMenuView(二)

之前已寫過關於LineMenuView的使用說明,主要針對 xml+java 這種經典的形式,也就是1.0版本:通用式菜單式控件——LineMenuView(一);

隨着kotlin的興起,很多項目也慢慢的轉向了這位新寵

同樣的,針對一些簡單佈局,會有這種轉變:xml-> anko

LineMenuView升級到版本二後,也集成了anko 功能,這裏會先介紹2.0的使用方法,然後根據源碼來簡單的說明一下anko的原理.

上一篇相同,貼出GITHUB

一 使用步驟

雖然LineMenuView升級到2.0有比較大的改動,但很多情況是兼容1.0的,比如有關xml佈局文件,就沒有任何改變.

不同的是,如果想使用2.0提供的anko功能,需要先添加kotlin+anko環境.

幸運的,androidstudio3.0 之後,默認會提供kotlin環境,至於anko,則可以參照anko-github地址來配置

1. gradle 引入

1.0一樣,添加依賴

    compile 'com.knowledge.mnlin:linemenuview:2.0.2'

2. 選擇提供的anko方法

LineMeneView 提供的 anko方法 放在 AnkoCreate.kt

主要包括以下幾種方法:

* lmv_none 適用於無插件情況
* lmv_text 適用於 text 插件形式
* lmv_switch 適用於 switch 形式
* lmv_radio 適用於 radio 形式
* lmv_select 適用於 select 形式
* lmv_transition 適用於 transition 形式

分別對應attr屬性,即plugin類型

    <!--單行菜單對應的參數:switch狀態、menu文本、icon圖標等-->
    <declare-styleable name="LineMenuView">
        <attr name="LineMenuView_plugin" format="enum">
            <enum name="none" value="0"/>
            <enum name="text" value="1"/>
            <enum name="switch_" value="2"/>
            <enum name="radio" value="3"/>
            <enum name="select" value="4"/>
            <enum name="transition" value="5"/>
        </attr>
        <attr name="LineMenuView_switch" format="enum">
            <enum name="off" value="0"/>
            <enum name="on" value="1"/>
        </attr>
        <!--選中/未選中-->
        <attr name="LineMenuView_radio" format="enum">
            <enum name="off" value="0"/>
            <enum name="on" value="1"/>
        </attr>
        <!--開/關-->
        <attr name="LineMenuView_transition" format="enum">
            <enum name="off" value="0"/>
            <enum name="on" value="1"/>
        </attr>

        <!--用於計算,default表示默認:只有在visible時纔會納入計算;on表示納入計算,即便是不可見狀態;off表示不納入計算,即使是可見狀態-->
        <attr name="LineMenuView_for_calculation" format="enum">
            <enum name="bypassed" value="0"/>
            <enum name="on" value="1"/>
            <enum name="off" value="2"/>
        </attr>

        <!--brief部分-->
        <attr name="LineMenuView_badge" format="reference"/>
        <attr name="LineMenuView_navigation" format="reference"/>
        <attr name="LineMenuView_brief" format="string"/>
        <attr name="LineMenuView_brief_text_color" format="color"/>
        <attr name="LineMenuView_brief_text_size" format="dimension"/>

        <!--menu部分-->
        <attr name="LineMenuView_icon" format="reference"/>
        <attr name="LineMenuView_menu" format="string"/>
        <attr name="LineMenuView_menu_text_color" format="color"/>
        <attr name="LineMenuView_menu_text_size" format="dimension"/>
    </declare-styleable>

關於插件類型,在上一篇裏已有詳細說明

在選擇好對應的方法後,就可以直接在代碼中進行調用:

3. 方法調用

2.0anko提供的方法,都是在1.0中以有的xml屬性值,這裏針對各種插件都進行一次調用,實例代碼可以直接在這裏找到:kotlin代碼實例

verticalLayout {
            //toolbar
            include<AppBarLayout>(R.layout.layout_top_bar)

            //scroll_view
            scrollView {
                overScrollMode = OVER_SCROLL_ALWAYS
                isVerticalScrollBarEnabled = false

                //佈局
                verticalLayout {
                    bottomPadding = dp16
                    topPadding = dp16

                    //無插件
                    var a = lmv_none(menuText = "無插件") {
                        setCalculation(2)

                        setOnClickListener(object : LineMenuListener {
                            override fun performClickLeft(v: TextView): Boolean {
                                showToast("我被點擊了左邊的控件,並且返回了false讓performSelf方法得以執行")
                                return false
                            }

                            override fun performClickRight(v: View): Boolean {
                                //這裏mLmvFirst屬於無插件形式,右側的範圍極小,很難點擊到
                                showToast("我被點擊了右邊的控件,並且阻止了performSelf方法的執行")
                                return true
                            }

                            override fun performSelf(v: LineMenuView) {
                                showToast("只有點擊左邊我纔會執行")
                            }
                        })
                    }.lparams(width = matchParent) { topMargin = dp12 }

                    //文本形式
                    lmv_text(menuText = "文本形式", briefText = "簡要信息").lparams(width = matchParent) { topMargin = dp12 }

                    //文本大小/顏色/改變
                    lmv_text(menuText = "文本大小/顏色/改變", menuTextSizeRes = R.dimen.text_size_large_18sp, menuTextColorRes = R.color.yellow,
                            briefText = "簡要信息", briefTextColorRes = R.color.blue, briefTextSize = dimen(R.dimen.text_size_10sp)).lparams(width = matchParent) { topMargin = dp12 }

                    //帶上箭頭形式
                    lmv_text(menuText = "帶上箭頭形式",
                            briefText = "簡要信息", briefBadgeRes = R.mipmap.mobile_black, briefNavigation = dispatchGetDrawable(R.drawable.icon_arrow_right))
                            .lparams(width = matchParent) { topMargin = dp12 }

                    //帶icon的簡要信息,且信息太長需要一直滾動滾動滾動滾動滾動滾動滾動滾動滾動滾動
                    lmv_text(menuText = "帶icon的簡要信息,且信息太長需要一直滾動滾動滾動滾動滾動滾動滾動滾動滾動滾動", menuIconRes = R.mipmap.mobile_blue,
                            briefText = "簡要信息", briefBadgeRes = R.mipmap.mobile_black, briefNavigation = dispatchGetDrawable(R.drawable.icon_arrow_right))
                            .lparams(width = matchParent) { topMargin = dp12 }

                    //切換模式
                    lmv_transition(menuText = "切換模式",
                            transition = true).lparams(width = matchParent) { topMargin = dp12 }

                    //選中/未選中模式
                    lmv_select(menuText = "選中/未選中模式",
                            select = false).lparams(width = matchParent) { topMargin = dp12 }

                    //radio顯示模式
                    lmv_radio(menuText = "選中/未選中模式",
                            radio = true).lparams(width = matchParent) { topMargin = dp12 }

                    //radio顯示模式
                    lmv_switch(menuText = "switch顯示模式",
                            switch = true).lparams(width = matchParent) { topMargin = dp12;leftMargin = dp16;rightMargin = dp16 }
                }.lparams(width = matchParent).applyRecursively {
                    if (it is LineMenuView) {
                        it.common_padding_bg()
                    }
                }
            }.lparams(width = matchParent, height = matchParent)
        }

這段anko 代碼對應 xml 如下(源碼對應activity_test_activity.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <include layout="@layout/layout_top_bar"/>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="none">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingBottom="@dimen/view_padding_margin_16dp"
            android:paddingTop="@dimen/view_padding_margin_16dp">

            <com.knowledge.mnlin.linemenuview.LineMenuView
                android:id="@+id/lmv_first"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="@color/white_background_5"
                android:paddingEnd="@dimen/view_padding_margin_16dp"
                android:paddingStart="@dimen/view_padding_margin_16dp"
                app:LineMenuView_for_calculation="off"
                app:LineMenuView_menu="無插件"
                app:LineMenuView_plugin="none"/>

            <!--text插件則會包含brief信息-->
            <com.knowledge.mnlin.linemenuview.LineMenuView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/view_padding_margin_12dp"
                android:background="@color/white_background_5"
                android:paddingEnd="@dimen/view_padding_margin_16dp"
                android:paddingStart="@dimen/view_padding_margin_16dp"
                app:LineMenuView_brief="簡要信息"
                app:LineMenuView_menu="文本形式"
                app:LineMenuView_plugin="text"/>

            <com.knowledge.mnlin.linemenuview.LineMenuView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/view_padding_margin_12dp"
                android:background="@color/white_background_5"
                android:paddingEnd="@dimen/view_padding_margin_16dp"
                android:paddingStart="@dimen/view_padding_margin_16dp"
                app:LineMenuView_brief="簡要信息"
                app:LineMenuView_brief_text_color="@color/blue"
                app:LineMenuView_brief_text_size="@dimen/text_size_10sp"
                app:LineMenuView_menu="文本大小/顏色/改變"
                app:LineMenuView_menu_text_color="@color/yellow"
                app:LineMenuView_menu_text_size="@dimen/text_size_large_18sp"
                app:LineMenuView_plugin="text"/>

            <com.knowledge.mnlin.linemenuview.LineMenuView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/view_padding_margin_12dp"
                android:background="@color/white_background_5"
                android:paddingEnd="@dimen/view_padding_margin_16dp"
                android:paddingStart="@dimen/view_padding_margin_16dp"
                app:LineMenuView_badge="@mipmap/mobile_black"
                app:LineMenuView_brief="簡要信息"
                app:LineMenuView_menu="帶上箭頭形式"
                app:LineMenuView_navigation="@drawable/icon_arrow_right"
                app:LineMenuView_plugin="text"/>

            <com.knowledge.mnlin.linemenuview.LineMenuView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/view_padding_margin_12dp"
                android:background="@color/white_background_5"
                android:paddingEnd="@dimen/view_padding_margin_16dp"
                android:paddingStart="@dimen/view_padding_margin_16dp"
                app:LineMenuView_badge="@mipmap/mobile_black"
                app:LineMenuView_brief="簡要信息"
                app:LineMenuView_icon="@mipmap/mobile_blue"
                app:LineMenuView_menu="帶icon的簡要信息,且信息太長需要一直滾動滾動滾動滾動滾動滾動滾動滾動滾動滾動"
                app:LineMenuView_navigation="@drawable/icon_arrow_right"
                app:LineMenuView_plugin="text"/>

            <com.knowledge.mnlin.linemenuview.LineMenuView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/view_padding_margin_12dp"
                android:background="@color/white_background_5"
                android:paddingEnd="@dimen/view_padding_margin_16dp"
                android:paddingStart="@dimen/view_padding_margin_16dp"
                app:LineMenuView_menu="切換模式"
                app:LineMenuView_plugin="transition"
                app:LineMenuView_transition="on"/>

            <com.knowledge.mnlin.linemenuview.LineMenuView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/view_padding_margin_12dp"
                android:background="@color/white_background_5"
                android:paddingEnd="@dimen/view_padding_margin_16dp"
                android:paddingStart="@dimen/view_padding_margin_16dp"
                app:LineMenuView_menu="選中/未選中模式"
                app:LineMenuView_plugin="select"/>

            <com.knowledge.mnlin.linemenuview.LineMenuView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/view_padding_margin_12dp"
                android:background="@color/white_background_5"
                android:paddingEnd="@dimen/view_padding_margin_16dp"
                android:paddingStart="@dimen/view_padding_margin_16dp"
                app:LineMenuView_menu="radio顯示模式"
                app:LineMenuView_plugin="radio"
                app:LineMenuView_radio="on"/>

            <!--注意下劃線-->
            <com.knowledge.mnlin.linemenuview.LineMenuView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/view_padding_margin_12dp"
                android:background="@color/white_background_5"
                android:paddingEnd="@dimen/view_padding_margin_16dp"
                android:paddingStart="@dimen/view_padding_margin_16dp"
                app:LineMenuView_menu="switch顯示模式"
                app:LineMenuView_plugin="switch_"
                app:LineMenuView_switch="on"/>
        </LinearLayout>
    </ScrollView>
</LinearLayout>

這裏列出了各種plugin的各種使用方式,在針對 簡單佈局時,使用anko可以省略大量的代碼.

以上代碼顯示效果和通用式菜單式控件——LineMenuView(一)中顯示效果相同

二 anko 原理淺析

從上面代碼可以看到,anko使用起來有些像是web,或者說其實和xml表現形式相同,那麼系統是如何處理anko呢?對於通用佈局,如何使用anko來定義LineMenuView模版?

1 anko到底是什麼格式?

以一個簡短的anko代碼爲例:

verticalLayout {
    include<AppBarLayout>(R.layout.layout_top_bar)

    scrollView {
        overScrollMode = View.OVER_SCROLL_ALWAYS
        isVerticalScrollBarEnabled = false

        verticalLayout {
            //系統存儲的值
            val locale = DefaultPreferenceUtil.getInstance().localeLanguageSwitch
            val menus = getStringArray(R.array.array_locale_language)

            //初始化界面
            for (i in lmvs.indices) {
                //lmv
                lmvs[i] = lmv_select(menuText = menus[i]) {
                    rightSelect = i == locale
                }.lparams(width = matchParent) {
                    if (i == 0) {
                        topMargin = dimen(R.dimen.view_padding_margin_10dp)
                    }
                }

                //分隔符divider
                if (i < lmvs.size - 1) {
                    dv_line().lparams(width = matchParent)
                }
            }
        }.lparams(width = matchParent).applyRecursively {
            if (it is LineMenuView || it is DividerView) {
                it.horizontalPadding = dimen(R.dimen.view_padding_margin_16dp)
                it.backgroundColorResource = R.color.main_color_white
            }
        }
    }.lparams(matchParent, matchParent)
}

它的效果圖是這樣的:

這裏寫圖片描述

只是一個簡單的仿微信應用語言切換的界面,都是LineMenuView的select類型使用,這裏使用for循環創建LineMenuView控件,然後使用applyRecursively統一處理style

要知道的是,anko 也是符合(必須符合) kotlin語法的,代碼最前的 verticalLayout 以及 includescrollView等,其實是真正的方法:fun,只是由於kotlin最後一個參數爲lam時可以簡寫的規則,看起來比較抽象,例如:

inline fun Activity.verticalLayout(theme: Int = 0, init: (@AnkoViewDslMarker _LinearLayout).() -> Unit): LinearLayout {
    return ankoView(`$$Anko$Factories$CustomViews`.VERTICAL_LAYOUT_FACTORY, theme, init)
}

那麼,這裏就不難理解了,其實上面的anko換成kotlin非簡寫形式,應該是這樣:

this.verticalLayout(theme = 0, init = {
    // ... 初始化創建好的 LinearLayout
})

只是一個簡單的方法調用而已,該方法主要做的功能(在該Activity中)有三個:

1.  方法內部創建一個 LinearLayout (orientation=Vertical)
2.  使用我們傳入的lam表達式 **init** 來初始化生成的 LinearLayout
3.  調用 setContentView 方法,將生成的佈局添加到主界面中

那這三個步驟,是怎麼實現的呢?

# 2. anko的實現

事實上,anko中針對每個view在不同的類上都添加了實現方法,比如vertialLayout的實現:

inline fun ViewManager.verticalLayout(theme: Int = 0): LinearLayout = verticalLayout(theme) {}
inline fun ViewManager.verticalLayout(theme: Int = 0, init: (@AnkoViewDslMarker _LinearLayout).() -> Unit): LinearLayout {
    return ankoView(`$$Anko$Factories$CustomViews`.VERTICAL_LAYOUT_FACTORY, theme, init)
}

inline fun Context.verticalLayout(theme: Int = 0): LinearLayout = verticalLayout(theme) {}
inline fun Context.verticalLayout(theme: Int = 0, init: (@AnkoViewDslMarker _LinearLayout).() -> Unit): LinearLayout {
    return ankoView(`$$Anko$Factories$CustomViews`.VERTICAL_LAYOUT_FACTORY, theme, init)
}

inline fun Activity.verticalLayout(theme: Int = 0): LinearLayout = verticalLayout(theme) {}
inline fun Activity.verticalLayout(theme: Int = 0, init: (@AnkoViewDslMarker _LinearLayout).() -> Unit): LinearLayout {
    return ankoView(`$$Anko$Factories$CustomViews`.VERTICAL_LAYOUT_FACTORY, theme, init)
}

源碼中同時對三個對象 (ViewManager,Context,Activity) 動態添加了verticalLayout方法

在觀察源碼之前,我們可以猜測一下這三種方式大概功能,首先以一般的xml佈局來說,主要用處就幾個:

 1. activity直接進行加載,然後界面顯示
 2. inflate出View,然後當做參數進行傳遞或者其他作用
 3. 通過 `include` 或者通過 ViewStub 方式進行引用
 4. 其他

雖然說用處有多重,但說到底,最後還是需要添加到activity中進行顯示的(特殊情況不考慮),不然view拿出來也沒什麼意義

安卓中View的創建有個參數不可缺少:Context,那麼可想而知,即便anko中要創建出View來,這個參數也是必不可少的

上面的代碼是在Activity中執行的,thisActivity,我們可以追蹤源碼查看:

inline fun Activity.verticalLayout(theme: Int = 0, init: (@AnkoViewDslMarker _LinearLayout).() -> Unit): LinearLayout {
    return ankoView(`$$Anko$Factories$CustomViews`.VERTICAL_LAYOUT_FACTORY, theme, init)
}

然後:

inline fun <T : View> Activity.ankoView(factory: (ctx: Context) -> T, theme: Int, init: T.() -> Unit): T {
    val ctx = AnkoInternals.wrapContextIfNeeded(this, theme)
    val view = factory(ctx)
    view.init()
    AnkoInternals.addView(this, view)
    return view
}

第一行代碼:AnkoInternals.wrapContextIfNeeded(this, theme)
傳入了activity以及theme,返回一個Context,根據方法的說明,可以看到它的功能是獲取到一個包含theme的上下文

第二行代碼:factory(ctx),根據Context創建一個需要的View,對於verticalLayout方法,系統默認提供的view是這樣的:

val VERTICAL_LAYOUT_FACTORY = { ctx: Context ->
    val view = _LinearLayout(ctx)
    view.orientation = LinearLayout.VERTICAL
    view
}

這也印證了上面所說:verticalLayout是一個orientation = LinearLayout.VERTICALLinearLayout

第三行代碼:view.init():這裏對剛創建好的View進行初始化,init是lam表達式,使我們主要進行邏輯處理的地方,類型爲:T.()

上面三行代碼以及針對view進行了創建,初始化等操作,接下來就是anko的核心部分:View的使用

創建好的view總是要加載到activity中的,或者作爲根佈局添加到activity(其實也是作爲子佈局),要麼就是作爲子View添加到ViewGroup中,接下來詳細分析一下第四行代碼:AnkoInternals.addView(this, view)

    fun <T : View> addView(manager: ViewManager, view: T) = when (manager) {
        is ViewGroup -> manager.addView(view)
        is AnkoContext<*> -> manager.addView(view, null)
        else -> throw AnkoException("$manager is the wrong parent")
    }

    fun <T : View> addView(ctx: Context, view: T) {
        ctx.UI { AnkoInternals.addView(this, view) }
    }

    fun <T : View> addView(activity: Activity, view: T) {
        createAnkoContext(activity, { AnkoInternals.addView(this, view) }, true)
    }

在這裏,addView已經有了區別,如果verticalLayout{*}是在activity中調用(根節點部分),那麼代碼會執行createAnkoContext(activity, { AnkoInternals.addView(this, view) }, true),三個參數表達的含義是這樣的:

inline fun <T> T.createAnkoContext(
        ctx: Context,
        init: AnkoContext<T>.() -> Unit,
        setContentView: Boolean = false
)

也就是說,當thisactivity時,setContentViewtrue,因此我們在activity中使用anko時,不需要主動去調用setContentView方法(同樣的,在Fragment中,系統也幫我們做了處理)

如果我們現在this不是activity,而是View,或者說是ViewGroup,也就是說,現在我們想對ViewGroup添加子佈局,那麼系統是如何實現的呢?

首先我們要知道,什麼是ViewManager

用官方api的解釋說明:

這裏寫圖片描述

然後可以發現,ViewGroup的繼承關係是這樣的:

public abstract class ViewGroup extends View implements ViewParent, ViewManager

這樣的話,我們在非根部局調用verticalLayout等方法時,系統走這條邏輯:

fun <T : View> addView(manager: ViewManager, view: T) = when (manager) {
    is ViewGroup -> manager.addView(view)
    is AnkoContext<*> -> manager.addView(view, null)
    else -> throw AnkoException("$manager is the wrong parent")
}

因爲我們此時thisViewGroup,因此,會直接調用ViewGroupaddView方法:

/**
 * <p>Adds a child view. If no layout parameters are already set on the child, the
 * default parameters for this ViewGroup are set on the child.</p>
 *
 * <p><strong>Note:</strong> do not invoke this method from
 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
 *
 * @param child the child view to add
 *
 * @see #generateDefaultLayoutParams()
 */
public void addView(View child) {
    addView(child, -1);
}

對於thiscontext的情況,其實和activity類似,只是在AnkoContextImpl<T>中方法addView有所區別:

override fun addView(view: View?, params: ViewGroup.LayoutParams?) {
    if (view == null) return

    if (myView != null) {
        alreadyHasView()
    }

    this.myView = view

    if (setContentView) {
        doAddView(ctx, view)
    }
}

三 LineMenuView 自定義實現 anko

庫中爲LIneMenuView添加anko實現其實很簡單,只是針對不同的方法或者參數生成屬性異同的LineMenuView對象而已.

lmv_transition插件爲例,方法調用邏輯是這樣:

/**
 * 默認爲transition形式
 */
fun ViewManager.lmv_transition(
        //menu參數部分
        menuText: String? = null, menuIcon: Drawable? = null, @DrawableRes menuIconRes: Int? = null, @Dimension(unit = PX) menuTextSize: Int? = null, @DimenRes menuTextSizeRes: Int? = null, @ColorInt menuTextColor: Int? = null, @ColorRes menuTextColorRes: Int? = null,

        //transition參數,true表示開
        transition: Boolean = false,

        //自定義初始化方法
        init: (LineMenuView.() -> Unit) = {}): LineMenuView {

    return this.lmv(menuText, menuIcon, menuIconRes, menuTextSize, menuTextSizeRes, menuTextColor, menuTextColorRes, init) {
        setPlugin(5)
        this.transition = transition
    }
}

然後調用通用的方法:

/**
 * 相同的添加menu
 */
private fun ViewManager.lmv(menuText: String? = null, menuIcon: Drawable? = null, @DrawableRes menuIconRes: Int? = null, @Dimension(unit = PX) menuTextSize: Int? = null, @DimenRes menuTextSizeRes: Int? = null, @ColorInt menuTextColor: Int? = null, @ColorRes menuTextColorRes: Int? = null, init: (LineMenuView.() -> Unit) = {}, pluginInt: LineMenuView.(ctx: Context) -> Unit): LineMenuView {
    return ankoView({ ctx ->
        LineMenuView(ctx, null, 0).apply {
            this.menuText = menuText
            menuIcon?.let {
                setIcon(it)
            }
            menuIconRes?.let {
                setIcon(getDrawable(ctx, it))
            }
            menuTextSize?.let {
                setMenuTextSize(TypedValue.COMPLEX_UNIT_PX, it)
            }
            menuTextSizeRes?.let {
                setMenuTextSize(TypedValue.COMPLEX_UNIT_PX, ctx.dimen(it))
            }
            menuTextColor?.let {
                setMenuTextColor(it)
            }
            menuTextColorRes?.let {
                setMenuTextColor(getColor(ctx, it))
            }

            //初始化插件
            pluginInt(ctx)
        }
    }, 0, init)
}

很簡單就完成了anko的自定義

更多使用方式請參考:GITHUB-LineMenuView

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章