Skip to content

Instantly share code, notes, and snippets.

@rlac
Created October 10, 2014 09:58
Show Gist options
  • Save rlac/b3efd6c1f498376d3a12 to your computer and use it in GitHub Desktop.
Save rlac/b3efd6c1f498376d3a12 to your computer and use it in GitHub Desktop.
A simple Kotlin builder for creating SpannableStrings. Original idea from https://gist.github.com/JakeWharton/11274467.
val span = spannable {
+"'spannable' makes it "
typeface(android.graphics.Typeface.ITALIC) {
+" easy "
}
+" to build a "
typeface(android.graphics.Typeface.BOLD) {
+" SpannableString "
}
+" without needing to touch SpannableStringBuilder."
+"\n\n"
+"It supports any type of span, and they can be nested!"
+"\n\n"
span(android.text.style.URLSpan("http://www.google.com")) {
+"www."
typeface(android.graphics.Typeface.BOLD) {
+"google"
}
+".com"
}
}
val textView = findViewById(R.id.text) as TextView
textView.setText(span.toCharSequence())
// Copyright 2014 Robert Carr
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import java.util.ArrayList
import android.text.SpannableStringBuilder
import android.text.style.StyleSpan
import android.text.Spanned
fun spannable(init: SpanWithChildren.() -> Unit) : SpanWithChildren {
val spanWithChildren = SpanWithChildren()
spanWithChildren.init()
return spanWithChildren
}
trait Span {
fun render(builder: SpannableStringBuilder)
fun toCharSequence() : SpannableStringBuilder {
val builder = SpannableStringBuilder()
render(builder)
return builder
}
}
class SpanWithChildren(val what : Any? = null) : Span {
val children = ArrayList<Span>()
fun typeface(typeface: Int, init: SpanWithChildren.() -> Unit) : SpanWithChildren =
span(StyleSpan(typeface), init)
fun span(what: Any, init: SpanWithChildren.() -> Unit) : SpanWithChildren {
var child = SpanWithChildren(what)
child.init()
children.add(child)
return this
}
fun String.plus() {
children.add(SpanWithText(this))
}
override fun render(builder: SpannableStringBuilder) {
val start = builder.length()
for (c in children) {
c.render(builder)
}
if (what != null) {
builder.setSpan(what, start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE)
}
}
}
class SpanWithText(val content: String) : Span {
override fun render(builder: SpannableStringBuilder) {
builder.append(content)
}
}
@Sirelon
Copy link

Sirelon commented Nov 2, 2016

Hi! Thanks for creating that.
I have updated this gist for new Kotlin Version
https://gist.github.com/Sirelon/2773a8dc51cc8322e473c5fd5b9e6802

@sough
Copy link

sough commented Aug 28, 2017

thx, add to class SpanWithCildren the size too

fun size(size: Float, init: SpanWithChildren.()-> Unit): SpanWithChildren =
span(RelativeSizeSpan(size), init)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment