Android 如何实现气泡选择动画,食堂大妈看完都会了

有锯齿的圆

解决方案是 smoothstep。它根据到 texture 与背景的变换起始点的距离平滑的从01变化。因此距离 0 到 0.49 时 texture 的透明度为 1,大于等于 0.5 时为 00.49 和 0.5 之间时平滑变化,如此圆的边就平滑了。

Android 如何实现气泡选择动画,食堂大妈看完都会了

无锯齿圆

OpenGL 中如何使用 texture 显示图像和文本?在动画中圆有两种状态 —— 普通和选中。在普通状态下圆的 texture包含文字和颜色,在选中状态下同时包含图像。因此我需要为每个圆创建两个不同的 texture

我使用 Bitmap 实例来创建 texture,绘制所有元素。

fun bindTextures(textureIds: IntArray, index: Int) {

texture = bindTexture(textureIds, index * 2, false)

imageTexture = bindTexture(textureIds, index * 2 + 1, true)

}

private fun bindTexture(textureIds: IntArray, index: Int, withImage: Boolean): Int {

glGenTextures(1, textureIds, index)

createBitmap(withImage).toTexture(textureIds[index])

return textureIds[index]

}

private fun createBitmap(withImage: Boolean): Bitmap {

var bitmap = Bitmap.createBitmap(bitmapSize.toInt(), bitmapSize.toInt(), Bitmap.Config.ARGB_4444)

val bitmapConfig: Bitmap.Config = bitmap.config ?: Bitmap.Config.ARGB_8888

bitmap = bitmap.copy(bitmapConfig, true)

val canvas = Canvas(bitmap)

if (withImage) drawImage(canvas)

drawBackground(canvas, withImage)

drawText(canvas)

return bitmap

}

private fun drawBackground(canvas: Canvas, withImage: Boolean) {

}

private fun drawText(canvas: Canvas) {

}

private fun drawImage(canvas: Canvas) {

}

之后我将 texture 单元赋值给 u_Text 变量。我使用 texture2() 方法获取片段的真实颜色,texture2() 接收 texture 单元和片段顶点的位置两个参数。

使用 JBox2D 让气泡动起来


关于动画的物理特性十分的简单。主要的对象是 World 实例,所有的实体创建都需要它。

class CircleBody(world: World, var position: Vec2, var radius: Float, var increasedRadius: Float) {

val decreasedRadius: Float = radius

val increasedDensity = 0.035f

val decreasedDensity = 0.045f

var isIncreasing = false

var isDecreasing = false

var physicalBody: Body

var increased = false

private val shape: CircleShape

get() = CircleShape().apply {

m_radius = radius + 0.01f

m_p.set(Vec2(0f, 0f))

}

private val fixture: FixtureDef

get() = FixtureDef().apply {

this.shape = this@CircleBody.shape

density = if (radius > decreasedRadius) decreasedDensity else increasedDensity

}

private val bodyDef: BodyDef

get() = BodyDef().apply {

type = BodyType.DYNAMIC

this.position = this@CircleBody.position

}

init {

physicalBody = world.createBody(bodyDef)

physicalBody.createFixture(fixture)

}

}

如你所见创建实体很简单:需要指定实体的类型(例如:动态、静态、运动学)、位置、半径、形状、密度以及运动。

每次画面绘制,都需要调用 World 的 step() 方法移动所有的实体。之后你可以在图形的新位置进行绘制。

我遇到的问题是 World 的重力只能是一个方向,而不能是一个点。JBox2D 不支持轨道重力。因此将圆移动到屏幕中心是无法实现的,所以我只能自己来实现引力。

private val currentGravity: Float

get() = if (touch) increasedGravity else gravity

private fun move(body: CircleBody) {

body.physicalBody.apply {

val direction = gravityCenter.sub(position)

val distance = direction.length()

val gravity = if (body.increased) 1.3f * currentGravity else currentGravity

if (distance > step * 200) {

applyForce(direction.mul(gravity / distance.sqr()), position)

}

}

}

Android 如何实现气泡选择动画,食堂大妈看完都会了

引力挑战

每次发生移动时,我计算出力的大小并作用于每个实体,看上去就像圆受引力作用在移动。

GlSurfaceView 中检测用户触摸事件


GLSurfaceView 和其它的 Android view 一样可以响应用户的点击事件。

override fun onTouchEvent(event: MotionEvent): Boolean {

when (event.action) {

MotionEvent.ACTION_DOWN -> {

startX = event.x

startY = event.y

previousX = event.x

previousY = event.y

}

MotionEvent.ACTION_UP -> {

if (isClick(event)) renderer.resize(event.x, event.y)

renderer.release()

}

MotionEvent.ACTION_MOVE -> {

if (isSwipe(event)) {

renderer.swipe(event.x, event.y)

previousX = event.x

previousY = event.y

} else {

release()

}

}

else -> release()

}

return true

}

private fun release() = postDelayed({ renderer.release() }, 1000)

private fun isClick(event: MotionEvent) = Math.abs(event.x - startX) < 20 && Math.abs(event.y - startY) < 20

private fun isSwipe(event: MotionEvent) = Math.abs(event.x - previousX) > 20 && Math.abs(event.y - previousY) > 20

最后

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

同时我经过多年的收藏目前也算收集到了一套完整的学习资料以及高清详细的Android架构进阶学习导图及笔记免费分享给大家,希望对想成为架构师的朋友有一定的参考和帮助。

下面是部分资料截图,诚意满满:特别适合有开发经验的Android程序员们学习。

Android 如何实现气泡选择动画,食堂大妈看完都会了

资料免费领取方式:点击我的GitHub~

不论遇到什么困难,都不应该成为我们放弃的理由!

和帮助。

下面是部分资料截图,诚意满满:特别适合有开发经验的Android程序员们学习。

[外链图片转存中…(img-FjtAZiWQ-1643776884601)]

资料免费领取方式:点击我的GitHub~

不论遇到什么困难,都不应该成为我们放弃的理由!

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

上一篇:迷宫DFS经典解法


下一篇:ES6入门(5)-- class