Animation-list,帧动画+属性动画,做出Flash般的效果

blackelephant 发布于1年前 阅读12117次
0 条评论

 

我们会用到PS,即使不会也不要怂,只需要几步傻瓜式操作即可。
属性动画可以看看我另一篇文章:属性动画详解

效果图

相信机智的各位,看完之后一定能发挥创意,做出更酷更炫的效果

图片加载

图层获取

首先你需要找一张你喜欢的GIF图,然后一张背景图片,以及一些小组件图片(为了这个页面不卡,我就直接发我处理后的图片资源了)。

ps处理

打开PS,把图片拖拽进去,然后GIF就会拆成各个独立的图层,也可以点击窗口——>动画进行预览。

PS图层保存

点击图层旁边的复选框(选中显示一个眼睛的图案),选中表示图层可见,每次选择一个图层,然后保存文件即可,然后一张GIF就被拆分成以下几个图片(我对图层进行了简单处理,如果会PS可以自行扩展):

abcde

其它资源(其实是有4张图片,白底可能看不到):

默认图背景图云1云2

认识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;
    }@Overridepublic 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() {@Overridepublic 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 */@Overridepublic 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>() {@Overridepublic 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);
                }
            }@Overridepublic 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);
        }@Overridepublic 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);
        }@Overridepublic void handleMessage(Message msg) {final ErrorDialog dialog = (ErrorDialog) reference.get();if (dialog != null) {switch (msg.what) {case REFRESH_FAILED://失败就显示默认页面postDelayed(new Runnable() {@Overridepublic 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://成功就关闭动画、关闭dialogdialog.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>() {@Overridepublic 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() {@Overridepublic 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>

 
需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。