SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/util/NetworkEmojiInvalidator.kt

104 lines
3.3 KiB
Kotlin

package jp.juggler.subwaytooter.util
import android.os.Handler
import android.os.SystemClock
import android.text.Spannable
import android.widget.TextView
import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.span.AnimatableSpan
import jp.juggler.subwaytooter.span.AnimatableSpanInvalidator
import jp.juggler.util.data.clip
import jp.juggler.util.log.LogCategory
import java.lang.ref.WeakReference
class NetworkEmojiInvalidator(
internal val handler: Handler,
internal val view: TextView,
// val parent:View? = null,
) : AnimatableSpanInvalidator {
companion object {
private val log = LogCategory("NetworkEmojiInvalidator")
}
var text: CharSequence
get() = view.text
set(value) {
register(value as? Spannable)
view.text = value
}
private val drawTargetList = ArrayList<WeakReference<Any>>()
// 最後に描画した時刻
private var tLastDraw = 0L
// アニメーション開始時刻
private var tStart = 0L
// アニメーション開始時刻を計算する
override val timeFromStart: Long
get() {
val now = SystemClock.elapsedRealtime()
if (tStart == 0L || now - tLastDraw >= 60000L) {
tStart = now
}
tLastDraw = now
return now - tStart
}
// Handler経由で遅延実行される
private val runnableInvalidate = object : Runnable {
override fun run() {
// 後から来たのをこのタイミングで重複排除する
handler.removeCallbacks(this)
if (view.isAttachedToWindow) {
view.postInvalidateOnAnimation()
}
}
}
// Handler経由で遅延実行される
private val runnableRequestLayout = object : Runnable {
override fun run() {
// 後から来たのをこのタイミングで重複排除する
handler.removeCallbacks(this)
if (view.isAttachedToWindow) {
view.requestLayout()
}
}
}
// 絵文字スパンを描画した直後に呼ばれる
// (絵文字が多いと描画の度に大量に呼び出される)
override fun delayInvalidate(delay: Long) {
// あとから来たのをconflateしたいので、このタイミングでは removeCallbacks しない
handler.postDelayed(runnableInvalidate, delay.clip(10L, 711L))
}
override fun requestLayout() {
// あとから来たのをconflateしたいので、このタイミングでは removeCallbacks しない
handler.postDelayed(runnableRequestLayout, 10L)
}
fun clear() {
for (o in drawTargetList) {
App1.custom_emoji_cache.cancelRequest(o)
}
drawTargetList.clear()
}
// 装飾テキスト中のカスタム絵文字スパンにコールバックを登録する
fun register(dst: Spannable?) {
clear()
if (dst != null) {
for (span in dst.getSpans(0, dst.length, AnimatableSpan::class.java)) {
val tag = WeakReference(Any())
drawTargetList.add(tag)
span.setInvalidateCallback(tag, this)
}
}
}
}