fix
lmw
2025-03-04 449bdb5d2b5bf7b272ca5cda4c066f9a65040064
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package com.lzf.easyfloat.anim
 
import android.animation.Animator
import android.animation.ValueAnimator
import android.graphics.Rect
import android.view.View
import android.view.WindowManager
import com.lzf.easyfloat.enums.SidePattern
import com.lzf.easyfloat.interfaces.OnFloatAnimator
import com.lzf.easyfloat.utils.DisplayUtils
import kotlin.math.min
 
/**
 * @author: liuzhenfeng
 * @function: 系统浮窗的默认效果,选择靠近左右侧的一边进行出入
 * @date: 2019-07-22  17:22
 */
open class DefaultAnimator : OnFloatAnimator {
 
    override fun enterAnim(
        view: View,
        params: WindowManager.LayoutParams,
        windowManager: WindowManager,
        sidePattern: SidePattern
    ): Animator? = getAnimator(view, params, windowManager, sidePattern, false)
 
    override fun exitAnim(
        view: View,
        params: WindowManager.LayoutParams,
        windowManager: WindowManager,
        sidePattern: SidePattern
    ): Animator? = getAnimator(view, params, windowManager, sidePattern, true)
 
    private fun getAnimator(
        view: View,
        params: WindowManager.LayoutParams,
        windowManager: WindowManager,
        sidePattern: SidePattern,
        isExit: Boolean
    ): Animator {
        val triple = initValue(view, params, windowManager, sidePattern)
        // 退出动画的起始值、终点值,与入场动画相反
        val start = if (isExit) triple.second else triple.first
        val end = if (isExit) triple.first else triple.second
        return ValueAnimator.ofInt(start, end).apply {
            addUpdateListener {
                try {
                    val value = it.animatedValue as Int
                    if (triple.third) params.x = value else params.y = value
                    // 动画执行过程中页面关闭,出现异常
                    windowManager.updateViewLayout(view, params)
                } catch (e: Exception) {
                    cancel()
                }
            }
        }
    }
 
    /**
     * 计算边距,起始坐标等
     */
    private fun initValue(
        view: View,
        params: WindowManager.LayoutParams,
        windowManager: WindowManager,
        sidePattern: SidePattern
    ): Triple<Int, Int, Boolean> {
        val parentRect = Rect()
        windowManager.defaultDisplay.getRectSize(parentRect)
        // 浮窗各边到窗口边框的距离
        val leftDistance = params.x
        val rightDistance = parentRect.right - (leftDistance + view.right)
        val topDistance = params.y
        val bottomDistance = parentRect.bottom - (topDistance + view.bottom)
        // 水平、垂直方向的距离最小值
        val minX = min(leftDistance, rightDistance)
        val minY = min(topDistance, bottomDistance)
 
        val isHorizontal: Boolean
        val endValue: Int
        val startValue: Int = when (sidePattern) {
            SidePattern.LEFT, SidePattern.RESULT_LEFT -> {
                // 从左侧到目标位置,右移
                isHorizontal = true
                endValue = params.x
                -view.right
            }
            SidePattern.RIGHT, SidePattern.RESULT_RIGHT -> {
                // 从右侧到目标位置,左移
                isHorizontal = true
                endValue = params.x
                parentRect.right
            }
            SidePattern.TOP, SidePattern.RESULT_TOP -> {
                // 从顶部到目标位置,下移
                isHorizontal = false
                endValue = params.y
                -view.bottom
            }
            SidePattern.BOTTOM, SidePattern.RESULT_BOTTOM -> {
                // 从底部到目标位置,上移
                isHorizontal = false
                endValue = params.y
                parentRect.bottom + getCompensationHeight(view, params)
            }
 
            SidePattern.DEFAULT, SidePattern.AUTO_HORIZONTAL, SidePattern.RESULT_HORIZONTAL -> {
                // 水平位移,哪边距离屏幕近,从哪侧移动
                isHorizontal = true
                endValue = params.x
                if (leftDistance < rightDistance) -view.right else parentRect.right
            }
            SidePattern.AUTO_VERTICAL, SidePattern.RESULT_VERTICAL -> {
                // 垂直位移,哪边距离屏幕近,从哪侧移动
                isHorizontal = false
                endValue = params.y
                if (topDistance < bottomDistance) -view.bottom
                else parentRect.bottom + getCompensationHeight(view, params)
            }
 
            else -> if (minX <= minY) {
                isHorizontal = true
                endValue = params.x
                if (leftDistance < rightDistance) -view.right else parentRect.right
            } else {
                isHorizontal = false
                endValue = params.y
                if (topDistance < bottomDistance) -view.bottom
                else parentRect.bottom + getCompensationHeight(view, params)
            }
        }
        return Triple(startValue, endValue, isHorizontal)
    }
 
    /**
     * 单页面浮窗(popupWindow),坐标从顶部计算,需要加上状态栏的高度
     */
    private fun getCompensationHeight(view: View, params: WindowManager.LayoutParams): Int {
        val location = IntArray(2)
        // 获取在整个屏幕内的绝对坐标
        view.getLocationOnScreen(location)
        // 绝对高度和相对高度相等,说明是单页面浮窗(popupWindow),计算底部动画时需要加上状态栏高度
        return if (location[1] == params.y) DisplayUtils.statusBarHeight(view) else 0
    }
 
}