[帧动画抽离]
This commit is contained in:
yangyakun
2023-08-21 19:53:49 +08:00
committed by zhongchao
parent 1699eb7af3
commit d6cdd0d98b
8 changed files with 34 additions and 329 deletions

View File

@@ -12,6 +12,7 @@ import com.mogo.eagle.core.utilcode.util.DeviceUtils
import com.mogo.eagle.core.utilcode.util.OverlayViewUtils
import com.mogo.map.listener.IMogoMapListener
import com.mogo.map.uicontroller.VisualAngleMode
import com.mogo.och.common.module.utils.FrameAnimatorContainer
import com.mogo.och.common.module.utils.RxUtils
import com.mogo.och.common.module.voice.VoiceNotice
import com.mogo.och.taxi.passenger.R
@@ -21,7 +22,6 @@ import com.mogo.och.taxi.passenger.ui.arrived.ArrivedView
import com.mogo.och.taxi.passenger.ui.bottom.BottomBar
import com.mogo.och.taxi.passenger.ui.check.TaxiPassengerCheckView
import com.mogo.och.taxi.passenger.ui.startautopilot.StartAutopilotView
import com.mogo.och.taxi.passenger.widget.animutils.AnimationsContainer
import kotlinx.android.synthetic.main.taxi_p_base_fragment.*
import java.lang.ref.WeakReference
@@ -52,7 +52,7 @@ class TaxiPassengerBaseFragment() :
*/
private var mStartAutopilotView: WeakReference<StartAutopilotView?>? = null
private var createProgressDialogAnim: AnimationsContainer? = null
private var createProgressDialogAnim: FrameAnimatorContainer?=null
override fun getLayoutId(): Int {
return R.layout.taxi_p_base_fragment

View File

@@ -10,10 +10,10 @@ import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
import com.mogo.eagle.core.utilcode.util.OverlayViewUtils
import com.mogo.och.common.module.utils.FrameAnimatorContainer
import com.mogo.och.common.module.utils.RxUtils
import com.mogo.och.taxi.passenger.R
import com.mogo.och.taxi.passenger.widget.WindowRelativeLayout
import com.mogo.och.taxi.passenger.widget.animutils.AnimationsContainer
import com.shuyu.gsyvideoplayer.GSYVideoManager
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
@@ -44,7 +44,7 @@ class ArrivedView : WindowRelativeLayout, ArrivedViewModel.ArrivedViewCallback {
private val gsyVideoOptionBuilder = GSYVideoOptionBuilder()
private var taxiPxiaozhiLove: AnimationsContainer?=null
private var taxiPxiaozhiLove: FrameAnimatorContainer?=null
private fun initView() {
d(SceneConstant.M_TAXI_P + TAG, "initView")
@@ -65,8 +65,8 @@ class ArrivedView : WindowRelativeLayout, ArrivedViewModel.ArrivedViewCallback {
OverlayViewUtils.dismissOverlayView(this)
}
taxiPxiaozhiLove = AnimationsContainer(R.array.xiaozhi_love, 20,iv_xiaozhi_belt)
taxiPxiaozhiLove?.setOnAnimStopListener(object :AnimationsContainer.OnAnimationStoppedListener{
taxiPxiaozhiLove = FrameAnimatorContainer(R.array.xiaozhi_love, 20,iv_xiaozhi_belt)
taxiPxiaozhiLove?.setOnAnimStopListener(object :FrameAnimatorContainer.OnAnimationStoppedListener{
override fun AnimationStopped() {
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "动画暂停")
}

View File

@@ -12,12 +12,9 @@ import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
import com.mogo.eagle.core.utilcode.util.OverlayViewUtils
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.mogo.och.common.module.utils.AnimatorDrawableUtil
import com.mogo.och.common.module.utils.FrameAnimatorContainer
import com.mogo.och.taxi.passenger.R
import com.mogo.och.taxi.passenger.ui.TaxiPassengerBaseFragment
import com.mogo.och.taxi.passenger.widget.WindowRelativeLayout
import com.mogo.och.taxi.passenger.widget.animutils.AnimationsContainer
import kotlinx.android.synthetic.main.taxi_p_base_fragment.aciv_xiaozhi_normal
import kotlinx.android.synthetic.main.taxi_p_start_autopilot_view.view.actv_front_left_door
import kotlinx.android.synthetic.main.taxi_p_start_autopilot_view.view.actv_front_right_door
import kotlinx.android.synthetic.main.taxi_p_start_autopilot_view.view.actv_orderinfo
@@ -52,9 +49,9 @@ class StartAutopilotView : WindowRelativeLayout, StartAutopilotViewModel.StartAu
var isStarting = false
private var taxiPStartAutopilot: AnimationsContainer?=null
private var taxiPStartAutopilotCar: AnimationsContainer?=null
private var taxiPXiaozhiBelt: AnimationsContainer?=null
private var taxiPStartAutopilot: FrameAnimatorContainer?=null
private var taxiPStartAutopilotCar: FrameAnimatorContainer?=null
private var taxiPXiaozhiBelt: FrameAnimatorContainer?=null
init {
@@ -63,20 +60,20 @@ class StartAutopilotView : WindowRelativeLayout, StartAutopilotViewModel.StartAu
private fun initView() {
LayoutInflater.from(context).inflate(R.layout.taxi_p_start_autopilot_view, this, true)
taxiPStartAutopilotCar = AnimationsContainer(R.array.taxi_p_start_autopilot_car, 20,taxi_p_autopilot_starting)
taxiPStartAutopilotCar?.setOnAnimStopListener(object :AnimationsContainer.OnAnimationStoppedListener{
taxiPStartAutopilotCar = FrameAnimatorContainer(R.array.taxi_p_start_autopilot_car, 20,taxi_p_autopilot_starting)
taxiPStartAutopilotCar?.setOnAnimStopListener(object :FrameAnimatorContainer.OnAnimationStoppedListener{
override fun AnimationStopped() {
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "动画暂停")
}
})
taxiPStartAutopilot = AnimationsContainer(R.array.taxi_p_start_autopilot, 15,taxi_p_autopilot_btn_bg)
taxiPStartAutopilot?.setOnAnimStopListener(object :AnimationsContainer.OnAnimationStoppedListener{
taxiPStartAutopilot = FrameAnimatorContainer(R.array.taxi_p_start_autopilot, 15,taxi_p_autopilot_btn_bg)
taxiPStartAutopilot?.setOnAnimStopListener(object :FrameAnimatorContainer.OnAnimationStoppedListener{
override fun AnimationStopped() {
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "动画暂停")
}
})
taxiPXiaozhiBelt = AnimationsContainer(R.array.xiaozhi_belt, 15,iv_xiaozhi_belt)
taxiPXiaozhiBelt?.setOnAnimStopListener(object :AnimationsContainer.OnAnimationStoppedListener{
taxiPXiaozhiBelt = FrameAnimatorContainer(R.array.xiaozhi_belt, 15,iv_xiaozhi_belt)
taxiPXiaozhiBelt?.setOnAnimStopListener(object :FrameAnimatorContainer.OnAnimationStoppedListener{
override fun AnimationStopped() {
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "动画暂停")
}

View File

@@ -1,146 +0,0 @@
package com.mogo.och.taxi.passenger.widget.animutils
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.os.Handler
import android.os.Looper
import android.widget.ImageView
import com.mogo.commons.AbsMogoApplication
import java.lang.ref.SoftReference
class AnimationsContainer(resId: Int, fps: Int, imageView: ImageView) {
private lateinit var mFrames: IntArray // 帧数组
private var mIndex = 0 // 当前帧
private var mShouldRun = false // 开始/停止播放用
private var mIsRunning = false // 动画是否正在播放,防止重复播放
private var mSoftReferenceImageView: SoftReference<ImageView>? = null // 软引用ImageView以便及时释放掉
private var mHandler: Handler? = null
private var mDelayMillis = 0
private var mOnAnimationStoppedListener: OnAnimationStoppedListener? = null//播放停止监听
private var mBitmap: Bitmap? = null
private var mBitmapOptions: BitmapFactory.Options? = null //Bitmap管理类可有效减少Bitmap的OOM问题
init {
createAnimation(imageView, getData(resId), fps)
}
private fun createAnimation(imageView: ImageView, frames: IntArray, fps: Int) {
mHandler = Handler(Looper.myLooper()!!)
mFrames = frames
mIndex = -1
mSoftReferenceImageView = SoftReference(imageView)
mShouldRun = false
mIsRunning = false
mDelayMillis = 1000 / fps //帧动画时间间隔,毫秒
imageView.setImageResource(mFrames[0])
// 当图片大小类型相同时进行复用避免频繁GC
val bmp = (imageView.drawable as BitmapDrawable).bitmap
val width = bmp.width
val height = bmp.height
val config = bmp.config
mBitmap = Bitmap.createBitmap(width, height, config)
mBitmapOptions = BitmapFactory.Options()
//设置Bitmap内存复用
mBitmapOptions!!.inBitmap = mBitmap //Bitmap复用内存块类似对象池避免不必要的内存分配和回收
mBitmapOptions!!.inMutable = true //解码时返回可变Bitmap
mBitmapOptions!!.inSampleSize = 1 //缩放比例
}
//循环读取下一帧
private val next: Int
get() {
mIndex++
if (mIndex >= mFrames.size) mIndex = 0
return mFrames[mIndex]
}
/**
* 播放动画,同步锁防止多线程读帧时,数据安全问题
*/
@Synchronized
fun start() {
mShouldRun = true
if (mIsRunning) return
val runnable: Runnable = object : Runnable {
override fun run() {
val imageView = mSoftReferenceImageView!!.get()
if (!mShouldRun || imageView == null) {
mIsRunning = false
if (mOnAnimationStoppedListener != null) {
mOnAnimationStoppedListener!!.AnimationStopped()
}
return
}
mIsRunning = true
//新开线程去读下一帧
mHandler!!.postDelayed(this, mDelayMillis.toLong())
if (imageView.isShown) {
val imageRes: Int = next
if (mBitmap != null) { // so Build.VERSION.SDK_INT >= 11
var bitmap: Bitmap? = null
try {
bitmap = BitmapFactory.decodeResource(
imageView.resources,
imageRes,
mBitmapOptions
)
} catch (e: Exception) {
e.printStackTrace()
}
if (bitmap != null) {
imageView.setImageBitmap(bitmap)
} else {
imageView.setImageResource(imageRes)
mBitmap!!.recycle()
mBitmap = null
}
} else {
imageView.setImageResource(imageRes)
}
}
}
}
mHandler!!.post(runnable)
}
/**
* 停止播放
*/
@Synchronized
fun stop() {
mShouldRun = false
}
/**
* 设置停止播放监听
* @param listener 设置监听
*/
fun setOnAnimStopListener(listener: OnAnimationStoppedListener?) {
mOnAnimationStoppedListener = listener
}
/**
* 从xml中读取帧数组
* @param resId
* @return
*/
private fun getData(resId: Int): IntArray {
val array = AbsMogoApplication.getApp().resources.obtainTypedArray(resId)
val len = array.length()
val intArray = IntArray(array.length())
for (i in 0 until len) {
intArray[i] = array.getResourceId(i, 0)
}
array.recycle()
return intArray
}
/**
* 停止播放监听
*/
interface OnAnimationStoppedListener {
fun AnimationStopped()
}
}

View File

@@ -13,6 +13,7 @@ import com.mogo.eagle.core.utilcode.util.DeviceUtils
import com.mogo.eagle.core.utilcode.util.OverlayViewUtils
import com.mogo.map.listener.IMogoMapListener
import com.mogo.map.uicontroller.VisualAngleMode
import com.mogo.och.common.module.utils.FrameAnimatorContainer
import com.mogo.och.common.module.utils.RxUtils
import com.mogo.och.common.module.voice.VoiceNotice
import com.mogo.och.taxi.passenger.R
@@ -21,7 +22,6 @@ import com.mogo.och.taxi.passenger.ui.arrived.ArrivedView
import com.mogo.och.taxi.passenger.ui.bottom.BottomBar
import com.mogo.och.taxi.passenger.ui.check.TaxiPassengerCheckView
import com.mogo.och.taxi.passenger.ui.startautopilot.StartAutopilotView
import com.mogo.och.taxi.passenger.widget.animutils.AnimationsContainer
import kotlinx.android.synthetic.main.taxi_p_base_fragment.*
import java.lang.ref.WeakReference
@@ -52,7 +52,7 @@ class TaxiPassengerBaseFragment() :
*/
private var mStartAutopilotView: WeakReference<StartAutopilotView?>? = null
private var createProgressDialogAnim: AnimationsContainer?=null
private var createProgressDialogAnim: FrameAnimatorContainer?=null
override fun getLayoutId(): Int {
return R.layout.taxi_p_base_fragment
@@ -72,8 +72,8 @@ class TaxiPassengerBaseFragment() :
overMapView.onCreateView(savedInstanceState)
overMapView.hideResetView()
createProgressDialogAnim = AnimationsContainer(R.array.xiaozhi_normal, 20,aciv_xiaozhi_normal)
createProgressDialogAnim?.setOnAnimStopListener(object :AnimationsContainer.OnAnimationStoppedListener{
createProgressDialogAnim = FrameAnimatorContainer(R.array.xiaozhi_normal, 20,aciv_xiaozhi_normal)
createProgressDialogAnim?.setOnAnimStopListener(object : FrameAnimatorContainer.OnAnimationStoppedListener{
override fun AnimationStopped() {
CallerLogger.d(M_TAXI_P + TAG, "动画暂停")
}

View File

@@ -9,10 +9,10 @@ import com.mogo.eagle.core.utilcode.kotlin.onClick
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
import com.mogo.eagle.core.utilcode.util.OverlayViewUtils
import com.mogo.och.common.module.utils.FrameAnimatorContainer
import com.mogo.och.common.module.utils.RxUtils
import com.mogo.och.taxi.passenger.R
import com.mogo.och.taxi.passenger.widget.WindowRelativeLayout
import com.mogo.och.taxi.passenger.widget.animutils.AnimationsContainer
import com.shuyu.gsyvideoplayer.GSYVideoManager
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
@@ -43,7 +43,7 @@ class ArrivedView : WindowRelativeLayout, ArrivedViewModel.ArrivedViewCallback {
private val gsyVideoOptionBuilder = GSYVideoOptionBuilder()
private var taxiPxiaozhiLove: AnimationsContainer?=null
private var taxiPxiaozhiLove: FrameAnimatorContainer?=null
private fun initView() {
d(SceneConstant.M_TAXI_P + TAG, "initView")
@@ -64,8 +64,8 @@ class ArrivedView : WindowRelativeLayout, ArrivedViewModel.ArrivedViewCallback {
OverlayViewUtils.dismissOverlayView(this)
}
taxiPxiaozhiLove = AnimationsContainer(R.array.xiaozhi_love, 20,iv_xiaozhi_belt)
taxiPxiaozhiLove?.setOnAnimStopListener(object :AnimationsContainer.OnAnimationStoppedListener{
taxiPxiaozhiLove = FrameAnimatorContainer(R.array.xiaozhi_love, 20,iv_xiaozhi_belt)
taxiPxiaozhiLove?.setOnAnimStopListener(object : FrameAnimatorContainer.OnAnimationStoppedListener{
override fun AnimationStopped() {
d(SceneConstant.M_TAXI_P + TAG, "动画暂停")
}

View File

@@ -13,9 +13,9 @@ import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
import com.mogo.eagle.core.utilcode.util.OverlayViewUtils
import com.mogo.eagle.core.utilcode.util.ToastUtils
import com.mogo.och.common.module.utils.FrameAnimatorContainer
import com.mogo.och.taxi.passenger.R
import com.mogo.och.taxi.passenger.widget.WindowRelativeLayout
import com.mogo.och.taxi.passenger.widget.animutils.AnimationsContainer
import kotlinx.android.synthetic.main.taxi_p_start_autopilot_view.view.actv_front_left_door
import kotlinx.android.synthetic.main.taxi_p_start_autopilot_view.view.actv_front_right_door
import kotlinx.android.synthetic.main.taxi_p_start_autopilot_view.view.actv_orderinfo
@@ -48,9 +48,9 @@ class StartAutopilotView : WindowRelativeLayout, StartAutopilotViewModel.StartAu
var isStarting = false
private var taxiPStartAutopilot: AnimationsContainer?=null
private var taxiPStartAutopilotCar: AnimationsContainer?=null
private var taxiPXiaozhiBelt: AnimationsContainer?=null
private var taxiPStartAutopilot: FrameAnimatorContainer?=null
private var taxiPStartAutopilotCar: FrameAnimatorContainer?=null
private var taxiPXiaozhiBelt: FrameAnimatorContainer?=null
init {
@@ -59,20 +59,20 @@ class StartAutopilotView : WindowRelativeLayout, StartAutopilotViewModel.StartAu
private fun initView() {
LayoutInflater.from(context).inflate(R.layout.taxi_p_start_autopilot_view, this, true)
taxiPStartAutopilotCar = AnimationsContainer(R.array.taxi_p_start_autopilot_car, 20,taxi_p_autopilot_starting)
taxiPStartAutopilotCar?.setOnAnimStopListener(object :AnimationsContainer.OnAnimationStoppedListener{
taxiPStartAutopilotCar = FrameAnimatorContainer(R.array.taxi_p_start_autopilot_car, 20,taxi_p_autopilot_starting)
taxiPStartAutopilotCar?.setOnAnimStopListener(object :FrameAnimatorContainer.OnAnimationStoppedListener{
override fun AnimationStopped() {
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "动画暂停")
}
})
taxiPStartAutopilot = AnimationsContainer(R.array.taxi_p_start_autopilot, 15,taxi_p_autopilot_btn_bg)
taxiPStartAutopilot?.setOnAnimStopListener(object :AnimationsContainer.OnAnimationStoppedListener{
taxiPStartAutopilot = FrameAnimatorContainer(R.array.taxi_p_start_autopilot, 15,taxi_p_autopilot_btn_bg)
taxiPStartAutopilot?.setOnAnimStopListener(object :FrameAnimatorContainer.OnAnimationStoppedListener{
override fun AnimationStopped() {
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "动画暂停")
}
})
taxiPXiaozhiBelt = AnimationsContainer(R.array.xiaozhi_belt, 15,iv_xiaozhi_belt)
taxiPXiaozhiBelt?.setOnAnimStopListener(object :AnimationsContainer.OnAnimationStoppedListener{
taxiPXiaozhiBelt = FrameAnimatorContainer(R.array.xiaozhi_belt, 15,iv_xiaozhi_belt)
taxiPXiaozhiBelt?.setOnAnimStopListener(object :FrameAnimatorContainer.OnAnimationStoppedListener{
override fun AnimationStopped() {
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "动画暂停")
}

View File

@@ -1,146 +0,0 @@
package com.mogo.och.taxi.passenger.widget.animutils
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.os.Handler
import android.os.Looper
import android.widget.ImageView
import com.mogo.commons.AbsMogoApplication
import java.lang.ref.SoftReference
class AnimationsContainer(resId: Int, fps: Int, imageView: ImageView) {
private lateinit var mFrames: IntArray // 帧数组
private var mIndex = 0 // 当前帧
private var mShouldRun = false // 开始/停止播放用
private var mIsRunning = false // 动画是否正在播放,防止重复播放
private var mSoftReferenceImageView: SoftReference<ImageView>? = null // 软引用ImageView以便及时释放掉
private var mHandler: Handler? = null
private var mDelayMillis = 0
private var mOnAnimationStoppedListener: OnAnimationStoppedListener? = null//播放停止监听
private var mBitmap: Bitmap? = null
private var mBitmapOptions: BitmapFactory.Options? = null //Bitmap管理类可有效减少Bitmap的OOM问题
init {
createAnimation(imageView, getData(resId), fps)
}
private fun createAnimation(imageView: ImageView, frames: IntArray, fps: Int) {
mHandler = Handler(Looper.myLooper()!!)
mFrames = frames
mIndex = -1
mSoftReferenceImageView = SoftReference(imageView)
mShouldRun = false
mIsRunning = false
mDelayMillis = 1000 / fps //帧动画时间间隔,毫秒
imageView.setImageResource(mFrames[0])
// 当图片大小类型相同时进行复用避免频繁GC
val bmp = (imageView.drawable as BitmapDrawable).bitmap
val width = bmp.width
val height = bmp.height
val config = bmp.config
mBitmap = Bitmap.createBitmap(width, height, config)
mBitmapOptions = BitmapFactory.Options()
//设置Bitmap内存复用
mBitmapOptions!!.inBitmap = mBitmap //Bitmap复用内存块类似对象池避免不必要的内存分配和回收
mBitmapOptions!!.inMutable = true //解码时返回可变Bitmap
mBitmapOptions!!.inSampleSize = 1 //缩放比例
}
//循环读取下一帧
private val next: Int
get() {
mIndex++
if (mIndex >= mFrames.size) mIndex = 0
return mFrames[mIndex]
}
/**
* 播放动画,同步锁防止多线程读帧时,数据安全问题
*/
@Synchronized
fun start() {
mShouldRun = true
if (mIsRunning) return
val runnable: Runnable = object : Runnable {
override fun run() {
val imageView = mSoftReferenceImageView!!.get()
if (!mShouldRun || imageView == null) {
mIsRunning = false
if (mOnAnimationStoppedListener != null) {
mOnAnimationStoppedListener!!.AnimationStopped()
}
return
}
mIsRunning = true
//新开线程去读下一帧
mHandler!!.postDelayed(this, mDelayMillis.toLong())
if (imageView.isShown) {
val imageRes: Int = next
if (mBitmap != null) { // so Build.VERSION.SDK_INT >= 11
var bitmap: Bitmap? = null
try {
bitmap = BitmapFactory.decodeResource(
imageView.resources,
imageRes,
mBitmapOptions
)
} catch (e: Exception) {
e.printStackTrace()
}
if (bitmap != null) {
imageView.setImageBitmap(bitmap)
} else {
imageView.setImageResource(imageRes)
mBitmap!!.recycle()
mBitmap = null
}
} else {
imageView.setImageResource(imageRes)
}
}
}
}
mHandler!!.post(runnable)
}
/**
* 停止播放
*/
@Synchronized
fun stop() {
mShouldRun = false
}
/**
* 设置停止播放监听
* @param listener 设置监听
*/
fun setOnAnimStopListener(listener: OnAnimationStoppedListener?) {
mOnAnimationStoppedListener = listener
}
/**
* 从xml中读取帧数组
* @param resId
* @return
*/
private fun getData(resId: Int): IntArray {
val array = AbsMogoApplication.getApp().resources.obtainTypedArray(resId)
val len = array.length()
val intArray = IntArray(array.length())
for (i in 0 until len) {
intArray[i] = array.getResourceId(i, 0)
}
array.recycle()
return intArray
}
/**
* 停止播放监听
*/
interface OnAnimationStoppedListener {
fun AnimationStopped()
}
}