首页 > 其他分享 >Android实现3D页面加载进度条动画

Android实现3D页面加载进度条动画

时间:2022-11-22 11:32:15浏览次数:37  
标签:loading 进度条 iv Animation context Android SOUFUN animation 3D


一.概述

最近在研究公司的代码,发现每次切换页面时做的进度条效果还挺不错的,所以想深入研究一下,今天就带大家来看看到底是如何实现的,首先上效果图

Android实现3D页面加载进度条动画_初始化

二.实现

上面的进度条最大的特点就是有种立体的感觉,中间的文字貌似是在垂直于平面在转动,下面看看具体的实现:
1.首先我们需要四张图片

SOUFUN_LOADING_BAR

Android实现3D页面加载进度条动画_ide_02

SOUFUN_LOADING

Android实现3D页面加载进度条动画_3d_03

SOUFUN_LOADING1

Android实现3D页面加载进度条动画_初始化_04

SOUFUN_LOADING2

Android实现3D页面加载进度条动画_ide_05

然后我们开始写自定义的View,名字叫做PageLoadingView,那么这个类该继承什么呢?在这里我们需要继承FrameLayout,因为我们要把这些图片添加到当前页面中去的,所有我们必须继承一个具体的ViewGroup的实现类,这里我们选择最简单的FrameLayout。

public class PageLoadingView extends FrameLayout{
//背景图
protected static int SOUFUN_LOADING_BAR = R.drawable.page_loading_bar;
//文字"天"的图片
protected static int SOUFUN_LOADING = R.drawable.page_loading;
//文字"下"的图片
protected static int SOUFUN_LOADING1 = R.drawable.page_loading1;
//文字"贷"的图片
protected static int SOUFUN_LOADING2 = R.drawable.page_loading2;

然后我们做初始化动作,并且在构造函数中调用

/**
* 在布局文件中使用对象是会调用此方法
* @param context
* @param attrs
*/
public PageLoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}

/**
* 在代码中创建对象是会调用此方法
* @param context
*/
public PageLoadingView(Context context) {
super(context);
init(context);
}

/**
* 初始化,把图片添加到布局中
* @param context
*/
public void init(Context context) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
//创建一个ImageView对象
iv_loading_bar = new ImageView(context);
//设置ImageView所显示的图片
iv_loading_bar.setImageResource(SOUFUN_LOADING_BAR);
iv_loading_bar.setLayoutParams(params);
iv_loading = new ImageView(context);
iv_loading.setImageResource(SOUFUN_LOADING2);
iv_loading.setLayoutParams(params);
//将背景图片添加到FrameLayout
this.addView(iv_loading_bar);
//把文字图片添加到FrameLayout中,这里可以随意添加一张,因为我们会在动画开始的时候动态替换
this.addView(iv_loading);
}

我们可以看到外面的圆圈很明显是个旋转动画,我们看看怎么实现:

private Animation createRotateAnimation() {
//绕自身中心旋转,从0到360度
Animation animation = new RotateAnimation(0, +360,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
//动画自执行时长
animation.setDuration(900);
//无限旋转
animation.setRepeatCount(Animation.INFINITE);
//设置线性插值器,意思就是让匀速旋转
animation.setInterpolator(new LinearInterpolator());
return animation;
}

接下来该看看重点了,也就是中间文字的旋转动画,我们先上代码,然后解释

private Rotate3d createRotate3dAnimation() {
//获取旋转点所在的X坐标,这里为容器的中心getWidth获得的就是整个容器的宽度
final float centerX = this.getWidth() / 2.0f;
final Rotate3d rotation = new Rotate3d(-90, 90, centerX, 0, 0, true);
rotation.setDuration(500);
rotation.setRepeatCount(Animation.INFINITE);
rotation.setInterpolator(new LinearInterpolator());
rotation.setAnimationListener(mAnimationListener);
return rotation;
}

private Animation.AnimationListener mAnimationListener = new Animation.AnimationListener() {
int time = 1;

/**
* 动画开始时执行此方法
* @param animation
*/
@Override
public void onAnimationStart(Animation animation) {
//将中心的文字设置为"天"
iv_loading.setImageResource(SOUFUN_LOADING);
}

/**
* 动画不断重复时执行此方法,因为我们把动画的模式都设置为了INFINITE,也就是无限循环
* 所以此方法会不断的执行
* @param animation
*/
@Override
public void onAnimationRepeat(Animation animation) {
//清除缓存
iv_loading.destroyDrawingCache();
if (time % 3 == 0) {
iv_loading.setImageResource(SOUFUN_LOADING);
} else if (time % 3 == 1) {
iv_loading.setImageResource(SOUFUN_LOADING1);
}else{
iv_loading.setImageResource(SOUFUN_LOADING2);
}
time++;

}

@Override
public void onAnimationEnd(Animation animation) { // 动画结束时执行此方法

}
};

我们先来看比较简单的,也就是图片是如何不断变化的,重点就在onAnimationRepeat方法里面,在这个方法里面我们定义了一个int类型的time,这里我们根据time值的不同,每次就会变化不同的图片,因为onAnimationRepeat方法是不断执行的,time的值是不断增加的,所以每隔固定的时间我们就可以看到进度条中间的文字图片在改变。

然后我们看看比较重要的一行

final Rotate3d rotation = new Rotate3d(-90, 90, centerX, 0, 0, true);

这里有一个类Rotate3d,重点在这里,我们进去看看,先给出完整代码:

public class Rotate3d extends Animation {
private final float mFromDegrees;
private final float mToDegrees;
private final float mCenterX;
private final float mCenterY;
private final float mDepthZ;
private final boolean mReverse;
private Camera mCamera;

public Rotate3d(float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ, boolean reverse) {
mFromDegrees = fromDegrees;
mToDegrees = toDegrees;
mCenterX = centerX;
mCenterY = centerY;
mDepthZ = depthZ;
mReverse = reverse;
}

/**
* 将初始化动画组件及其父容器的宽高;通常亦可进行另外的初始化工作
* @param width
* @param height
* @param parentWidth
* @param parentHeight
*/
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
}

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final float fromDegrees = mFromDegrees;
float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
final float centerX = mCenterX;
final float centerY = mCenterY;
final Camera camera = mCamera;
//获得代表变换的矩阵对象
final Matrix matrix = t.getMatrix();
//保存Camera的状态
camera.save();
if (mReverse) {
//正向旋转,距离Z轴的距离从小到大
camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
} else {
//逆向旋转,距离Z轴的距离从小到大
camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
}
//根据Y轴旋转
camera.rotateY(degrees);
//计算当前变换所对应的矩阵并且将其复制给应用此Matrix的对象
camera.getMatrix(matrix);
//恢复保存的状态
camera.restore();
//根据给定的转换设定matrix
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}

