[5.0.0]
[帧动画抽离]
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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, "动画暂停")
|
||||
}
|
||||
|
||||
@@ -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, "动画暂停")
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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, "动画暂停")
|
||||
}
|
||||
|
||||
@@ -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, "动画暂停")
|
||||
}
|
||||
|
||||
@@ -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, "动画暂停")
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user