blob: 79d4a7643a223d7a89a19002e89d3846a0492710 [file] [log] [blame]
package com.airbnb.lottie.samples
import android.content.Context
import android.text.InputType
import android.util.AttributeSet
import android.view.KeyEvent
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.BaseInputConnection
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import android.widget.FrameLayout
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieComposition
import java.util.*
class LottieFontViewGroup @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
private val compositionMap = HashMap<String, LottieComposition>()
private val views = ArrayList<View>()
private val cursorView: LottieAnimationView by lazy { LottieAnimationView(context) }
init {
isFocusableInTouchMode = true
LottieComposition.Factory.fromAssetFileName(context, "Mobilo/BlinkingCursor.json"
) { composition ->
if (composition == null) {
return@fromAssetFileName
}
cursorView.layoutParams = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
cursorView.setComposition(composition)
cursorView.loop(true)
cursorView.playAnimation()
addView(cursorView)
}
}
private fun addSpace() {
val index = indexOfChild(cursorView)
addView(createSpaceView(), index)
}
override fun addView(child: View, index: Int) {
super.addView(child, index)
if (index == -1) {
views.add(child)
} else {
views.add(index, child)
}
}
private fun removeLastView() {
if (views.size > 1) {
val position = views.size - 2
removeView(views[position])
views.removeAt(position)
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
if (views.isEmpty()) {
return
}
var currentX = paddingTop
var currentY = paddingLeft
for (i in views.indices) {
val view = views[i]
if (!fitsOnCurrentLine(currentX, view)) {
if (view.tag != null && view.tag == "Space") {
continue
}
currentX = paddingLeft
currentY += view.measuredHeight
}
currentX += view.width
}
setMeasuredDimension(measuredWidth, currentY + views[views.size - 1].measuredHeight * 2)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
if (views.isEmpty()) {
return
}
var currentX = paddingTop
var currentY = paddingLeft
for (i in views.indices) {
val view = views[i]
if (!fitsOnCurrentLine(currentX, view)) {
if (view.tag != null && view.tag == "Space") {
continue
}
currentX = paddingLeft
currentY += view.measuredHeight
}
view.layout(currentX, currentY, currentX + view.measuredWidth,
currentY + view.measuredHeight)
currentX += view.width
}
}
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
val fic = BaseInputConnection(this, false)
outAttrs.actionLabel = null
outAttrs.inputType = InputType.TYPE_NULL
outAttrs.imeOptions = EditorInfo.IME_ACTION_NEXT
return fic
}
override fun onCheckIsTextEditor(): Boolean {
return true
}
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
if (keyCode == KeyEvent.KEYCODE_SPACE) {
addSpace()
return true
}
if (keyCode == KeyEvent.KEYCODE_DEL) {
removeLastView()
return true
}
if (!isValidKey(event)) {
return super.onKeyUp(keyCode, event)
}
val letter = "" + Character.toUpperCase(event.unicodeChar.toChar())
// switch (letter) {
// case ",":
// letter = "Comma";
// break;
// case "'":
// letter = "Apostrophe";
// break;
// case ";":
// case ":":
// letter = "Colon";
// break;
// }
val fileName = "Mobilo/$letter.json"
if (compositionMap.containsKey(fileName)) {
addComposition(compositionMap[fileName]!!)
} else {
LottieComposition.Factory.fromAssetFileName(context, fileName
) { composition ->
if (composition == null) {
return@fromAssetFileName
}
compositionMap.put(fileName, composition)
addComposition(composition)
}
}
return true
}
private fun isValidKey(event: KeyEvent): Boolean {
if (!event.hasNoModifiers()) {
return false
}
if (event.keyCode >= KeyEvent.KEYCODE_A && event.keyCode <= KeyEvent.KEYCODE_Z) {
return true
}
// switch (keyCode) {
// case KeyEvent.KEYCODE_COMMA:
// case KeyEvent.KEYCODE_APOSTROPHE:
// case KeyEvent.KEYCODE_SEMICOLON:
// return true;
// }
return false
}
private fun addComposition(composition: LottieComposition) {
val lottieAnimationView = LottieAnimationView(context)
lottieAnimationView.layoutParams = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
lottieAnimationView.setComposition(composition)
lottieAnimationView.playAnimation()
val index = indexOfChild(cursorView)
addView(lottieAnimationView, index)
}
private fun fitsOnCurrentLine(currentX: Int, view: View): Boolean {
return currentX + view.measuredWidth < width - paddingRight
}
private fun createSpaceView(): View {
val spaceView = View(context)
spaceView.layoutParams = FrameLayout.LayoutParams(
resources.getDimensionPixelSize(R.dimen.font_space_width),
ViewGroup.LayoutParams.WRAP_CONTENT
)
spaceView.tag = "Space"
return spaceView
}
}