文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android怎么实现点赞动画效果

2023-06-29 01:53

关注

今天小编给大家分享一下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怎么实现点赞动画效果”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