Kotlin – pierwsze starcie – Barnsley Fern

Kotlin dołączył do oficjalnych języków programowania aplikacji na Androida, więc postanowiłam sobie, że coś w nim napiszę. Miało być szybkie i niekoniecznie funkcjonalne. Ot, taka apka żeby zapoznać się troszkę z nowym językiem programowania. Padło na Paproć Barnsleya.

Zaczęłam od ściągnięcia Android Studio w wersji 3.0, a taki jest efekt po kilku dniach klepania kodu 😉

To co jest fajne w Kotlinie to to, że nie muszę już wywoływać funkcji 'findViewById(R.id.seekBar)’, tylko od razu mogę użyć ID – poniżej ustawianie listenera dla obiektu o id seekBar:


seekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onStartTrackingTouch(p0: SeekBar?) {
}
override fun onStopTrackingTouch(p0: SeekBar?) {
if (p0 != null) {
fernView.n = (p0.progress / 100.0 * MAX).toInt()
fernView.requestLayout()
}
}
override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
}
})

view raw

MainActivity.kt

hosted with ❤ by GitHub

Z innych ciekawostek: ? po nazwie typu sprawia, że ten SeekBar będzie mógł być nullem.

Udało mi się stworzyć własną klasę FernView, dziedziczący po View. Wykorzystałam ją do rysowania na canvasie pikseli paprotki. Kotlin udostępnia szczególną składnię jeśli chodzi o konstruktory 😉


class FernView : View {
var fern: Fern = BarnsleyFern()
var n: Int = 100000
constructor(ctx: Context) : super(ctx)
constructor(ctx: Context, attributeSet: AttributeSet) : super(ctx, attributeSet)
val paint = Paint()
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.translate(width / 2f, 0f)
paint.style = Paint.Style.FILL
paint.color = Color.WHITE
canvas.drawPaint(paint)
paint.color = Color.parseColor("#006200")
val points = fern.generateFern(n)
canvas.drawPoints(points, paint)
}
}

view raw

FernView.kt

hosted with ❤ by GitHub

Różnica między var a val? val to takie javowe final. Jak raz się coś przypisze do takiej zmiennej to nie ma mowy żeby ją przepisać na coś innego.

Drugi konstruktor zawierający w parametrze Attribute set jest potrzebny po to, żeby można było ten widok zadeklarować w xmlu, który nie zmienia się niezależnie od tego, z którego języka się korzysta 😉


<com.projects.jezinka.barnsleyfern.FernView
android:id="@+id/fernView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/radioGroup" />

Samo tworzenie paproci nie jest jakoś specjalnie skomplikowane. Są 4 funkcje wyliczające współrzędne x i y kolejnego punktu. Funkcje wybierane są z odgórnie ustalonym prawdopodobieństwem.


fun generateFern(n: Int): FloatArray {
val random = Random()
points = kotlin.FloatArray(n)
for (i: Int in 2..n – 1 step 2) {
val r = random.nextFloat()
val p1 = matrix[F1]!![P]!!
val p2 = matrix[F2]!![P]!!
val p3 = matrix[F3]!![P]!!
var function: String
if (r <= p1) {
function = F1
} else if (r <= p1 + p2) {
function = F2
} else if (r <= p1 + p2 + p3) {
function = F3
} else {
function = F4
}
this.points[i] = newX(function, i)
this.points[i + 1] = newY(function, i)
}
return this.points.map { it * 100 }.toFloatArray()
}

view raw

Fern.kt

hosted with ❤ by GitHub

I znowu dziwny operator: !! -> to wyrzuca Null Pointer Exception 😉

Jak wyglądają funkcje wyliczające współrzędne kolejnych punktów:


fun newX(function: String, i: Int): Float {
val a = matrix[function]!![A]!!
val b = matrix[function]!![B]!!
val e = matrix[function]!![E]!!
return (a * getX(i) + b * getY(i) + e)
}
fun newY(function: String, i: Int): Float {
val c = matrix[function]!![C]!!
val d = matrix[function]!![D]!!
val f = matrix[function]!![F]!!
return (c * getX(i) + d * getY(i) + f)
}

view raw

Fern.kt

hosted with ❤ by GitHub

W programie użyłam znalezionego na angielskiej wikipedii zapisu prawdopodobieństw i składników wyrażeń.Dzięki temu mogłam dodawać kolejne wariacje paprotki bez dodawania za dużej liczby linijek kodu. I mogłam się przy okazji dowiedzieć jak używa się HashMap w Kotlinie:


override var matrix: HashMap<String, HashMap<String, Float>> = hashMapOf(
F1 to hashMapOf(P to 0.01f, A to 0f, B to 0f, C to 0f, D to 0.16f, E to 0f, F to 0f),
F2 to hashMapOf(P to 0.85f, A to 0.85f, B to 0.04f, C to -0.04f, D to 0.85f, E to 0f, F to 1.6f),
F3 to hashMapOf(P to 0.07f, A to 0.2f, B to -0.26f, C to 0.23f, D to 0.22f, E to 0f, F to 1.6f),
F4 to hashMapOf(P to 0.07f, A to -0.15f, B to 0.28f, C to 0.26f, D to 0.24f, E to 0f, F to 0.44f)
)

view raw

BarnsleyFern.kt

hosted with ❤ by GitHub

Pierwsze wrażenie ogólnie dobre. Choć były momenty kiedy kompilator krzyczał do mnie: Array<Float> is not a FloatArray! Zastanawiam się jaką aplikację mogłabym jeszcze napisać z wykorzystaniem Kotlina, ale na ten moment brak mi pomysłów 😉

Cały kod dostępny na githubie: https://github.com/jezinka/BarnsleyFern

Wytłumaczenie tych wszystkich operatorów dotyczących null-safe tu: http://kotlinlang.org/docs/reference/null-safety.html#null-safety

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

This site uses Akismet to reduce spam. Learn how your comment data is processed.