Closed wojiaosuxiaobai closed 6 months ago
请看一下FrameAnimationDrawable
的API,有手动开始或停止的方法
class ExpressionSpan : DynamicDrawableSpan {
private var mContextRef: WeakReference<Context>? = null
private var mTextViewRef: WeakReference<TextView>? = null
private var mResourceId = 0
private var mPath: String? = null
private var mSize = 0
private var mTextSize = 0
private var mHeight = 0
private var mWidth = 0
private var mTop = 0
private var mDrawable: Drawable? = null
private var mDrawableRef: WeakReference<Drawable>? = null
constructor(context: Context, textView: TextView?, resourceId: Int, size: Int, alignment: Int, textSize: Int) : super(alignment) {
mContextRef = WeakReference<Context>(context)
mTextViewRef = WeakReference<TextView>(textView)
mResourceId = resourceId
mSize = size
mHeight = mSize
mWidth = mHeight
mTextSize = textSize
mPath = null
}
constructor(context: Context, textView: TextView?, path: String, size: Int, alignment: Int, textSize: Int) : super(alignment) {
mContextRef = WeakReference<Context>(context)
mTextViewRef = WeakReference<TextView>(textView)
mPath = path
mSize = size * 7 / 6
mHeight = mSize
mWidth = mHeight
mTextSize = textSize
mResourceId = -1
}
override fun getDrawable(): Drawable {
if (mDrawable == null) {
try {
val context = mContextRef!!.get()
if (context != null) {
mDrawable = if (mResourceId > 0) {
ResourcesCompat.getDrawable(context.resources, mResourceId, null)
} else {
val file = File(mPath)
if (file.exists()) {
try {
if (APNGParser.isAPNG(file.path)) {
val apngDrawable = APNGDrawable.fromFile(file.absolutePath)
apngDrawable.setAutoPlay(true)
apngDrawable.setVisible(true, true)
apngDrawable.start()
/**
* 通过传入TextView弱引用定时刷新备选方案,该方案有诸多缺点,还需寻找替代方案
*/
// CoroutineScope(Dispatchers.IO).launch {
// while (mTextViewRef?.get() != null) {
// withContext(Dispatchers.Main) {
// mTextViewRef?.get()?.invalidate()
// }
// delay(100)
// }
// }
apngDrawable.mutate()
} else {
Drawable.createFromPath(file.absolutePath)
}
} catch (e: Throwable) {
ResourcesCompat.getDrawable(context.resources, R.drawable.ic_post_image, null)
}
} else {
ResourcesCompat.getDrawable(context.resources, R.drawable.ic_post_image, null)
}
}
}
mHeight = mSize
mWidth = mHeight * mDrawable!!.intrinsicWidth / mDrawable!!.intrinsicHeight
mTop = if (mHeight > mTextSize * 7 / 6) {
0
} else {
(mTextSize * 7 / 6 - mHeight) / 2
}
mDrawable!!.setBounds(0, mTop, mWidth, mTop + mHeight)
} catch (e: Exception) {
HBLogger.e("ExpressionSpan getDrawable onError: ${e.message}")
}
}
if (mDrawable == null) {
val context = mContextRef!!.get()
if (context != null) {
mDrawable = context.resources.getDrawable(R.drawable.ic_post_image)
}
}
return mDrawable!!
}
override fun draw(canvas: Canvas, text: CharSequence?, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
val b = getCachedDrawable()
canvas.save()
val fm = paint.fontMetricsInt
// int transY = y + fm.ascent/2 - (b.getBounds().bottom + b.getBounds().top) / 2; // 图片中心与文字中心(baseline为底部)对齐
var transY = y - (b!!.bounds.bottom + b.bounds.top) / 2 + (fm.ascent + fm.descent) / 2 // 图片中心与文字中心对齐
if (transY + b.bounds.bottom > bottom) {
transY = bottom - b.bounds.bottom
}
if (mVerticalAlignment == ALIGN_BASELINE) {
transY = top + (bottom - top) / 2 - (b.bounds.bottom - b.bounds.top) / 2 - mTop
}
canvas.translate(x, transY.toFloat())
b.draw(canvas)
canvas.restore()
// if (b is APNGDrawable) {
// b.setAutoPlay(true)
// b.setVisible(true, true)
// b.start()
// }
}
private fun getCachedDrawable(): Drawable? {
if (mDrawableRef == null || mDrawableRef?.get() == null) {
mDrawableRef = WeakReference(drawable)
}
return mDrawableRef?.get()
}
}
大佬,目前span的代码是这个,我尝试在getDrawable和draw的时候调用setVisible和start,但是并没有动画效果。
当我把注释掉的invalidate代码恢复后,动画效果也随之恢复,但是这个方案存在不少问题
autoplay为true时就是根据生命周期自动start和stop, 手动控制autoplay设为false
我现在是在一个自定义Span里用的 手动控制autoplay设为false后,手动调用start(),依然没效果 只要我不调用textview的invalidate,就没有效果,我还有找到其他方案
//尝试是用的代码
apngDrawable.setAutoPlay(false)
apngDrawable.setLoopLimit(-1)
apngDrawable.setVisible(true, true)
apngDrawable.start()
看一下textview的源码吧, 这个库本身没有对这个场景做适配
好的,谢谢大佬帮忙
我看到其他issue里有使用定时invalidate的方案,但是我目前的需求不是很支持使用invalidate,我目前是在一个recyclerview中的item的TextView支持apng的ImageSpan用作处理表情。大佬有没有除去定时invalidate的其他方案。