我们看到Rotate3d 这个类继承了Animation,这里就是自定义动画。
比较重要的是两个方法initialize和applyTransformation,我们先来看initialize这个方法,

public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}

根据官方的介绍,这个方法的作用是初始化动画组件及其父容器的宽高;通常亦可进行另外的初始化工作,我们在这里创建了一个Camera对象,供后面的使用。

然后我们来看applyTransformation这个方法

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
}

该方法有两个参数。第一个为动画的进度时间值,范围是[0.0f,1.0f],第二个参数Transformation记录着动画某一帧中变形的原始数据。该方法在动画的每一帧显示过程中都会被调用。
然后我们在这里做了一个线性算法来生成中间角度:

float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);

因为interpolatedTime是不断变化的,所以degrees这个值也是不断变化的。Camera 类是用来实现绕 Y 轴旋转后透视投影的。我们只需要其返回的 Matrix 值 , 这个值会赋给 Transformation 中的矩阵成员,这里涉及到了动画的实现原理,这里就不详细介绍了,大家下来自己研究研究,最后给出PageLoadingView的全部代码:

public class PageLoadingView extends FrameLayout{
//背景图
protected static int SOUFUN_LOADING_BAR = R.drawable.page_loading_bar;
//文字"天"的图片
protected static int SOUFUN_LOADING = R.drawable.page_loading;
//文字"下"的图片
protected static int SOUFUN_LOADING1 = R.drawable.page_loading1;
//文字"贷"的图片
protected static int SOUFUN_LOADING2 = R.drawable.page_loading2;

private static Animation animation;
private static Rotate3d rotate3d;

private ImageView iv_loading_bar;
private ImageView iv_loading;

/**
* 在布局文件中使用对象是会调用此方法
* @param context
* @param attrs
*/
public PageLoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}

/**
* 在代码中创建对象是会调用此方法
* @param context
*/
public PageLoadingView(Context context) {
super(context);
init(context);
}

/**
* 初始化,把图片添加到布局中
* @param context
*/
public void init(Context context) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
//创建一个ImageView对象
iv_loading_bar = new ImageView(context);
//设置ImageView所显示的图片
iv_loading_bar.setImageResource(SOUFUN_LOADING_BAR);
iv_loading_bar.setLayoutParams(params);
iv_loading = new ImageView(context);
iv_loading.setImageResource(SOUFUN_LOADING2);
iv_loading.setLayoutParams(params);
//将背景图片添加到FrameLayout
this.addView(iv_loading_bar);
//把文字图片添加到FrameLayout中,这里可以随意添加一张,因为我们会在动画开始的时候替换为第一张
//也就是"天"这种图片
this.addView(iv_loading);
}

@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
if (visibility == View.VISIBLE) {
animation = createRotateAnimation();
iv_loading_bar.startAnimation(animation);
post(new Runnable() {
@Override
public void run() {
rotate3d = createRotate3dAnimation();
iv_loading.startAnimation(rotate3d);
}
});
}
}

