用 Kotlin 開發 Android 專案是一種什麼樣的感受?(用 DSL 配置自定義 view)

neverwoods發表於2018-01-05

前言

離上一篇文章已經過去了挺長時間,在這期間發生了不少事,比如 Kotlin 火了,比如作者我要回老家領證了2333。

關於 Kotlin 火了這事,我一直覺得這是一門很棒的語言,不火也是。但是既然現在 google 都為它開路了,那麼想來今後的發展應該會很不錯。

鑑於 Kotlin 已紅遍大江南北,類似的文章現在也如雨後春筍層出不窮,作者原來的標題【用 Kotlin 開發 Android 是一種什麼樣的感受?】似乎也不那麼好使了,畢竟很多 Android 開發者都已經開始在嘗試,有的也許淺嘗輒止,有的也許會深入的使用下去,但終究在這個時間段再寫一些很基礎的語法文章,我個人感覺意義不大了。

最近我在用 Kotlin 做一個挺有意思的開源專案,雖然完成度還很低,但也勉強算是五臟俱全。這篇文章就當做是一個引子,來介紹介紹我這個小專案,順便讓初學 Kotlin 的各位瞭解一下,用這麼一門語言,你能做出什麼東西來。

DSL

應該有不少小夥伴做過自定義 view,也知道在 Android 中自定義 view 大致分為兩種:

1.繼承於 ViewGroup,將多個 view 組合在一起而形成 2.繼承於 View,在 canvas(畫布)上通過相應 API 繪製而成

因為上東家的各種奇葩需求,本人算是飽受 CustomView Hell 的摧殘,也明白兩種方案各有適用的場合。方案1 相對來說還比較容易上手,基本會佈局就會寫,而方案2 則需要一定的學習成本,也需要一定的經驗去處理遇到的各式問題,最後的最後,是寫起來比較繁雜。那麼有沒有什麼辦法可以讓 canvas 繪製變得更輕鬆呢?

在接觸過 anko 之後,我才發現原來用程式碼佈局也可以那麼優雅那麼簡單。這裡不是在給 anko 打廣告(吃瓜群眾:你口是心非),而是想介紹用 anko 佈局時的寫法:

verticalLayout {
    textView {
        text = "隨便寫點啥"
        textSize = 20f
    }

    imageView {
        imageResource = R.mipmap.ic_launcher
    }
}
複製程式碼

諸如此類程式碼,大家應該都很眼熟:

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
複製程式碼

沒錯,anko 佈局和 gradle 的語法很像,除去少量差別,你甚至會覺得這就是同一種語言。這就是我要給大家介紹的 領域特定語言(domain-specific languages,簡稱 DSL)

MagicPen

MagicPen 是我發起的一個用 Kotlin 編寫的用於操作 canvas 來自定義 view 的開源專案。似乎這麼說有點模糊?那我們直接上程式碼和圖吧

package com.lab.zhangll.magicpen

import android.graphics.Color
import android.graphics.Paint
import android.graphics.PointF
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import com.lab.zhangll.magicpen.lib.*

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(
                magicPen {
                    val line = line {
                        start = PointF(0f, 1000f) // 線條起點
                        end = PointF(1000f, 1000f) // 線條終點
                    }

                    val bigOne = circle {
                        radius = 200f // 圓半徑

                        aboveOf(line) // 線上條上面
                        leftMargin = 500f // 左邊距
                        bottomMargin = 10f // 下邊距

                        paint = Paint().apply { color = Color.RED } // 紅色
                    }

                    text {
                        content = "我是一隻小小鳥"
                        paint = Paint().apply { textSize = 40f }
                        centerIn(bigOne)
                    }

                    circle {
                        radius = 50f // 半徑
                        centerIn(bigOne) // 在大圓中間

                        gesture {
                            onClick = { Toast.makeText(this@MainActivity, "clicked", Toast.LENGTH_SHORT).show() } // 點選時彈框
                            onDragBy = { x, y -> moveBy(x, y) } // 跟著拖動的手指動
                            onRelease = { smoothMoveToOrigin() } // 放手後滑動到原點
                        }
                    }
                }
        )
    }
}
複製程式碼

算上package、import 和我有意識的空行,一共50行程式碼,我們看看它能實現出什麼樣的效果吧

magicPen.gif

相信圖文結合在一起,再加上程式碼中的註釋,大家能很輕鬆的看明白。我像佈局似的就做出了這麼一個 view。包括線條、圓、文字三種圖形;也包括絕對位置、相對關係;甚至還有點選事件、拖拽事件和平滑移動動畫。挺精簡的對吧?

可惜的是,目前支援的功能也就這麼多了,畢竟這個專案才啟動沒多長時間,還有兩個有意的小夥伴也得在過一段時間之後才能學習 Kotlin 並加入這個專案的開發工作。不過在不久之後,MagicPen 將可以用來建立我能想到的大量自定義 view,請拭目以待。

專案原始碼在 https://github.com/neverwoodsS/MagicPen 歡迎各位圍觀與提出不足

PS.這是在下作為單身青年的最後一篇文章

相關文章