1. <div id="f8mbs"></div>
        您好,歡迎來到源碼搜藏網!分享精神,快樂你我!
        [加入VIP] 設為首頁 | 收藏本站 | 網站地圖 | Sitemap | TAG標簽
      2. 首 頁
      3. 在線工具
      4. jquery手冊
      5. 當前位置:首頁 > 安卓源碼 > 技術博客 >

        Android UI開發神兵利器Kotlin Anko

        時間:2019-02-23 19:44 來源:互聯網 作者:源碼搜藏 瀏覽:收藏 挑錯 推薦 打印

        Anko的簡介 引用Anko的GitHub主頁上面的解釋: Anko is a Kotlin library which makes Android application development faster and easier. It makes your code clean and easy to read, and lets you forget about rough edges of the Android SDK for Jav

        Anko的簡介

        引用Anko的GitHub主頁上面的解釋:

        Anko is a Kotlin library which makes Android application development faster and easier. It makes your code clean and easy to read, and lets you forget about rough edges of the Android SDK for Java.

        Anko是為了使Android開發程序更加簡單和快速而生成的一個Kotlin庫,它可以使您的代碼清晰、易讀,并且它可以讓您忘記粗糙的Java Android SDK。

        Anko目前主要用于:Layout布局、SQLite數據庫和Coroutines協程三個方面。

        接下來我們主要交流的是Layout方面的知識。

        引入Anko和遇到的問題

        添加Anko的依賴: implementation "org.jetbrains.anko:anko:$anko_version"

        這時發現有爆紅的地方了:提示v7包和v4包版本不一致,這就很納悶了,我都沒用私自添加刪除v4包,怎么會出現問題呢,接著我就去libraries找原因了,原來是Anko也引入了v4的包,而且版本是27.1.1,我新建工程的編譯版本是28.0.0,小伙伴們要注意了。

        解決:排除anko包中的v4包

        implementation("org.jetbrains.anko:anko:$anko_version") {
                exclude module: 'support-v4'
        }
        

        使用Anko,從四個點介紹下如何使用Anko以及遇到的問題

        ① 實現一個簡單的登錄界面
        既然是使用Anko,那么當然是要拋棄xml布局文件咯,也就不用寫setContentView()來綁定布局文件了,可以直接在onCreate()方法里面調用我們自己寫的AnkoComponent類的setContentView()綁定activity就行了,這種寫法是比較推薦的一種,還有一種就是直接把verticalLayout{}寫在onCreate()里面,但是不推薦,這樣會造成Activity類的代碼冗余。下面來看看如何實現這么一個簡單的布局:

        class AnkoActivity : AppCompatActivity() {
        
            override fun onCreate(savedInstanceState: Bundle?) {
                super.onCreate(savedInstanceState)
                // AnkoComponent和Activity相互綁定
                MainUI().setContentView(this@AnkoActivity)
            }
        }
        
        class MainUI : AnkoComponent<AnkoActivity> {
            override fun createView(ui: AnkoContext<AnkoActivity>) = with(ui) {
                verticalLayout {
                    // 這個gravity對應的就是gravity,而在lparams閉包中,gravity對應的是layout_gravity
                    gravity = Gravity.CENTER
                    // 布局的屬性params在閉包里面的lparams中設置,但是button、TextView等控件的屬性params是在閉包外的lparams設置
                    lparams(matchParent, matchParent)
                    editText {
                        hint = "userName"
                        gravity = Gravity.CENTER
                        // 監聽輸入框輸入情況
                        addTextChangedListener(object : TextWatcher {
                            override fun afterTextChanged(s: Editable?) {
                            }
        
                            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                            }
        
                            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                            }
                        })
                    }.lparams(width = dip(250), height = 200)
        
                    editText {
                        hint = "password"
                        top = 20
                        gravity = Gravity.CENTER
                    }.lparams(width = dip(250), height = 200)
        
                    button("list") {
                        backgroundColor = Color.parseColor("#FF9999")
                        alpha = 0.5f
                        // 點擊事件
                        onClick {
                            // anko封裝的intent攜帶值跳轉
                            startActivity<ListActivity>("aulton" to "aulton")
                        }
                        // 長按事件
                        onLongClick {
                            toast("Long Click")
                        }
                    }.lparams(dip(250), dip(50))
        
                    button("setting") {
                        backgroundColor = Color.parseColor("#FF7777")
                        alpha = 0.5f
                        // 點擊事件
                        onClick {
                            // anko封裝的intent攜帶值跳轉
                            startActivity<SettingActivity>("aulton" to "aulton")
                        }
                    }.lparams(dip(250), dip(50)) {
                        topMargin = dip(16)
                    }
        
                    button("custom_view") {
                        backgroundColor = Color.parseColor("#FF7777")
                        alpha = 0.5f
                        // 點擊事件
                        onClick {
                            // anko封裝的intent攜帶值跳轉
                            startActivity<CustomCircleActivity>("aulton" to "aulton")
                        }
                    }.lparams(dip(250), dip(50)) {
                        topMargin = dip(16)
                    }
                }
            }
        }
        
        • 這里我們用的都是大家常見的一些布局和控件,verticalLayout就是oritentation=verticalLinearLayout

        • 控件和布局的一些屬性需要注意下,比如verticalLayout里面的gravity = Gravity.CENTER對應的就是xml中的gravity,如果出現在lparams閉包中的gravity = Gravity.CENTER指的就是layout_gravity屬性了。千萬要分清。

        • AnkoComponentcreateView()其實是有返回值的

        interface AnkoComponent<in T> {
            fun createView(ui: AnkoContext<T>): View
        }
        

        返回的是一個View對象,這里我使用with(ui)來實現自動返回。你也可以使用let()或者apply()等作用域函數。你可以從ui: AnkoContext<T>對象中拿到ContextActivityView三個對象,都是很重要的屬性。

        效果如下:

        Android UI開發神兵利器Kotlin Anko

        ② 使用Anko實現RV列表

        要想使用RecyclerView你必須添加新的依賴:

        //    RecyclerView-v7
        implementation "org.jetbrains.anko:anko-recyclerview-v7:$anko_version"
        implementation "org.jetbrains.anko:anko-recyclerview-v7-coroutines:$anko_version"
        

        首先寫出rv+swipeRefreshLayout布局:

        class ListUI : AnkoComponent<ListActivity> {
            override fun createView(ui: AnkoContext<ListActivity>) = with(ui) {
                // 下拉刷新控件
                swipeRefreshLayout {
                    // 下拉監聽事件
                    setOnRefreshListener {
                        toast("refresh")
                        isRefreshing = false
                    }
                    // rv
                    recyclerView {
                        layoutManager = LinearLayoutManager(ui.ctx)
                        lparams(width = matchParent, height = matchParent)
                        adapter = MyAdapter(ui.ctx, mutableListOf("1",
                                "2", "3", "4"))
                    }
                }
            }
        }
        

        rv所有的屬性:manageradapter都可以直接在閉包里面設置。

        接下來看看適配器中的ItemView如何用Anko實現:

        class MyAdapter(private val context: Context,
                        private val mData: MutableList<String>) : RecyclerView.Adapter<MyAdapter.MyHolder>() {
        
            // 創建Holder對象
            override fun onCreateViewHolder(p0: ViewGroup, p1: Int): MyHolder {
                // 根據anko生成itemView,并且給itemView的tag賦值,從而取得MyHolder
                return AdapterUI().createView(AnkoContext.create(context, p0)).tag as MyHolder
            }
        
            override fun getItemCount(): Int {
                return mData.size
            }
        
            // 綁定holder,呈現UI
            override fun onBindViewHolder(holder: MyHolder, p1: Int) {
                holder.tv_name.text = mData[p1]
            }
        
            class MyHolder(view: View, val tv_name: TextView) : RecyclerView.ViewHolder(view)
        
            class AdapterUI : AnkoComponent<ViewGroup> {
                override fun createView(ui: AnkoContext<ViewGroup>): View {
                    var tv_name: TextView? = null
                    val item_view = with(ui) {
                        relativeLayout {
                            lparams(width = matchParent, height = dip(50))
                            tv_name = textView {
                                textSize = 12f
                                textColor = Color.parseColor("#FF0000")
                                backgroundColor = Color.parseColor("#FFF0F5")
                                gravity = Gravity.CENTER
                            }.lparams(width = matchParent, height = dip(50)) {
                                // 設置外邊距
                                topMargin = dip(10)
                            }
                        }
                    }
                    // 返回itemView,并且通過tag生成MyHolder
                    item_view.tag = MyHolder(item_view, tv_name = tv_name!!)
                    return item_view
                }
            }
        }
        

        其實這里主要使用到的就是View對象的tag屬性,將ItemViewtagHolder綁定在一起,這樣我們AnkoComponentcreateView()返回ItemView的同時也把Holder生成并返回了,就可以在AdapteronCreateViewHolder()方法中拿到Holder對象。

        效果如下:

        Android UI開發神兵利器Kotlin Anko

        ③ 復用AnkoView

        在日常開發中我們會遇到這樣的情形,類似于通用的設置界面,所有的條目都是很類似的,只不過文字或者icon不一樣,如果我們用rv來實現,難免覺得條目太少,不劃算,但是每個條目都是自己寫一遍,又會覺得太繁瑣,這時候Anko就會幫助我們簡化很大的代碼,下面一起來看看:

        fun myLinearLayout(viewManager: ViewManager,
                           itemHeight: Int = 40,
                           itemMarginTop: Int = 0,
                           itemMarginBottom: Int = 0,
                           headImageId: Int = 0,
                           headTextRes: String,
                           bottomImageId: Int = 0) = with(viewManager) {
            linearLayout {
                orientation = LinearLayout.HORIZONTAL
                leftPadding = dip(16)
                rightPadding = dip(16)
                backgroundColor = Color.parseColor("#FFFFFF")
                // 設置整體的寬高和外邊距
                lparams(width = matchParent, height = dip(itemHeight)) {
                    setMargins(0, itemMarginTop, 0, itemMarginBottom)
                }
                // 左邊圖片
                if (headImageId != 0) {
                    imageView(headImageId) {
                        scaleType = ImageView.ScaleType.FIT_XY
                    }.lparams(width = dip(30), height = dip(30)) {
                        gravity = Gravity.CENTER
                    }
                }
                // 左邊字體
                textView(headTextRes) {
                    gravity = Gravity.CENTER_VERTICAL
                }.lparams(width = matchParent, height = matchParent, weight = 1f) {
                    if (headImageId != 0) {
                        marginStart = dip(16)
                    }
                }
                // 右邊圖片
                if (bottomImageId != 0) {
                    imageView(bottomImageId) {
                        scaleType = ImageView.ScaleType.FIT_XY
                    }.lparams(width = dip(30), height = dip(30)) {
                        gravity = Gravity.CENTER
                    }
                }
            }
        }
        

        首先定義一個方法,方法包含了item的高度、上下外邊距、頭部icon、頭部文字、尾部icon和ViewManager7個參數。方法的內部實現采用Anko的DSL(領域特定語言)語言實現。其中參數ViewManager是我們前面提到的AnkoComponent的父類,它是這個方法的主要參數,因為在Anko實現的一系列View都是ViewManager的擴展函數。想復用的話,直接調用這個方法就行了,ForExample:

        class SettingUI : AnkoComponent<SettingActivity> {
            override fun createView(ui: AnkoContext<SettingActivity>) = with(ui) {
                verticalLayout {
                    myLinearLayout(viewManager = this,
                            headImageId = R.mipmap.setting,
                            headTextRes = "Setting",
                            bottomImageId = R.mipmap.arrow,
                            itemMarginBottom = 8,
                            itemMarginTop = 8)
                    myLinearLayout(viewManager = this,
                            headTextRes = "MyInfo",
                            bottomImageId = R.mipmap.arrow,
                            itemMarginBottom = 8)
                    myLinearLayout(this,
                            headTextRes = "Exit",
                            headImageId = R.mipmap.exit,
                            bottomImageId = R.mipmap.arrow)
                }
            }
        }
        

        效果如下:

        Android UI開發神兵利器Kotlin Anko

        ④ 在Anko中使用自定義View

        有一天產品讓你畫一個比較奇特的圓弧,這個圓弧你必須用自定義View實現,在你實現了之后,你發現Anko中卻不能使用,ViewManager并沒有生成自定義View的方法,這時你傻眼了,辛辛苦苦寫的View在Anko中用不了。別急,下面我們一起來學習下如何使用:

        第一步:自定義一個圓弧,這里用很簡單的一個例子

        定義屬性:這些屬性都可以在Anko的閉包中直接賦值

        // 圓弧開始的角度
        var startAngle: Float = 0f
        // 圓弧結束的角度
        var endAngle: Float = 0f
        // 圓弧的背景顏色
        @ColorInt
        var arcBg: Int = 0
            set(value) {
                field = value
                circlePaint?.color = value
            }
        // 畫筆的寬度
        var paintWidth: Float = 1f
            set(value) {
                field = value
                circlePaint?.strokeWidth = value
                rectPaint?.strokeWidth = value
            }
        

        RectArc:簡單的實現下

        override fun onDraw(canvas: Canvas) {
            super.onDraw(canvas)
            canvas.drawRect(circleRect!!, rectPaint!!)
            canvas.drawArc(circleRect!!, startAngle, endAngle - startAngle, true, circlePaint!!)
        }
        

        第二步:實現擴展函數,擴展函數主要的還是靠返回的ankoView()來實現,我們看到的CustomCircle(it)中的it就是Context對象。這樣就直接調用了自定義View的構造函數。

        /**
         * 以下都是為了在anko中實現自定義的CustomCircle,定義的一系列方法
         */
        inline fun ViewManager.customCircle(): CustomCircle = customCircle {}
        inline fun ViewManager.customCircle(theme: Int = 0, init: CustomCircle.() -> Unit): CustomCircle {
            return ankoView({ CustomCircle(it) }, theme, init)
        }
        
        inline fun Context.customCircle(): CustomCircle = customCircle {}
        inline fun Context.customCircle(theme: Int = 0, init: CustomCircle.() -> Unit): CustomCircle {
            return ankoView({ CustomCircle(it) }, theme, init)
        }
        
        inline fun Activity.customCircle(): CustomCircle = customCircle {}
        inline fun Activity.customCircle(theme: Int = 0, init: CustomCircle.() -> Unit): CustomCircle {
            return ankoView({ CustomCircle(it) }, theme, init)
        }
        

        第三步:調用,其實和buttontv沒什么區別,看你自定義中的參數而已

        class CustomCircleUI : AnkoComponent<CustomCircleActivity> {
            override fun createView(ui: AnkoContext<CustomCircleActivity>) = with(ui) {
                linearLayout {
                    orientation = LinearLayout.VERTICAL
                    gravity = Gravity.CENTER
                    lparams(matchParent, matchParent)
                    verticalLayout {
                        lparams(width = dip(200), height = dip(200))
                        backgroundColor = Color.parseColor("#ff9999")
                        customCircle {
                            startAngle = 0f
                            endAngle = 180f
                            arcBg = Color.WHITE
                            paintWidth = 2f
                        }
                    }
        
                }
            }
        }
        

        效果:

        Android UI開發神兵利器Kotlin Anko

        Anko中Layout部分使用就介紹到這

        Android UI開發神兵利器Kotlin Anko轉載http://www.rhcg.tw/appboke/39557.html
        標簽:網站源碼
        辽宁十一选五单双