Animation-list,帧动画+属性动画,做出Flash般的效果
我们会用到PS,即使不会也不要怂,只需要几步傻瓜式操作即可。
属性动画可以看看我另一篇文章:属性动画详解
效果图
相信机智的各位,看完之后一定能发挥创意,做出更酷更炫的效果
图层获取
首先你需要找一张你喜欢的GIF图,然后一张背景图片,以及一些小组件图片(为了这个页面不卡,我就直接发我处理后的图片资源了)。
打开PS,把图片拖拽进去,然后GIF就会拆成各个独立的图层,也可以点击窗口——>动画进行预览。
点击图层旁边的复选框(选中显示一个眼睛的图案),选中表示图层可见,每次选择一个图层,然后保存文件即可,然后一张GIF就被拆分成以下几个图片(我对图层进行了简单处理,如果会PS可以自行扩展):
其它资源(其实是有4张图片,白底可能看不到):
认识Animation-list
根标签为animation-list,文件存放在res/drawable目录下,强调是drawable文件夹,我和小伙伴都有放错文件夹的经历的说。
item标签用于声明图片,没什么好说的
两个关键属性:
oneshot代表着是否只展示一遍,设置为false会不停的循环播放动画
android:duration 表示展示所用的该图片的时间长度
完整的文件如下:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@mipmap/load_anim_a"
android:duration="150" />
<item
android:drawable="@mipmap/load_anim_b"
android:duration="150" />
<item
android:drawable="@mipmap/load_anim_c"
android:duration="150" />
<item
android:drawable="@mipmap/load_anim_d"
android:duration="150" />
<item
android:drawable="@mipmap/load_anim_e"
android:duration="150" />
</animation-list>
源码:
然后就直接上代码了,具体注意事项我就放在代码注释中好了,String资源文件自行添加。
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<!--使用CardView,好看!-->
<android.support.v7.widget.CardView
android:id="@+id/error_top"
android:layout_width="240dp"
android:layout_height="216dp"
app:cardCornerRadius="3dp"
app:cardElevation="5dp">
<!--定义一个布局,放背景飘过的云彩,动态添加也成-->
<RelativeLayout
android:id="@+id/error_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimaryLightest"
android:contentDescription="@string/description_img"
android:scaleType="fitXY" />
<!--动画的背景图片-->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/description_img"
android:scaleType="fitXY"
android:src="@mipmap/load_anim_bg" />
<!--启动动画时候的图片-->
<ImageView
android:id="@+id/error_in"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/description_img"
android:scaleType="fitXY"
android:src="@drawable/internet_connect"
android:visibility="invisible" />
<!--默认状态下的图片-->
<ImageView
android:id="@+id/error_show"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:contentDescription="@string/description_img"
android:scaleType="fitXY"
android:src="@mipmap/load_anim_default" />
<!--按钮,可以点击重新加载-->
<Button
android:id="@+id/error_refresh_btn"
android:layout_width="80dp"
android:layout_height="24dp"
style="@style/Widget.AppCompat.Button.Borderless"
android:background="@color/holo_orange_light"
android:layout_gravity="bottom|center"
android:layout_margin="6dp"
android:gravity="center"
android:textColor="@android:color/white"
android:text="@string/err_try_connect" />
</android.support.v7.widget.CardView>
</RelativeLayout>
Java代码:
/**
* Created by ChenSS on 2016/10/25.
*/
public class ErrorDialog extends Dialog {
private static final int REFRESH_FAILED = 0;
private static final int REFRESH_OK = 1;
private static final int REFRESH_TIMES = 2;
private static final int ANIM_START = 3;
private Context mContext;
private Button error_refresh;
private ImageView error_in;
private ImageView error_show;
private Handler mHandler;
private AnimationDrawable animationDrawable;
private InternetRunnable runnable;
private List<ImageView> mWind;
public ErrorDialog(Context context) {
super(context, R.style.dialog);
this.mContext = context;
setCanceledOnTouchOutside(true);
}
//网络连接成功的标志
private boolean flag;
public boolean isConnected() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.error_activity);
mHandler = new MyHandler(ErrorDialog.this);
error_in = (ImageView) findViewById(R.id.error_in);
error_show = (ImageView) findViewById(R.id.error_show);
error_refresh = (Button) findViewById(R.id.error_refresh_btn);
RelativeLayout error_container = (RelativeLayout) findViewById(R.id.error_container);
//AnimationDrawable对象
animationDrawable = (AnimationDrawable) error_in.getDrawable();
//生成随机飘过的云彩,这样每次打开ErrorDialog动画都是不同的
mWind = new ArrayList<>(5);
for (int i = 0; i < 5; i++) {
ImageView wind = new ImageView(mContext);
LinearLayout.LayoutParams params;
switch ((int) (Math.random() * 3)) {
case 0:
//生成一个小的16×1的白色矩形
params = new LinearLayout.LayoutParams(16, 1);
wind.setLayoutParams(params);
wind.setBackgroundColor(mContext
.getResources()
.getColor(R.color.well_background));
break;
case 1:
//使用白云的图片资源
params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
wind.setLayoutParams(params);
wind.setImageResource(R.mipmap.clouds_a);
break;
case 2:
//使用白云的图片资源
params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
wind.setLayoutParams(params);
wind.setImageResource(R.mipmap.clouds_b);
break;
}
//先隐藏起来,防止出现画面闪烁,或者莫名的白点
wind.setVisibility(View.INVISIBLE);
//将之前的图层放到集合中备用
mWind.add(wind);
error_container.addView(wind);
}
error_refresh.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//当用户选择重新加载
runnable = new InternetRunnable(ErrorDialog.this);
//默认图片隐藏
error_show.setVisibility(View.GONE);
//动画可见
error_in.setVisibility(View.VISIBLE);
//按钮不可点击
error_refresh.setClickable(false);
//按钮文本变化
error_refresh.setText(mContext.getString(R.string.err_title));
if (CheckNetUtils.isNetworkConnected(mContext)) {
//这是我写的判断手机当前是否联网的方法,如果手机断网了,也没必要尝试重新链接。
//测试时,可直接删除代码,实际使用,设计自己的代码逻辑。
}
//启动动画
animationDrawable.start();
//这里我是直接调用项目的线程池,你可以new一个线程。
ThreadPool.getCachedThreadPool().execute(runnable);
//向Handler发送延迟消息(是线程跑完再发送?还是发送延迟消息?自己选择吧)
mHandler.sendEmptyMessage(REFRESH_FAILED);
}
});
}
/**
* 按返回键关掉dialogue
*/
@Override
public void onBackPressed() {
this.dismiss();
if (runnable != null)
runnable.stopThread();
mHandler.removeCallbacksAndMessages(null);
super.onBackPressed();
}
/**
* 这是一个我写的检测网络连接的方法,如果链接成功,返回true。
* 测试时,可以删除方法体,直接返回false,实际使用,编写自己的代码逻辑
*/
private boolean checkConnect() {
RetrofitService retrofitService = RetrofitClient.getClient();
Call<ResponseBody> call = retrofitService.checkConnection(Parameter.URI_CHECK_NET);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
try {
String str = response.body().string();
if (Parameter.SUCCEEDED.equals(str))
setFlag(true);
} catch (IOException e) {
setFlag(false);
}
} else {
setFlag(false);
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
setFlag(false);
}
});
return false;
}
/**
* 写一个随时可以stop的runnable
*/
private static class InternetRunnable implements Runnable {
private boolean stop;
private Thread thread;
private WeakReference<Dialog> reference;
//参数就是当前Dialog对象了
public InternetRunnable(Dialog dialog) {
stop = false;
thread = Thread.currentThread();
reference = new WeakReference<>(dialog);
}
@Override
public void run() {
//activity 其实是ErrorDialog,忘记改了o(∩_∩)o
final ErrorDialog activity = (ErrorDialog) reference.get();
int count = 0;
while (!stop) {
try {
//这个参数,我是尝试加载一次,“连接中...”中的省略号就加一个,然后天上飘过一朵
count++;
Message message = activity.mHandler.obtainMessage();
if (count % 2 == 0) {
message.arg1 = count / 2;
//如果链接成功,就向Handler发送消息,然后关闭线程等等,失败就继续检测
if (activity.isConnected()) {
activity.mHandler.sendEmptyMessage(REFRESH_OK);
} else {
activity.checkConnect();
}
message.what = REFRESH_TIMES;
activity.mHandler.sendMessage(message);
} else {
//天上飘过一朵云
message.arg1 = count / 2;
message.what = ANIM_START;
activity.mHandler.sendMessage(message);
}
//每次线程睡眠0.2秒
Thread.sleep(200);
} catch (InterruptedException e) {
this.thread.interrupt();
}
}
}
//关闭线程
public void stopThread() {
this.stop = !stop;
System.gc();
}
}
private static class MyHandler extends Handler {
private WeakReference<Dialog> reference;
public MyHandler(Dialog dialog) {
reference = new WeakReference<>(dialog);
}
@Override
public void handleMessage(Message msg) {
final ErrorDialog dialog = (ErrorDialog) reference.get();
if (dialog != null) {
switch (msg.what) {
case REFRESH_FAILED:
//失败就显示默认页面
postDelayed(new Runnable() {
@Override
public void run() {
dialog.error_in.setVisibility(View.GONE);
dialog.error_show.setVisibility(View.VISIBLE);
dialog.runnable.stopThread();
dialog.animationDrawable.stop();
dialog.error_refresh.setText(dialog.mContext.getString(R.string.err_try_connect));
dialog.error_refresh.setClickable(true);
}
}, 5000);
break;
case REFRESH_OK:
//成功就关闭动画、关闭dialog
dialog.animationDrawable.stop();
dialog.dismiss();
break;
case REFRESH_TIMES:
//修改“连接中...”的省略号个数
String txt = dialog.mContext.getString(R.string.err_title);
int count = msg.arg1;
for (int i = 0; i < count % 3; i++) {
txt += dialog.mContext.getString(R.string.err_title_dot);
}
dialog.error_refresh.setText(txt);
break;
case ANIM_START:
//天上飘过一朵云
int position = msg.arg1 % 5;
dialog.startWind(dialog.mWind.get(position));
break;
}
}
}
}
/**
* 天上飘过一朵云的动画,参数是View,大家可以直接传入任意一个View测试一下这个方法,
* 这里我就不具体展开介绍属性动画了
*/
public void startWind(final View view) {
final float pointY = Math.round(Math.random() * 240);
if (view.getVisibility() == View.INVISIBLE)
view.setVisibility(View.VISIBLE);
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(1000);
valueAnimator.setObjectValues(new PointF(0, 0));
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator<PointF>() {
@Override
public PointF evaluate(float fraction, PointF startValue,
PointF endValue) {
PointF point = new PointF();
point.x = 250 * fraction * 3;
point.y = pointY;
return point;
}
});
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF point = (PointF) animation.getAnimatedValue();
view.setX(point.x);
view.setY(point.y);
}
});
}
}
注意事项:
由于这是一个自定义Dialog,要对它的样式进行处理,否则背景会是布局中所显示的颜色
<style name="dialog" parent="@android:style/Theme.Dialog">
<!--背景颜色及透明程度-->
<item name="android:windowBackground">@android:color/transparent</item>
<!--是否有标题 -->
<item name="android:windowNoTitle">true</item>
<!--是否浮现在activity之上-->
<item name="android:windowIsFloating">true</item>
</style>
可能漏传部分资源文件,大家可以自行添加,或者留言提醒我:
<string name="err_title">连接中.</string>
<string name="err_title_dot">.</string>
Animation-list,帧动画+属性动画,做出Flash般的效果的更多相关文章
- android 帧动画,补间动画,属性动画的简单总结
帧动画——FrameAnimation 将一系列图片有序播放,形成动画的效果.其本质是一个Drawable,是一系列图片的集合,本身可以当做一个图片一样使用 在Drawable文件夹下,创建ani ...
- Android 动画——属性动画Property Animation
Android在3.0之前只提供了两种动画:View Animation .Drawable Animation .也就是我们在<Android 动画——Frame Animation与Twee ...
- Android笔记(六十五) android中的动画——属性动画(propertyanimation)
补间动画只能定义起始和结束两个帧在“透明度”.“旋转”.“倾斜”.“位移”4个方面的变化,逐帧动画也只能是播放多个图片,无法满足我们日常复杂的动画需求,所以谷歌在3.0开始,推出了属性动画(prope ...
- Android 动画 属性动画 视图动画 补间动画 帧动画 详解 使用
Android动画 Property Animation res/animator/filename.xml In Java: R.animator.filename In XML: @[packag ...
- 【属性动画总结】Property Animation
属性动画概述 3.0以前,android仅支持两种动画模式,tweened animation 和 frame-by-frame animation,在android3.0中又引入了一个新的动画系统: ...
- 第三部分:Android 应用程序接口指南---第四节:动画和图形---第一章 属性动画及动画与图形概述
第1章 属性动画及动画与图形概述 Android提供了一系列强大的API来把动画加到UI元素中,以及绘制自定义的2D和3D图像中去.下面的几节将综述这些可用的API以及系统的功能,同时帮你做出最优的选 ...
- View动画和属性动画
在应用中, 动画效果提升用户体验, 主要分为View动画和属性动画. View动画变换场景图片效果, 效果包括平移(translate), 缩放(scale), 旋转(rotate), 透明(alph ...
- 属性动画详解 Interpolator TypeEvaluator
概述 产生原因 3.0以前,android支持两种动画模式,tween animation,frame animation,在android3.0中又引入了一个新的动画系统:prope ...
- 每日一问:到底为什么属性动画后 View 在新位置还能响应事件
在 Android 开发中,我们难免会使用动画来处理各种各样的动画效果,以满足 UI 的高逼格设计.对于比较复杂的动画效果,我们通常会采用著名的开源库:lottie-android,或许你会对 lot ...
随机推荐
- Centos7安装后出现please make your choice from '1' to e 解决方式
[输入"1",按Enter键 输入"2",按Enter键 输入"q",按Enter键 输入"yes",按 ...
- LESS IS MORE
学习完css部分,相信大家对通过css进行DOM元素的样式操作已经非常熟悉,也可以通过css的语法进行页面显示效果的添加和修改.如果你们对css报以崇高敬意,感觉它拯救了你的整个网页的话,其实你正在犯 ...
- 【Win 10 应用开发】在代码中加载文本资源
记得前一次,老周给大伙,不,小伙伴们介绍了如何填写 .resw 文件,并且在 XAML 中使用 x:Uid 标记来加载.也顺便给大伙儿分析了运行时是如何解析 .resw 文件的. 本来说好了,后续老周 ...
- github 项目绑定自己的域名
上周脑子发热申请了自己的一个域名.本想搞一个自己的网站,后来囊中羞涩,数据库,服务器..买不起了,只买个域名,发现啥也搞不成.后来突然想到了不行找个东西映射到这个域名上吧,就想到了github,之前也 ...
- R学习笔记 第三篇:数据框
数据框(data.frame)用于存储二维表(即关系表)的数据,每一列存储的数据类型必须相同,不同的数据列的数据类型可以相同,也可以不同,但是,每列的长度必须相同.数据框的每列可以有唯一的命名,在已创 ...
- 无所不会的fiddler遇到的尴尬
昨天测试项目时,遇到一个尴尬的事 预期功能:点击页面某个按钮会post2个请求 实际情况:点了按钮,fiddler抓包没有看到任何请求 后来经过他人提醒在PC端浏览器打开此页面,点击按钮后看到页面有j ...
- Python - 单步调试
Python 有一个单步调试器模块,能实现基本的调试效果!详情请看Python标准文档说明:https://docs.python.org/2/library/pdb.html 调试例子: >& ...
- LCIS(区间合并)
LCIS Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submissi ...
- 详细解读-this-关键字在全局、函数、对象、jQuery等中的基础用法!
一.前言 1. Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的设计模式来实现面向对象的编程,其 ...
- 【20171106早】BeEF 工具初探
老黑今天接触BeEF工具,首先要了解这个工具能够做什么? 0x01:功能介绍 专业文档:点击这里 通俗的说就是可以控制别的浏览器,获取浏览器的信息.然后做something 专业的说就是好用的渗透测试 ...