自定义dialog当然已经被写烂咯,本文的重点是很方便地获取二次元动漫动图。自带的progress dialog看腻了吗?来换个和bilibili一样的动漫二次元加载吧!
一、动画来源获取
1.1 来源简介
先来预览下效果咯:
很萌很萌吧!!!loading动画当然还是帧动画咯,由于是二次元,pixiv(俗称p站)可谓是动漫图片最多的站点了,上面有数以亿计的动漫图片和动图。
pixiv :新兴的日本同人画、插画作品分享站点。
采用了web2.0的方式,每个参与者都有自己的主页并可以对作品评价打分。
但是由于版权的保护性政策,动图是无法直接下载到gif的,所以我们必须通过一些非常规手段获取,巧合的是,获取到的是动画帧的图片压缩包,所以可以直接拿来当做安卓开发的帧动画使用!
1.2 动画帧获取
p站如今支持中文,所以阅读上没有了障碍,大家可以搜索自己喜欢主题的动图,或者直接去每日排行榜获取高人气动图,我们以此链接 为例。
-
使用chrome内核的浏览器,右键选择检查:
- 进入开发者工具界面后,按下
Ctrl+F
(Command+F
)搜索关键词zip
,其实已经可以看到我们要的下载链接了,但是不能直接复制,必须选中整个段落后,右键copy到文本编辑器中。
-
在文本编辑器中,删除所有的转义字符
\
后,复制名字里带有600x600的那个zip链接,然后粘贴到浏览器或者迅雷中下载。
-
解压后即可获得动画帧图片,顺序为名称。
警告:pixiv站点所有图片拥有版权©️,商用请联系原作者,下载仅仅是个人学习参考之用。
二、帧动画xml文件的建立
怕是没有人不会吧,直接贴代码了,具体的duration根据实际情况自己调节:
三、自定义dialog的建立
3.1 Dialog概念
dialog的官方定义:
A dialog is a small window that prompts the user to make a decision or enter additional information. A dialog does not fill the screen and is normally used for modal events that require users to take an action before they can proceed.
先来了解下什么是Window:
Window表示窗口的概念,它实际上是View的直接管理者,包括View的视图创建,事件分发机制都必须先经过Window。
自定义Dialog,要先明确Dialog的地位。
-
View
是android中视图的呈现方式,但是View不能单独存在,必须依附在Window
窗口这个抽象概念上,而Android中提供视图的地方有Activity,Dialog,Toast。 - 所以某种程度上来说,Dialog是和活动平起平坐的,Dialog的
Window
创建过程与Activity类似(几乎没区别),所以Dialog也有setContentView
方法。具体的创建过程可以参考《Android开发艺术探索》这本书。
所以我们在后面想要管理Dialog的对话框大小就必须使用WindowManager类,而不是去设置父布局的params。
3.2 建立dialog布局文件
直接上代码了,注意,我直接在布局最外层设定了固定的大小,且使用了一个圆角半透明矩形shape作为背景。
效果图:
3.3 自定义dialog的建立
我们新建一个类LoadingDialog
继承自Dialog
,初始化布局参数:
private void initView() {
setContentView(R.layout.dialog_loading_layout);
imageView = (ImageView) findViewById(R.id.loading_view);
//启动我们的二次元帧动画
AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();
animationDrawable.start();
//获取WindowManager.LayoutParams来管理dialog最外部window的大小,理由在3.1 节中已经说明。其实这里不用设置,因为我们在布局最外层指定了居中,且设为固定大小 后对话框最外层布局会自适应(但是android5.0以上默认最外布局match_parent)。
WindowManager.LayoutParams params = getWindow().getAttributes();
params.gravity = Gravity.CENTER;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
getWindow().setAttributes(params);
}
但是坑来了,尽管我们设定了最外层布局为WRAP_CONTENT,但是它是默认白色的背景,所以我们的圆角矩形效果就失效了,借@青蛙要fly的一张图,如果设定background为黑色则效果更加直观:
解决的办法很简单,直接覆盖重写dialog style里的透明属性即可,另外,使用兼容包的dialog样式默认没有Title了,但是这里还是覆写一下:
在构造函数中传入我们的新style(dialog提供了这个构造方法):
public LoadingDialog(Context context) {
super(context,R.style.LoadingDialog);
mContext=context;
}
最后我们的自定义dialog就已经完成了,贴上完整代码:
public class LoadingDialog extends Dialog {
private Context mContext;
ImageView imageView;
public LoadingDialog(Context context) {
super(context,R.style.LoadingDialog);
mContext=context;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
}
private void initView() {
setContentView(R.layout.dialog_loading_layout);
imageView = (ImageView) findViewById(R.id.loading_view);
AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();
animationDrawable.start();
WindowManager.LayoutParams params = getWindow().getAttributes();
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
getWindow().setAttributes(params);
}
@Override
public void dismiss() {
super.dismiss();
}
}
四、封装构建Dialog管理类
为了效率和复用性,我们使用单例模式封装一个线程安全的DialogManger
类:
public class DialogManager {
private static DialogManager mInstnce = null;
private ProgressDialog mDialog;
public static DialogManager getInstnce() {
if (mInstnce == null) {
//线程安全模式
synchronized (DialogManager.class) {
if (mInstnce == null) {
mInstnce = new DialogManager();
}
}
}
return mInstnce;
}
public void showProgressDialog(Context context) {
if (mDialog == null) {
mDialog = new ProgressDialog(context);
//设置点击dialog外部,不会自动退出dialog
mDialog.setCanceledOnTouchOutside(false);
}
mDialog.show();
}
public void dismissProgressDialog() {
if (mDialog != null) {
mDialog.dismiss();
}
mDialog = null;
}
}
这样,我们就可以一句话调出和取消读取界面了:
//显示
DialogManager.getInstnce().showProgressDialog(this);
//取消显示
DialogManager.getInstnce().dismissProgressDialog();
五、总结
其实整个过程非常简单,就是理解window类,然后自定义一个dialog,然后在dialog中启动帧动画,有些老生常谈的坑需要注意罢了。再来看一眼我们萌萌的loading动画吧: