ImageFrame icon indicating copy to clipboard operation
ImageFrame copied to clipboard

另外一种实现方式

Open nobeginning opened this issue 7 years ago • 1 comments

用Kotlin实现的另外一种方式的思路。看一下是否有参考价值

用法:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_anim);

        View imageView = findViewById(R.id.imageView);
        List<Integer> resources = new ArrayList<>(32);
        Resources res = getResources();
        final String packageName = getPackageName();
        for (int i=1; i<=210; i++){
                String resName = "gift_" + i;
                int imageResId = res.getIdentifier(resName, "drawable", packageName);
                resources.add(imageResId);
        }
        controller = FrameAnim.Companion.create()
                .target(imageView)    //target支持任意View
                .resources(resources)
                .duration(16)
                .controller();
        controller.start();

        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (controller == null) {
                    return;
                }
                if (controller.isPaused()) {
                    controller.resume();
                } else {
                    controller.pause();
                }
            }
        });
}

主要功能类如下:

import android.graphics.drawable.BitmapDrawable
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.support.v4.view.ViewCompat
import android.util.Log
import android.view.View
import com.mrwang.imageframe.BitmapLoadUtils
import com.mrwang.imageframe.ImageCache
import java.lang.ref.SoftReference

/**
 * Created by young on 2018/2/8.
 */


class FrameAnim {

    companion object {
        fun create(): FrameAnim {
            return FrameAnim()
        }
    }

    interface AnimEndCallBack{
        fun onAnimEnd()
    }

    interface AnimLoopedCallBack{
        fun onAnimLooped(loopedCount:Int)
    }

    /**
     * 遥控器
     */
    interface Controller {
        fun start()
        fun isPaused(): Boolean
        fun pause()
        fun resume()
        fun destroy()
    }

    private inner class ControllerImpl(val ext: FrameAnim) : Controller {
        override fun start() {
            ext.start()
        }

        override fun destroy() {
            ext.destroy()
        }

        override fun isPaused(): Boolean {
            return ext.paused
        }

        override fun pause() {
            ext.pause()
        }

        override fun resume() {
            ext.resume()
        }
    }

    private val TAG = javaClass.simpleName

    private var target: View? = null
    private var list: List<Int>? = null
    private var duration: Long = 300
    private var index = 0
    private val decodeThread = DecodeThread()
    private var decodeHandler: Handler? = null
    private val uiHandler = Handler(Looper.getMainLooper())
    private var bitmapDrawable: BitmapDrawable? = null
    private var isInitLoad = true
    private var loop = true
    private var loopedCount = 0
    private var paused = false
    private var destroyed = false
    private val controller: Controller = ControllerImpl(this)
    private var animEndCallBack:AnimEndCallBack? = null
    private var animLoopedCallBack:AnimLoopedCallBack? = null

    private val autoDestroy:IAutoDestroy = object : IAutoDestroy {
        override fun autoDestroy() {
            destroy()
        }
    }

    fun target(target: View): FrameAnim {
        this.target = target
        return this
    }

    fun resources(list: List<Int>): FrameAnim {
        this.list = list
        return this
    }

    fun duration(duration: Long): FrameAnim {
        this.duration = duration
        return this
    }

    fun loop(lp: Boolean): FrameAnim {
        this.loop = lp
        return this
    }

    fun callBackForAnimEnd(endCallBack: AnimEndCallBack): FrameAnim {
        this.animEndCallBack = endCallBack
        return this
    }

    fun callBackForAnimLooped(loopedCallBack: AnimLoopedCallBack): FrameAnim {
        this.animLoopedCallBack = loopedCallBack
        return this
    }

    fun controller():Controller{
        return controller
    }

    fun start(): Controller {
        if (target == null) {
            Log.w(TAG, "The target is Null")
            throw IllegalArgumentException("The target must not be Null")
        }
        if (list == null || list!!.isEmpty()) {
            Log.w(TAG, "The resources is Empty")
            throw IllegalArgumentException("The resources must not be Null or Empty")
        }
        val ctx = target!!.context
        ctx.registerAutoDestroy(autoDestroy)
        if (decodeHandler!=null){
            Log.e(TAG, "Task already started")
            return controller
        }
        if (paused) {
            Log.e(TAG, "Task is paused, Please use resume() to continue")
            return controller
        }
        decodeThread.start()
        if (decodeHandler == null) {
            decodeHandler = Handler(decodeThread.looper)
        }
        load()
        return controller
    }

    private fun pause() {
        if (decodeHandler == null) {
            throw IllegalStateException("Have u forgot to invoke the ``fun start()``")
        }
        paused = true
        decodeHandler!!.removeCallbacksAndMessages(null)
        uiHandler.removeCallbacksAndMessages(null)
    }

    private fun resume() {
        if (decodeHandler == null) {
            throw IllegalStateException("Have u forgot to invoke the ``fun start()``")
        }
        paused = false
        load()
    }

    fun destroy() {
        if (destroyed){
            return
        }
        destroyed = true
        decodeThread.quit()
        uiHandler.removeCallbacks(uiCallBack)
        println("Component has destroyed")
    }

    private var uiCallBack: Runnable? = null
    private val imageCache = ImageCache()
    private fun load() {
        val resources = list!!
        if (index >= resources.size && loop) {
            index = 0
            loopedCount++
            animLoopedCallBack?.onAnimLooped(loopedCount)
        } else if (index >= resources.size && !loop) {
            Log.d(TAG, "The End")
            println("The End")
            animEndCallBack?.onAnimEnd()
            return
        }

        if (bitmapDrawable != null) {
            imageCache.mReusableBitmaps.add(SoftReference(bitmapDrawable!!.bitmap))
        }
        val resId = resources[index]
        decodeHandler!!.post {
            val start = System.currentTimeMillis()
            val resource = target!!.resources
            bitmapDrawable = BitmapLoadUtils.decodeSampledBitmapFromRes(resource, resId, 0,
                    0,
                    imageCache, true)
            val end = System.currentTimeMillis()
            val decodeConsuming = end - start
            val delay = duration - decodeConsuming
            val actDelay = if (delay > 0) delay else 0
            val finalDelay = if (isInitLoad) 0 else actDelay
            isInitLoad = false
            uiCallBack = Runnable {
                ViewCompat.setBackground(target, bitmapDrawable)
                index++
                load()
            }
            uiHandler.postDelayed(uiCallBack, finalDelay)
        }
    }

    inner class DecodeThread : HandlerThread("DecodeThread")

}

自动处理生命周期:

interface IAutoDestroy {
    fun autoDestroy()
}

class LifeFragment : Fragment() {
    private val set: MutableSet<IAutoDestroy> = mutableSetOf()

    fun register(autoDestroy: IAutoDestroy) {
        set.add(autoDestroy)
    }

    override fun onDestroy() {
        super.onDestroy()
        for (autoDestroy in set) {
            autoDestroy.autoDestroy()
        }
    }
}

fun Context.registerAutoDestroy(autoDestroy: IAutoDestroy) {
    if (this is FragmentActivity) {
        var exist = supportFragmentManager.findFragmentByTag("Hello")
        if (exist == null) {
            exist = LifeFragment()
            supportFragmentManager.beginTransaction().add(exist, "Hello").commit()
        }
        if (exist is LifeFragment) {
            exist.register(autoDestroy)
        }
    }else {
        Log.e("registerAutoDestroy", "The context type do not support fragment")
    }
}

nobeginning avatar Feb 12 '18 04:02 nobeginning

大佬666

Mr-wangyong avatar Aug 11 '18 03:08 Mr-wangyong