广告
返回顶部
首页 > 资讯 > 精选 >Android怎么实现点赞动画效果
  • 702
分享到

Android怎么实现点赞动画效果

2023-06-29 01:06:59 702人浏览 安东尼
摘要

今天小编给大家分享一下Android怎么实现点赞动画效果的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、前言对接下来功能实

今天小编给大家分享一下Android怎么实现点赞动画效果的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    一、前言

    对接下来功能实现的探索。

    二、需求拆分

    仔细观察点赞交互,看出大概以下几个步骤:

    点赞控件需要自定义,对其触摸事件进行处理。

    点赞动画的实现。

    要有一个存放动画的容器

    三、实现方案

    1、点赞控件触摸事件处理

    点赞控件是区分长按和点击处理的,另外我们发现在手指按下以后包括手指的移动直到手指的抬起都在执行动画。因为点赞的点击区域可能包括点赞次数,所以这里就自定义了点赞控件,并处理onTouchEvent(event: MotionEvent)事件,区分长按和单击是使用了点击到手指抬起的间隔时间区分的,伪代码如下:

    override fun onTouchEvent(event: MotionEvent): Boolean {    var onTouch: Boolean    when (event.action) {        MotionEvent.ACTION_DOWN -> {            isRefreshing = false            isDowning = true            //点击            lastDownTime = System.currentTimeMillis()            postDelayed(autoPollTask, CLICK_INTERVAL_TIME)            onTouch = true        }        MotionEvent.ACTION_UP -> {            isDowning = false            //抬起            if (System.currentTimeMillis() - lastDownTime < CLICK_INTERVAL_TIME) {                //小于间隔时间按照单击处理                onFingerDowningListener?.onDown(this)            } else {                //大于等于间隔时间按照长按抬起手指处理                onFingerDowningListener?.onUp()            }            removeCallbacks(autoPollTask)            onTouch = true        }        MotionEvent.ACTION_CANCEL ->{            isDowning = false            removeCallbacks(autoPollTask)            onTouch = false        }        else -> onTouch = false    }    return onTouch}

    长按时使用Runnable的postDelayed(Runnable action, long delayMillis)方法来进行不断的执行动画,伪代码:

    private inner class AutoPollTask : Runnable {    override fun run() {        onFingerDowningListener?.onLongPress(this@LikeView)        if(!canLongPress){            removeCallbacks(autoPollTask)        }else{            postDelayed(autoPollTask, CLICK_INTERVAL_TIME)        }    }}

    2、点赞动画的实现

    点赞效果元素分为:点赞表情图标、点赞次数数字以及点赞文案

    2.1、点赞效果图片的获取和存储管理

    这里参考了SuperLike的做法,对图片进行了缓存处理,代码如下:

    object BitmapProviderFactory {    fun getProvider(context: Context): BitmapProvider.Provider {        return BitmapProvider.Builder(context)            .setDrawableArray(                intArrayOf(                        R.mipmap.emoji_1, R.mipmap.emoji_2, R.mipmap.emoji_3,                        R.mipmap.emoji_4, R.mipmap.emoji_5, R.mipmap.emoji_6,                        R.mipmap.emoji_7, R.mipmap.emoji_8, R.mipmap.emoji_9, R.mipmap.emoji_10,                        R.mipmap.emoji_11, R.mipmap.emoji_12, R.mipmap.emoji_13,                        R.mipmap.emoji_14                )            )            .setNumberDrawableArray(                intArrayOf(                        R.mipmap.multi_digg_num_0, R.mipmap.multi_digg_num_1,                        R.mipmap.multi_digg_num_2, R.mipmap.multi_digg_num_3,                        R.mipmap.multi_digg_num_4, R.mipmap.multi_digg_num_5,                        R.mipmap.multi_digg_num_6, R.mipmap.multi_digg_num_7,                        R.mipmap.multi_digg_num_8, R.mipmap.multi_digg_num_9                )            )            .setLevelDrawableArray(                intArrayOf(                        R.mipmap.multi_digg_Word_level_1, R.mipmap.multi_digg_word_level_2,                        R.mipmap.multi_digg_word_level_3                )            )            .build()    }}
    object BitmapProvider {    class Default(        private val context: Context,        cacheSize: Int,        @DrawableRes private val drawableArray: IntArray,        @DrawableRes private val numberDrawableArray: IntArray?,        @DrawableRes private val levelDrawableArray: IntArray?,        private val levelStringArray: Array<String>?,        private val textSize: Float    ) : Provider {        private val bitmapLruCache: LruCache<Int, Bitmap> = LruCache(cacheSize)        private val NUMBER_PREFIX = 0x70000000        private val LEVEL_PREFIX = -0x80000000                override fun getNumberBitmap(number: Int): Bitmap? {            var bitmap: Bitmap?            if (numberDrawableArray != null && numberDrawableArray.isNotEmpty()) {                val index = number % numberDrawableArray.size                bitmap = bitmapLruCache[NUMBER_PREFIX or numberDrawableArray[index]]                if (bitmap == null) {                    bitmap =                        BitmapFactory.decodeResource(context.resources, numberDrawableArray[index])                    bitmapLruCache.put(NUMBER_PREFIX or numberDrawableArray[index], bitmap)                }            } else {                bitmap = bitmapLruCache[NUMBER_PREFIX or number]                if (bitmap == null) {                    bitmap = createBitmapByText(textSize, number.toString())                    bitmapLruCache.put(NUMBER_PREFIX or number, bitmap)                }            }            return bitmap        }                override fun getLevelBitmap(level: Int): Bitmap? {            var bitmap: Bitmap?            if (levelDrawableArray != null && levelDrawableArray.isNotEmpty()) {                val index = level.coerceAtMost(levelDrawableArray.size)                bitmap = bitmapLruCache[LEVEL_PREFIX or levelDrawableArray[index]]                if (bitmap == null) {                    bitmap =                        BitmapFactory.decodeResource(context.resources, levelDrawableArray[index])                    bitmapLruCache.put(LEVEL_PREFIX or levelDrawableArray[index], bitmap)                }            } else {                bitmap = bitmapLruCache[LEVEL_PREFIX or level]                if (bitmap == null && !levelStringArray.isNullOrEmpty()) {                    val index = level.coerceAtMost(levelStringArray.size)                    bitmap = createBitmapByText(textSize, levelStringArray[index])                    bitmapLruCache.put(LEVEL_PREFIX or level, bitmap)                }            }            return bitmap        }                override val randomBitmap: Bitmap            get() {                val index = (Math.random() * drawableArray.size).toInt()                var bitmap = bitmapLruCache[drawableArray[index]]                if (bitmap == null) {                    bitmap = BitmapFactory.decodeResource(context.resources, drawableArray[index])                    bitmapLruCache.put(drawableArray[index], bitmap)                }                return bitmap            }        private fun createBitmapByText(textSize: Float, text: String): Bitmap {            val textPaint = TextPaint()            textPaint.color = Color.BLACK            textPaint.textSize = textSize            val bitmap = Bitmap.createBitmap(                textPaint.measureText(text).toInt(),                textSize.toInt(), Bitmap.Config.ARGB_4444            )            val canvas = Canvas(bitmap)            canvas.drawColor(Color.TRANSPARENT)            canvas.drawText(text, 0f, textSize, textPaint)            return bitmap        }    }    class Builder(var context: Context) {        private var cacheSize = 0        @DrawableRes        private var drawableArray: IntArray? = null        @DrawableRes        private var numberDrawableArray: IntArray? = null        @DrawableRes        private var levelDrawableArray: IntArray? = null        private var levelStringArray: Array<String>? = null        private var textSize = 0f        fun setCacheSize(cacheSize: Int): Builder {            this.cacheSize = cacheSize            return this        }                fun setDrawableArray(@DrawableRes drawableArray: IntArray?): Builder {            this.drawableArray = drawableArray            return this        }                fun setNumberDrawableArray(@DrawableRes numberDrawableArray: IntArray): Builder {            this.numberDrawableArray = numberDrawableArray            return this        }                fun setLevelDrawableArray(@DrawableRes levelDrawableArray: IntArray?): Builder {            this.levelDrawableArray = levelDrawableArray            return this        }        fun setLevelStringArray(levelStringArray: Array<String>?): Builder {            this.levelStringArray = levelStringArray            return this        }        fun setTextSize(textSize: Float): Builder {            this.textSize = textSize            return this        }        fun build(): Provider {            if (cacheSize == 0) {                cacheSize = 32            }            if (drawableArray == null || drawableArray?.isEmpty() == true) {                drawableArray = intArrayOf(R.mipmap.emoji_1)            }            if (levelDrawableArray == null && levelStringArray.isNullOrEmpty()) {                levelStringArray = arrayOf("次赞!", "太棒了!!", "超赞同!!!")            }            return Default(                context, cacheSize, drawableArray!!, numberDrawableArray,                levelDrawableArray, levelStringArray, textSize            )        }    }    interface Provider {                val randomBitmap: Bitmap                fun getNumberBitmap(number: Int): Bitmap?                fun getLevelBitmap(level: Int): Bitmap?    }}
    2.2、点赞表情图标动画实现

    这里的实现参考了toutiaothumb,表情图标的动画大致分为:上升动画的同时执行图标大小变化动画和图标透明度变化,在上升动画完成时进行下降动画。代码如下:

    class EmojiAnimationView @JVMOverloads constructor(    context: Context,    private val provider: BitmapProvider.Provider?,    attrs: AttributeSet? = null,    defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {    private var mThumbImage: Bitmap? = null    private var mBitmapPaint: Paint? = null    private var mAnimatorListener: AnimatorListener? = null        private var emojiWith = 0        private var emojiHeight = 0    private fun init() {        //初始化图片,取出随机图标        mThumbImage = provider?.randomBitmap    }    init {        //初始化paint        mBitmapPaint = Paint()        mBitmapPaint?.isAntiAlias = true    }        private fun showAnimation() {        val imageWidth = mThumbImage?.width ?:0        val imageHeight = mThumbImage?.height ?:0        val topX = -1080 + (1400 * Math.random()).toFloat()        val topY = -300 + (-700 * Math.random()).toFloat()        //上升动画        val translateAnimationX = ObjectAnimator.ofFloat(this, "translationX", 0f, topX)        translateAnimationX.duration = DURATION.toLong()        translateAnimationX.interpolator = LinearInterpolator()        val translateAnimationY = ObjectAnimator.ofFloat(this, "translationY", 0f, topY)        translateAnimationY.duration = DURATION.toLong()        translateAnimationY.interpolator = DecelerateInterpolator()        //表情图片的大小变化        val translateAnimationRightLength = ObjectAnimator.ofInt(            this, "emojiWith",            0,imageWidth,imageWidth,imageWidth,imageWidth, imageWidth, imageWidth, imageWidth, imageWidth, imageWidth        )        translateAnimationRightLength.duration = DURATION.toLong()        val translateAnimationBottomLength = ObjectAnimator.ofInt(            this, "emojiHeight",            0,imageHeight,imageHeight,imageHeight,imageHeight,imageHeight, imageHeight, imageHeight, imageHeight, imageHeight        )        translateAnimationBottomLength.duration = DURATION.toLong()        translateAnimationRightLength.addUpdateListener {            invalidate()        }        //透明度变化        val alphaAnimation = ObjectAnimator.ofFloat(            this,            "alpha",            0.8f,            1.0f,            1.0f,            1.0f,            0.9f,            0.8f,            0.8f,            0.7f,            0.6f,            0f        )        alphaAnimation.duration = DURATION.toLong()        //动画集合        val animatorSet = AnimatorSet()        animatorSet.play(translateAnimationX).with(translateAnimationY)            .with(translateAnimationRightLength).with(translateAnimationBottomLength)            .with(alphaAnimation)        //下降动画        val translateAnimationXDown =            ObjectAnimator.ofFloat(this, "translationX", topX, topX * 1.2f)        translateAnimationXDown.duration = (DURATION / 5).toLong()        translateAnimationXDown.interpolator = LinearInterpolator()        val translateAnimationYDown =            ObjectAnimator.ofFloat(this, "translationY", topY, topY * 0.8f)        translateAnimationYDown.duration = (DURATION / 5).toLong()        translateAnimationYDown.interpolator = AccelerateInterpolator()        //设置动画播放顺序        val animatorSetDown = AnimatorSet()        animatorSet.start()        animatorSet.addListener(object : Animator.AnimatorListener {            override fun onAnimationStart(animation: Animator) {}            override fun onAnimationEnd(animation: Animator) {                animatorSetDown.play(translateAnimationXDown).with(translateAnimationYDown)                animatorSetDown.start()            }            override fun onAnimationCancel(animation: Animator) {}            override fun onAnimationRepeat(animation: Animator) {}        })        animatorSetDown.addListener(object : Animator.AnimatorListener {            override fun onAnimationStart(animation: Animator) {}            override fun onAnimationEnd(animation: Animator) {                //动画完成后通知移除动画view                mAnimatorListener?.onAnimationEmojiEnd()            }            override fun onAnimationCancel(animation: Animator) {}            override fun onAnimationRepeat(animation: Animator) {}        })    }    override fun onDraw(canvas: Canvas) {        super.onDraw(canvas)        drawEmojiImage(canvas)    }        private fun drawEmojiImage(canvas: Canvas) {        mThumbImage?.let{            val dst = Rect()            dst.left = 0            dst.top = 0            dst.right = emojiWith            dst.bottom = emojiHeight            canvas.drawBitmap(it, null, dst, mBitmapPaint)        }    }        fun getEmojiWith(): Int {        return emojiWith    }    fun setEmojiWith(emojiWith: Int) {        this.emojiWith = emojiWith    }    fun getEmojiHeight(): Int {        return emojiHeight    }    fun setEmojiHeight(emojiHeight: Int) {        this.emojiHeight = emojiHeight    }    fun setEmojiAnimation() {        showAnimation()    }    fun setAnimatorListener(animatorListener: AnimatorListener?) {        mAnimatorListener = animatorListener    }    interface AnimatorListener {                fun onAnimationEmojiEnd()    }    fun setEmoji() {        init()    }    compaNIOn object {        //动画时长        const val DURATION = 500    }}
    2.3、点赞次数和点赞文案的绘制

    这里的点赞次数处理了从1到999,并在不同的点赞次数区间显示不同的点赞文案。代码如下:

    class NumberLevelView @JvmOverloads constructor(    context: Context,    private val provider: BitmapProvider.Provider?,    private val x: Int,    attrs: AttributeSet? = null,    defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {    private var textPaint: Paint = Paint()        private var mNumber = 0        private var bitmapTalk: Bitmap? = null        private var level = 0        private var numberImageWidth = 0        private var offsetX = 0        private var initialValue = 0        private var spacing = 0    init {        textPaint.isAntiAlias = true        initialValue = x - PublicMethod.dp2px(context, 120f)        numberImageWidth = provider?.getNumberBitmap(1)?.width ?: 0        spacing = PublicMethod.dp2px(context, 10f)    }    override fun onDraw(canvas: Canvas) {        super.onDraw(canvas)        val levelBitmap = provider?.getLevelBitmap(level) ?: return        //等级图片的宽度        val levelBitmapWidth = levelBitmap.width        val dst = Rect()        when (mNumber) {            in 0..9 -> {                initialValue = x - levelBitmapWidth                dst.left =  initialValue                dst.right = initialValue + levelBitmapWidth            }            in 10..99 -> {                initialValue  = x - PublicMethod.dp2px(context, 100f)                dst.left =  initialValue + numberImageWidth + spacing                dst.right = initialValue+ numberImageWidth  + spacing+ levelBitmapWidth            }            else -> {                initialValue = x - PublicMethod.dp2px(context, 120f)                dst.left =  initialValue + 2*numberImageWidth + spacing                dst.right = initialValue+ 2*numberImageWidth + spacing + levelBitmapWidth            }        }        dst.top = 0        dst.bottom = levelBitmap.height        //绘制等级文案图标        canvas.drawBitmap(levelBitmap, null, dst, textPaint)        while (mNumber > 0) {            val number = mNumber % 10            val bitmap = provider.getNumberBitmap(number)?:continue            offsetX += bitmap.width            //这里是数字            val rect = Rect()            rect.top = 0            when {                mNumber/ 10 < 1 -> {                    rect.left = initialValue - bitmap.width                    rect.right = initialValue                }                mNumber/ 10 in 1..9 -> {                    rect.left = initialValue                    rect.right = initialValue + bitmap.width                }                else -> {                    rect.left = initialValue +  bitmap.width                    rect.right = initialValue +2* bitmap.width                }            }            rect.bottom = bitmap.height            //绘制数字            canvas.drawBitmap(bitmap, null, rect, textPaint)            mNumber /= 10        }    }    fun setNumber(number: Int) {        this.mNumber = number        if (mNumber >999){            mNumber = 999        }        level = when (mNumber) {            in 1..20 -> {                0            }            in 21..80 -> {                1            }            else -> {                2            }        }        //根据等级取出等级文案图标        bitmapTalk = provider?.getLevelBitmap(level)        invalidate()    }}

    3、存放点赞动画的容器

    我们需要自定义一个view来存放动画,以及提供开始动画以及回收动画view等工作。代码如下:

    class LikeAnimationLayout @JvmOverloads constructor(    context: Context,    attrs: AttributeSet? = null,    defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr) {    private var lastClickTime: Long = 0    private var currentNumber = 1    private var mNumberLevelView: NumberLevelView? = null        private var hasEruptionAnimation = false        private var hasTextAnimation = false        private var canLongPress = false        private var maxAngle = 0    private var minAngle = 0    private var pointX = 0    private var pointY = 0    var provider: BitmapProvider.Provider? = null        get() {            if (field == null) {                field = BitmapProvider.Builder(context)                    .build()            }            return field        }    private fun init(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {        val typedArray = context.obtainStyledAttributes(            attrs,                R.styleable.LikeAnimationLayout,            defStyleAttr,            0        )        maxAngle =            typedArray.getInteger(R.styleable.LikeAnimationLayout_max_angle, MAX_ANGLE)        minAngle =            typedArray.getInteger(R.styleable.LikeAnimationLayout_min_angle, MIN_ANGLE)        hasEruptionAnimation = typedArray.getBoolean(                R.styleable.LikeAnimationLayout_show_emoji,            true        )        hasTextAnimation = typedArray.getBoolean(R.styleable.LikeAnimationLayout_show_text, true)        typedArray.recycle()    }        private fun addEmojiView(        context: Context?,        x: Int,        y: Int    ) {        for (i in 0 .. ERUPTION_ELEMENT_AMOUNT) {            val layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)            layoutParams.setMargins(x, y, 0, 0)            val articleThumb = context?.let {                EmojiAnimationView(                    it, provider                )            }            articleThumb?.let {                it.setEmoji()                this.addView(it, -1, layoutParams)                it.setAnimatorListener(object : EmojiAnimationView.AnimatorListener {                    override fun onAnimationEmojiEnd() {                        removeView(it)                        val handler = Handler()                        handler.postDelayed({                            if (mNumberLevelView != null && System.currentTimeMillis() - lastClickTime >= SPACING_TIME) {                                removeView(mNumberLevelView)                                mNumberLevelView = null                            }                        }, SPACING_TIME)                    }                })                it.setEmojiAnimation()            }        }    }        fun launch(x: Int, y: Int) {        if (System.currentTimeMillis() - lastClickTime >= SPACING_TIME) {            pointX = x            pointY = y            //单次点击            addEmojiView(context, x, y-50)            lastClickTime = System.currentTimeMillis()            currentNumber = 1            if (mNumberLevelView != null) {                removeView(mNumberLevelView)                mNumberLevelView = null            }        } else { //连续点击            if (pointX != x || pointY != y){                return            }            lastClickTime = System.currentTimeMillis()            Log.i(TAG, "当前动画化正在执行")            addEmojiView(context, x, y)            //添加数字连击view            val layoutParams = RelativeLayout.LayoutParams(                ViewGroup.LayoutParams.MATCH_PARENT,                ViewGroup.LayoutParams.WRAP_CONTENT            )           layoutParams.setMargins(0, y - PublicMethod.dp2px(context, 60f), 0, 0)            if (mNumberLevelView == null) {                mNumberLevelView = NumberLevelView(context,provider,x)                addView(mNumberLevelView, layoutParams)            }            currentNumber++            mNumberLevelView?.setNumber(currentNumber)        }    }    companion object {        private const val TAG = "LikeAnimationLayout"                private const val ERUPTION_ELEMENT_AMOUNT = 8        private const val MAX_ANGLE = 180        private const val MIN_ANGLE = 70        private const val SPACING_TIME = 400L    }    init {        init(context, attrs, defStyleAttr)    }}

    注意:动画完成之后一定要清除view。

    4、启动动画

    点赞控件的手势回调,伪代码如下:

    holder.likeView.setOnFingerDowningListener(object : OnFingerDowningListener {        override fun onLongPress(v: View) {        if (!bean.hasLike) {            //未点赞            if (!fistLongPress) {                //这里同步点赞接口等数据交互                bean.likeNumber++                bean.hasLike = true                setLikeStatus(holder, bean)            }            //显示动画            onLikeAnimationListener?.doLikeAnimation(v)        } else {            if (System.currentTimeMillis() - lastClickTime <= throttleTime && lastClickTime != 0L) {                //处理点击过后为点赞状态的情况                onLikeAnimationListener?.doLikeAnimation(v)                lastClickTime = System.currentTimeMillis()            } else {                //处理长按为点赞状态后的情况                onLikeAnimationListener?.doLikeAnimation(v)            }        }        fistLongPress = true    }        override fun onUp() {        fistLongPress = false    }        override fun onDown(v: View) {        if (System.currentTimeMillis() - lastClickTime > throttleTime || lastClickTime == 0L) {            if (!bean.hasLike) {                //未点赞情况下,点赞接口和数据交互处理                bean.hasLike = true                bean.likeNumber++                setLikeStatus(holder, bean)                throttleTime = 1000                onLikeAnimationListener?.doLikeAnimation(v)            } else {                //点赞状态下,取消点赞接口和数据交互处理                bean.hasLike = false                bean.likeNumber--                setLikeStatus(holder, bean)                throttleTime = 30            }        } else if (lastClickTime != 0L && bean.hasLike) {            //在时间范围内,连续点击点赞,显示动画            onLikeAnimationListener?.doLikeAnimation(v)        }        lastClickTime = System.currentTimeMillis()    }})

    在显示动画页面初始化工作时初始化动画资源:

    override fun onCreate(savedInstanceState: Bundle?) {    super.onCreate(savedInstanceState)    setContentView(R.layout.activity_list)    likeAnimationLayout?.provider = BitmapProviderFactory.getProvider(this)}

    在显示动画的回调中启动动画:

    override fun doLikeAnimation(v: View) {    val itemPosition = IntArray(2)    val superLikePosition = IntArray(2)    v.getLocationOnScreen(itemPosition)    likeAnimationLayout?.getLocationOnScreen(superLikePosition)    val x = itemPosition[0] + v.width / 2    val y = itemPosition[1] - superLikePosition[1] + v.height / 2    likeAnimationLayout?.launch(x, y)}

    四、遇到的问题

    因为流列表中使用了SmartRefreshLayout下拉刷新控件,如果在列表前几条内容进行点赞动画当手指移动时触摸事件会被SmartRefreshLayout拦截去执行下拉刷新,那么手指抬起时点赞控件得不到响应会一直进行动画操作,目前想到的解决方案是点赞控件在手指按下时查看父布局有无SmartRefreshLayout,如果有通过反射先禁掉下拉刷新功能,手指抬起或者取消进行重置操作。代码如下:

    override fun dispatchTouchEvent(event: MotionEvent?): Boolean {    parent?.requestDisallowInterceptTouchEvent(true)    return super.dispatchTouchEvent(event)}override fun onTouchEvent(event: MotionEvent): Boolean {    var onTouch: Boolean    when (event.action) {        MotionEvent.ACTION_DOWN -> {            isRefreshing = false            isDowning = true            //点击            lastDownTime = System.currentTimeMillis()            findSmartRefreshLayout(false)            if (isRefreshing) {                //如果有下拉控件并且正在刷新直接不响应                return false            }            postDelayed(autoPollTask, CLICK_INTERVAL_TIME)            onTouch = true        }        MotionEvent.ACTION_UP -> {            isDowning = false            //抬起            if (System.currentTimeMillis() - lastDownTime < CLICK_INTERVAL_TIME) {                //小于间隔时间按照单击处理                onFingerDowningListener?.onDown(this)            } else {                //大于等于间隔时间按照长按抬起手指处理                onFingerDowningListener?.onUp()            }            findSmartRefreshLayout(true)            removeCallbacks(autoPollTask)            onTouch = true        }        MotionEvent.ACTION_CANCEL ->{            isDowning = false            findSmartRefreshLayout(true)            removeCallbacks(autoPollTask)            onTouch = false        }        else -> onTouch = false    }    return onTouch}private fun findSmartRefreshLayout(enable: Boolean) {    var parent = parent    while (parent != null && parent !is ContentFrameLayout) {        if (parent is SmartRefreshLayout) {            isRefreshing = parent.state == RefreshState.Refreshing            if (isRefreshing){                //如果有下拉控件并且正在刷新直接结束                break            }            if (!enable && firstClick){                try {                    firstClick = false                    val field: Field = parent.javaClass.getDeclaredField("mEnableRefresh")                    field.isAccessible = true                    //通过反射获取是否可以先下拉刷新的初始值                    enableRefresh = field.getBoolean(parent)                }catch (e: Exception) {                    e.printStackTrace()                }            }            if (enableRefresh){                //如果初始值不可以下拉刷新不要设置下拉刷新状态                parent.setEnableRefresh(enable)            }            parent.setEnableLoadMore(enable)            break        } else {            parent = parent.parent        }    }}

    五、实现效果

    Android怎么实现点赞动画效果

    以上就是“Android怎么实现点赞动画效果”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

    --结束END--

    本文标题: Android怎么实现点赞动画效果

    本文链接: https://www.lsjlt.com/news/321937.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • Android怎么实现点赞动画效果
      今天小编给大家分享一下Android怎么实现点赞动画效果的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、前言对接下来功能实...
      99+
      2023-06-29
    • iOS实现抖音点赞动画效果
      本文实例为大家分享了iOS实现抖音点赞动画的具体代码,供大家参考,具体内容如下 1. 概述 最近看到抖音点赞爱心的动画效果比较好,出于好奇,自己也研究仿照动画效果写了一个,不喜欢的朋...
      99+
      2022-05-31
      iOS 抖音 点赞
    • Android实现仿今日头条点赞动画效果实例
      目录一、前言二、需求拆分三、实现方案1、点赞控件触摸事件处理2、点赞动画的实现2.1、点赞效果图片的获取和存储管理2.2、点赞表情图标动画实现2.3、点赞次数和点赞文案的绘制3、存放...
      99+
      2022-11-13
    • Android实现点赞动画(27)
      本文实例为大家分享了Android使用入门第二十七篇点赞动画的具体代码,供大家参考,具体内容如下 MainActivity.java代码: package siso.like...
      99+
      2022-06-06
      动画 Android
    • 使用Vue transition 实现点赞动画效果
      要实现点赞动画效果,你可以使用Vue的过渡(transition)组件。下面是一个简单的示例代码:```html<templa...
      99+
      2023-09-21
      Vue
    • Android实现简单点赞动画
      本文实例为大家分享了Android实现简单点赞动画的具体代码,供大家参考,具体内容如下 思路 1、找到Activity中DecorView的RootView 2、确定点赞控件位于屏幕...
      99+
      2022-11-12
    • 利用Android实现一种点赞动画效果的全过程
      目录前言点击后的缩放效果拇指的散开效果示例总结前言 最近有个需求,需要仿照公司的H5实现一个游戏助手,其中一个点赞的按钮有动画效果,如下图: 分析一下这个动画,点击按钮后,拇指首先...
      99+
      2022-12-08
      android 点赞动画 android点赞效果 android点击动画
    • 通过JetpackCompose实现双击点赞动画效果
      目录实现步骤先红色画个爱心点击事件加动画完整代码效果图实现步骤 先红色画个爱心 Icon( Icons.Filled.Favorite, "爱心", Modi...
      99+
      2022-11-13
    • Vue transition实现点赞动画效果的示例
      目录效果一览爱心效果 数字滚动动画 点赞动画 效果一览 爱心效果 材料:爱心图标两个,没有我这种 icon 组件的用 png 图片代替 <transition :nam...
      99+
      2022-11-12
    • iOS实现点赞动画特效
      本文实例为大家分享了iOS实现点赞动画特效的具体代码,供大家参考,具体内容如下 动画的基本使用 动画的实现基本上是基于对View控件和View的layer属性进行操作,对视图进行移动...
      99+
      2022-06-05
      iOS 点赞
    • PHP+Redis怎么实现点赞效果
      这篇文章主要介绍“PHP+Redis怎么实现点赞效果”,在日常操作中,相信很多人在PHP+Redis怎么实现点赞效果问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PHP+Redis怎么实现点赞效果”的疑惑有所...
      99+
      2023-06-04
    • 如何通过Jetpack Compose实现双击点赞动画效果
      这篇文章主要介绍如何通过Jetpack Compose实现双击点赞动画效果,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!实现步骤先红色画个爱心Icon(    Ico...
      99+
      2023-06-28
    • 在Android项目中实现一个点赞动画
      在Android项目中实现一个点赞动画?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。具体内容如下MainActivity.java代码:package siso.likea...
      99+
      2023-05-31
      android roi 目中
    • android怎么实现加载动画效果
      Android中实现加载动画效果可以通过以下几种方式:1. 使用ProgressBar:ProgressBar是Android系统提...
      99+
      2023-08-08
      android
    • Flutter实现抖音点赞效果
      目录效果图如下:分析效果思路实现1.对外公开的参数2.声明需要的对象3.手势的处理4.动画小红心的布局5.小红心动效使用效果源码效果图如下: 分析效果 1.整个控件可以点击,控件...
      99+
      2022-11-12
    • 简单实用的Android UI微博动态点赞效果
      说起空间动态、微博的点赞效果,网上也是很泛滥,各种实现与效果一大堆。而详细实现的部分,讲述的也是参差不齐,另一方面估计也有很多大侠也不屑一顾,觉得完全没必要单独开篇来写和讲解吧...
      99+
      2022-06-06
      动态 Android
    • Android项目开发 教你实现Periscope点赞效果
      现在视频应用越来越火,Periscope火起来后,国内也出现了不少跟风者,界面几乎跟Periscope一模一样.Periscope确实不错,点赞的效果也让人眼前一亮,很漂亮,于...
      99+
      2022-06-06
      Android
    • Android列表怎么实现单选点击缩放动画效果
      本篇内容介绍了“Android列表怎么实现单选点击缩放动画效果”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!recycleView单选的时候...
      99+
      2023-06-20
    • CSS如何实现点赞效果心形效果
      小编给大家分享一下CSS如何实现点赞效果心形效果,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧! CSS实现点赞效果心形效果 <!DOCTYPE html> <htm...
      99+
      2022-10-19
    • Android实现动画效果详解
      目前Android平台提供了两类动画一类是Tween动画,第二类就是 Frame动画,具体内容介绍请看下文: 一类是Tween动画,就是对场景里的对象不断的进行图像变化来产生动...
      99+
      2022-06-06
      动画 Android
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作