android 自定义漂浮,Android漂浮背景效果的制作方法

本文介绍了一种通过自定义ViewGroup和多个自定义View实现的悬浮动效技术,每个“漂浮物”沿随机赛贝尔曲线运动,赋予了动画自然的随机性。通过重写onDraw方法和控制运动状态,实现了平滑的动画效果。该技术已应用于注册界面,提供了一种创建动态背景的新方式。
摘要由CSDN通过智能技术生成

GIF动图效果不是很好,实际效果非常平滑very smooth,而且添加不同的图形可以组成各种效果,目前已经用在我们项目的注册界面~

12001a0d071068e7d956fdad68405a4c.png

原理:

实现原理很简单,每一个悬浮的“小物体”就是一个自定义View,这些小的自定义View都盛放在一个自定义的ViewGroup中。然后所有的视图都放在这个ViewGroup之上,这样就相当于做一个可动的背景。

下面结合代码详细介绍下:

详解:

FloatObject

悬浮的物体,继承自View,需要重写onDraw方法,主要作用就是来画出自己,并进行随机曲线运动。

任何需要画出的对象都需要继承FloatObject,并重写提供的drawFloatObject方法,在此方法中可以通过设置画笔和画布画出任意图形。比如下面是画出一行文字:

public class FloatText extends FloatObject {

String text;

public FloatText(float posX, float posY, String text) {

super(posX, posY);

this.text = text;

setAlpha(88);

setColor(Color.WHITE);

}

@Override

public void drawFloatObject(Canvas canvas, float x, float y, Paint paint) {

paint.setTextSize(65);

canvas.drawText(text, x, y, paint);

}

}

随机曲线:

其实最复杂的部分就是让漂浮的物体做随机无规则的曲线运动,并且每个漂浮物的速度不同,这样整个漂浮动画才更加自然。

我之前想过使用布朗运动,但是在网上找了好久也没找到一个好用的算法。

最后只能还是使用3点赛贝尔曲线,使漂浮物沿着一条赛贝尔曲线运动,达到终点时,再随机产生一条新的曲线,这样就可以实现随机曲线运动了。

控制运动的代码如下:

public void drawFloatItem(Canvas canvas) {

switch (status) {

case START:

// fade in

if (isFade() && alpha <= ALPHA_LIMIT) {

paint.setAlpha(alpha);

alpha += ALPHA_PER_FRAME;

} else {

setStatus(MOVE);

}

break;

case MOVE:

// 更新赛贝尔曲线点

if (mCurDistance == 0) {

start = new PointF(x, y);

end = getRandomPoint((int)start.x, (int)start.y, (int) distance);// 取值范围distance

c1 = getRandomPoint((int)start.x, (int)start.y, random.nextInt(width / 2)); // 取值范围width/2

c2 = getRandomPoint(end.x, end.y, random.nextInt(width / 2));// 取值范围width/2

}

// 计算塞贝儿曲线的当前点

PointF bezierPoint = CalculateBezierPoint(mCurDistance / distance, start, c1, c2, end);

x = bezierPoint.x;

y = bezierPoint.y;

// 更新当前路径

mCurDistance += MOVE_PER_FRAME;

// 一段画完后重置

if (mCurDistance >= distance) {

mCurDistance = 0;

}

break;

case END:

// fade out

if (isFade() && alpha > 0) {

paint.setAlpha(alpha);

alpha -= ALPHA_PER_FRAME;

} else {

setStatus(FINISH);

}

break;

}

if (status != FINISH) {

Log.e("drawFloatObject", x+", "+y);

drawFloatObject(canvas, x ,y, paint);

}

}

关于赛贝尔曲线运动的算法都是复用之前写的一篇文章ANDROID模拟火花粒子的滑动喷射效果,如果大家有兴趣可以看看。

FloatBackground

FloatBackground继承自FrameLayout,里面有一个用于存放FloatObject的集合。

FloatBackground的主要作用就是绘制所有的“漂浮物”,以及维护其生命周期:

初始化:

private void initFloatObject(int width, int height) {

for (FloatObject floatObject : floats) {

int x = (int) (floatObject.posX * width);

int y = (int) (floatObject.posY * height);

floatObject.init(x, y, width, height);

}

}

绘制:

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

for (FloatObject floatObject : floats) {

floatObject.drawFloatItem(canvas);

}

// 隔一段时间重绘一次, 动画效果

getHandler().postDelayed(runnable, DELAY);

}

// 重绘线程

private Runnable runnable = new Runnable() {

@Override

public void run() {

invalidate();

// 控制帧数

}

};

开始和结束:

public void startFloat() {

for (FloatObject floatObject : floats) {

floatObject.setStatus(FloatObject.START);

}

}

public void endFloat() {

for (FloatObject floatObject : floats) {

floatObject.setStatus(FloatObject.END);

}

}

使用

使用时非常简单,在layout文件中将FloatBackground设置为最底层的视图(其实就是当作一个背景):

android:id="@+id/float_view"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:layout_gravity="center"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="vertical">

android:id="@+id/start"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:text="Start" />

android:id="@+id/end"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:text="End" />

在代码中进行如下调用:

final FloatBackground floatBackground = (FloatBackground) this.findViewById(R.id.float_view);

Button start = (Button) this.findViewById(R.id.start);

start.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

floatBackground.startFloat();

}

});

Button end = (Button) this.findViewById(R.id.end);

end.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

floatBackground.endFloat();

}

});

floatBackground.addFloatView(new FloatRect(0.2f, 0.3f, 30, 40));

floatBackground.addFloatView(new FloatBitmap( this, 0.2f, 0.3f, R.drawable.gr_ptn_03));

floatBackground.addFloatView(new FloatCircle( 0.8f, 0.8f));

floatBackground.addFloatView(new FloatText( 0.3f, 0.6f, "E"));

floatBackground.addFloatView(new FloatRing( 0.6f, 0.2f, 15 ,20));

浮物”时:floatBackground.addFloatView(new FloatText( 0.3f, 0.6f, “E”))

接收的三个参数分别为出生位置在屏幕宽的百分比,长的百分比,和显示的文字。

Github

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值