Android 如何实现气泡选择动画,Android实战项目视频

gl_FragColor = distance < 0.5 ? texture2D(u_Text, v_UV) : u_BgColor;

我根据点到中心的距离调整片段的颜色,没有采取抗锯齿手段。当然结果差强人意 —— 圆的边是凹凸不平的。

有锯齿的圆

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

image

无锯齿圆

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)

}

}

}

引力挑战

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

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

GLSurfaceView 拦截所有的点击,并用渲染器进行处理。

渲染器:

fun swipe(x: Float, y: Float) = Engine.swipe(x.convert(glView.width, scaleX),

y.convert(glView.height, scaleY))

fun release() = Engine.release()

fun Float.convert(size: Int, scale: Float) = (2f * (this / size.toFloat()) - 1f) / scale

引擎:

fun swipe(x: Float, y: Float) {

gravityCenter.set(x * 2, -y * 2)

touch = true

}

fun release() {

gravityCenter.setZero()

touch = false

}

用户点击屏幕时,我将重力中心设为用户点击点,这样看起来就像用户在控制气泡的移动。用户停止移动后我会将气泡恢复到初始位置。

根据用户点击坐标查找气泡


当用户点击圆时,我从 onTouchEvent() 方法获取屏幕点击点。但是我也需要找到 OpenGL 坐标系中点击的圆。GLSurfaceView的默认中心位置坐标为[0, 0]x y 取值范围为 -1 到 1。所以我需要考虑屏幕的比例。

private fun getItem(position: Vec2) = position.let {

val x = it.x.convert(glView.width, scaleX)

val y = it.y.convert(glView.height, scaleY)

circles.find { Math.sqrt(((x - it.x).sqr() + (y - it.y).sqr()).toDouble()) <= it.radius }

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

文末

我总结了一些Android核心知识点,以及一些最新的大厂面试题、知识脑图和视频资料解析。

以后的路也希望我们能一起走下去。(谢谢大家一直以来的支持)

部分资料一览:

  • 330页PDF Android学习核心笔记(内含8大板块)

  • Android学习的系统对应视频

  • Android进阶的系统对应学习资料

  • Android BAT大厂面试题(有解析)

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

脑图和视频资料解析。

以后的路也希望我们能一起走下去。(谢谢大家一直以来的支持)

部分资料一览:

  • 330页PDF Android学习核心笔记(内含8大板块)

[外链图片转存中…(img-NtekG4Ig-1712350914546)]

[外链图片转存中…(img-dTVxacbs-1712350914546)]

  • Android学习的系统对应视频

  • Android进阶的系统对应学习资料

[外链图片转存中…(img-IBpfTPi3-1712350914546)]

  • Android BAT大厂面试题(有解析)

[外链图片转存中…(img-R5KzIetO-1712350914547)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 23
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
您可以使用 Android动画框架来实现从小变大气泡动画效果。下面是一个简单的示例代码: 1. 首先,在您的 XML 布局文件中添加一个显示气泡的 View,如下所示: ``` <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/bubble" android:layout_width="50dp" android:layout_height="50dp" android:src="@drawable/bubble" android:layout_centerInParent="true" /> </RelativeLayout> ``` 2. 接下来,使用 ScaleAnimation 类来创建一个缩放动画,使气泡从小变大。以下是示例代码: ``` ImageView bubble = findViewById(R.id.bubble); Animation anim = new ScaleAnimation(0f, 1f, 0f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); anim.setDuration(500); bubble.startAnimation(anim); ``` 在这个示例代码中,我们使用了 ScaleAnimation 类来创建一个从 0 到 1 的缩放动画,同时指定了气泡的中心点为其自身的中心点。动画的持续时间为 500 毫秒。 3. 最后,为了让气泡从小变大,您需要在 Activity 或 Fragment 的 onCreate() 方法中调用上述动画代码。以下是示例代码: ``` public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ImageView bubble = findViewById(R.id.bubble); Animation anim = new ScaleAnimation(0f, 1f, 0f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); anim.setDuration(500); bubble.startAnimation(anim); } } ``` 这样,当您运行应用程序时,您应该会看到一个从小变大的气泡动画效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值