private Animation createRotateAnimation() {
//绕自身中心旋转,从0到360度
Animation animation = new RotateAnimation(0, +360,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
//动画自执行时长
animation.setDuration(900);
//无限旋转
animation.setRepeatCount(Animation.INFINITE);
//设置线性插值器,意思就是让匀速旋转
animation.setInterpolator(new LinearInterpolator());
return animation;
}

private Rotate3d createRotate3dAnimation() {
//获取旋转点所在的X坐标,这里为容器的中心getWidth获得的就是整个容器的宽度
final float centerX = this.getWidth() / 2.0f;
final Rotate3d rotation = new Rotate3d(-90, 90, centerX, 0, 0, true);
rotation.setDuration(500);
rotation.setRepeatCount(Animation.INFINITE);
rotation.setInterpolator(new LinearInterpolator());
rotation.setAnimationListener(mAnimationListener);
return rotation;
}

private Animation.AnimationListener mAnimationListener = new Animation.AnimationListener() {
int time = 1;

/**
* 动画开始时执行此方法
* @param animation
*/
@Override
public void onAnimationStart(Animation animation) {
//将中心的文字设置为"天"
iv_loading.setImageResource(SOUFUN_LOADING);
}

/**
* 动画不断重复时执行此方法,因为我们把动画的模式都设置为了INFINITE,也就是无限循环
* 所以此方法会不断的执行
* @param animation
*/
@Override
public void onAnimationRepeat(Animation animation) {
//清除缓存
iv_loading.destroyDrawingCache();
if (time % 3 == 0) {
iv_loading.setImageResource(SOUFUN_LOADING);
} else if (time % 3 == 1) {
iv_loading.setImageResource(SOUFUN_LOADING1);
}else{
iv_loading.setImageResource(SOUFUN_LOADING2);
}
time++;

}

@Override
public void onAnimationEnd(Animation animation) { // 动画结束时执行此方法

}
};


标签:loading,进度条,iv,Animation,context,Android,SOUFUN,animation,3D
From: https://blog.51cto.com/u_10847930/5877260

相关文章

  • Android使用MAT分析内存泄露
    一.概述首先来普及一下什么是内存泄露:内存泄露是指对象的内存在分配之后无法通过程序的执行逻辑释放对该对象的引用,导致不能回收该对象所占内存。内存泄露会导致以下情......
  • Android网络类型判断
    在Android开发中,我们有时候需要根据当前网络的类型去做一些操作,下面看看如何判断当前网络的状况:publicclassNetWorkUtil{privatestaticConnectivityManagermanage......
  • Unity :Android局域网通信、UDP广播实现控制器开关(继电器)
    要解决的问题:1.UDP广播:因为平板控制的不仅仅是继电器,还有其他电脑2.继电器接收的是16进制指令,所以要把12个按钮1-12转换成16进制,要不然一个个的发送太麻烦,这里是指令的理......
  • [Android开发学iOS系列] TableView展现一个list
    TableView基础本文讲讲TableView的基本使用.顺便介绍一下delegation.TableView用来做什么TableView用来展示一个很长的list.和Android中的RecyclerView不同,iOS中的......
  • 在博客园随笔中插入3D分子模型
    技术背景博主对前端技术不甚了解,只是想在博客中直接展示一些已有的分子结构,而且需要是可以交互的。而我们了解到通过3Dmol这样的前端工具可以实现,通过在博客园随笔中直接......
  • Cesium关于3Dtiles的细节分享
    介绍介绍一下Cesium中有关3dTiles的奇淫技巧,存在一些埋坑的地方,以下内容仅为自己摸索的细节和方法,仅供参考,若有更好的办法欢迎讨论通用快速获取feature中包含的属性信息......
  • 服饰3D柔性渲染调研及实践
    服饰3D柔性渲染调研及实践调研背景 当前全球服装制造的产业链中,我国的中小企业的难以参与到其中利润最高的环节比如产品的设计和研发,主要原因就是服装设计的难度......
  • MAC环境Android SDK环境变量配置
    打开.bash_profile文件exportANDROID_HOME=/Users/liwen/Library/Android/sdkexportPATH=${PATH}:${ANDROID_HOME}/platform-toolsexportPATH=${PATH}:${ANDROID_HOME}/t......
  • Android 自定义标题栏组件
    1.绘制Layout文件首先新建一个layout文件,命名为title_bar,在里面绘制标题栏,我需要的是一个有返回键和当前页面标题的titleBar布局代码如下<?xmlversion="1.0"......
  • 3d产品vr虚拟仿真展示比看真实的产品更加形象生动-深圳华锐视点
    对一个企业来说,盈利是企业创建的目的;同样对于企业营销工作者的最终目的也是卖出产品,获取利润。产品3D展示利用3d虚拟现实仿真技术把企业产品的性能特征、工作原理的实......